Vendor Integrations
Vendor Integrations connect Olyron CRM to the carriers, TPAs, and PEOs your agency works with — so member files, enrollments, and commission data flow into one console instead of living in separate carrier portals. This guide covers registering a vendor, applying a carrier template, ingesting data over SFTP or file upload, running the enrollment engine, and tracking commissions.
#What vendor integrations are
A vendor in Olyron CRM is any external data partner — an insurance carrier, third-party administrator (TPA), or PEO — that sends you member or enrollment data. Each vendor is stored per tenant in the vendors table and drives four connected capabilities: a reusable carrier template library, file/SFTP ingestion, the enrollment engine, and commission tracking.
- Vendors and carriers — register a vendor, choose how its data arrives (manual, SFTP, or API), and manage it from the dashboard.
- Vendor templates — pre-built column and mapping definitions for known carrier file formats, applied to a vendor in one step.
- Enrollments — the Olyron enrollment engine, which walks a member through a compliant intake-to-confirmation wizard.
- Commissions — schedules, records, and approvals for agent payouts tied to enrollments, deals, or policies.
Most endpoints below are tenant-scoped through requireTenantUser, so a request only ever sees data for the caller's organization (the shared carrier-template library and the human-only payment/completion steps authenticate the signed-in user directly instead). Write actions (creating SFTP configs, applying templates, creating or approving commissions) are restricted to the org_owner and agency_admin roles.
/dashboard/vendors (with a per-vendor view at /dashboard/vendors/[vendorId]). Enrollments are at /dashboard/enrollments, and commission settings at /dashboard/settings/commissions.#Adding a vendor and applying a carrier template
Start by registering the vendor, then apply a template from the shared carrier library so you do not have to hand-map every column. The template library is queried from the vendor_template_library table and returns entries typed as carrier, tpa, peo, or custom.
Vendor fields
namestring (required)- Display name of the carrier or partner.
codestring (required)- Short unique code used to reference the vendor in files and joins.
ingestion_mode'manual' | 'sftp' | 'api'- How data arrives from this vendor.
data_source_type'file' | 'api' | 'hybrid'- The shape of the source data feed.
supports_files / supports_apiboolean- Capability flags describing what the vendor can send.
contact_name / contact_email / contact_phonestring- Carrier relationship contact details.
is_activeboolean- Inactive vendors are hidden from the default list.
- 1Create the vendorFrom
/dashboard/vendors, add the vendor with a name and code. The record is written to thevendorstable with yourtenant_idandcreated_by. - 2Browse templatesCall
GET /api/vendor-templates(optionally with?type=carrieror?search=<name>) to list matching carrier formats from the library. - 3Apply a templateCall
POST /api/vendor-templates/[templateId]/applywith the targetvendorId. This auto-generates a vendor file definition and mapping from the template's column and mapping definitions. - 4Adjust mappings if neededPass
customizations.columnMappingsorcustomizations.additionalMappingsto override how specific source columns map onto member, enrollment, or employer fields.
curl -X POST /api/vendor-templates/<TEMPLATE_ID>/apply \
-H "Content-Type: application/json" \
-d '{
"vendorId": "b1d3...-uuid",
"customizations": {
"columnMappings": { "Member SSN": "member_ssn" },
"additionalMappings": {
"enrollment": { "plan_code": { "column": "Plan" } }
}
}
}'POST /api/vendor-templates/suggest with { "headers": [...] }. It returns the best-matching template plus a matchScore, and only suggests when at least 50% of the template's columns are present.#Bringing vendor data in: SFTP and file upload
Once a vendor has an active mapping, you can push rows directly or have Olyron pull files from the carrier's SFTP server on a schedule. Both paths run each row through the vendor normalizer, which resolves members and policies and records an import job.
Direct file / row import
POST /api/vendors/[vendorId]/files accepts a rows array plus a vendorMemberKeyField (and optional vendorEnrollmentKeyField) that identify which column keys each record. It creates an import job, processes every row against the vendor's active mapping, and returns counts.
{
"success": true,
"processed": 142,
"failed": 3,
"errors": [{ "index": 17, "error": "Missing vendor member key" }],
"job_id": "job_9f2c..."
}Poll GET /api/vendors/[vendorId]/files/[jobId]/status to track a job after submission.
SFTP configuration
Save connection details with POST /api/vendors/[vendorId]/sftp. Credentials are stored encrypted — the GET response masks passwordEnc and privateKeyEnc as "***" and never returns the raw secret.
| Field | Notes |
|---|---|
| host | SFTP server hostname (required) |
| port | Defaults to 22 |
| username | SFTP login (required) |
| password / privateKey | Provide one; stored encrypted |
| remotePath | Directory to read files from (required) |
| filePattern | Optional glob to match files, e.g. *.csv |
| schedule | Optional cron expression for automated pulls |
| archivePath | Optional path to move processed files |
- Test before saving:
POST /api/vendors/[vendorId]/sftp/testvalidates the connection. - Trigger a one-off pull:
POST /api/vendors/[vendorId]/sftp/sync(admin only). - Remove a config:
DELETE /api/vendors/[vendorId]/sftp.
org_owner or agency_admin role. Other members receive a 403 "Insufficient permissions" response.When a vendor sends member or policy changes, they land as change events. Review them with GET /api/vendors/changes, filtering by vendorId, changeType, severity, or since. Each event joins back to the related vendor, member, and policy.
#Enrollments
The Olyron enrollment engine runs a compliant, wizard-style enrollment for a chosen product and plan. Start one with POST /api/enrollments and list or filter them with GET /api/enrollments.
curl -X POST /api/enrollments \
-H "Content-Type: application/json" \
-d '{
"productId": "prod_123",
"planId": "plan_456",
"advisorId": "advisor_789",
"userContext": {}
}'An enrollment moves through seven steps — intake, eligibility, plan_selection, disclosures, details, payment, confirmation — and carries one of these statuses:
| Status | Meaning |
|---|---|
| started | Enrollment initiated, intake in progress |
| eligible | Passed eligibility checks |
| ineligible | Failed eligibility checks (terminal) |
| pending_payment | Awaiting payment confirmation |
| completed | Successfully enrolled |
| cancelled | User or system cancelled |
GET /api/enrollments supports status (comma-separated), productId, planId, assignedAdvisor, createdAfter, createdBefore, plus page, pageSize (max 100), sortBy, and sortOrder.
POST /api/enrollments/[id]/confirm-payment) can never be automated. It requires humanInitiatedAcknowledgment: true along with amount and customerEmail, and it logs the acting user, IP, and user agent for audit. Call the endpoint's GET first to verify prerequisites and surface any blockers before showing the confirmation UI.Finalizing an enrollment (POST /api/enrollments/[id]/confirm-completion) similarly requires a paymentIntentId plus both finalReviewAcknowledgment and complianceAcknowledgment flags set to true.
#Commission tracking
Commissions tie agent payouts to a source event — an enrollment, deal, policy, or a manual entry — and run through a create-then-approve workflow. Records live per tenant, and non-admin agents can only ever see their own.
Commission schedules
Define how payouts are calculated with POST /api/commissions/schedules. A schedule has a scheduleType of flat, tiered, percentage, or hybrid, and tiered schedules carry a tiers array (each with a rate type of percentage or flat_amount, and an appliesTo of premium, deal_value, or count). List existing schedules with GET /api/commissions/schedules?activeOnly=true.
Creating a commission record
agentIduuid (required)- The agent earning the commission.
sourceType'enrollment' | 'deal' | 'policy' | 'manual'- What the commission is earned on.
sourceId / sourceReferenceuuid / string- Link back to the originating record.
periodStart / periodEnddate (required)- The earning period.
baseValuenumber > 0 (required)- Premium or deal value the rate applies to.
rateAppliednumber 0–1 (required)- Commission rate as a decimal fraction.
scheduleIduuid (optional)- Schedule used to derive the rate.
adjustments / notesnumber / string- Manual adjustment amount and free-text notes.
- 1Create the recordAn admin posts to
POST /api/commissions. The body is validated with Zod and returns the new record with a 201 status. - 2Review the pipelineList records with
GET /api/commissions, filtering byagentId,status,periodStart,periodEnd, orlimit. - 3Approve
POST /api/commissions/[commissionId]/approverecords the approving user. Admin-only. - 4Report
GET /api/commissions/summaryreturns an agent-level summary, or a tenant-wide summary when an admin omitsagentId.
GET /api/commissions and GET /api/commissions/summary, only org_owner and agency_admin can query other agents or the tenant-wide view. Everyone else is transparently scoped to their own user.id.#Reference and troubleshooting
| Action | Endpoint | Admin only? |
|---|---|---|
| List carrier templates | GET /api/vendor-templates | No |
| Apply template to vendor | POST /api/vendor-templates/[templateId]/apply | Yes |
| Suggest template from headers | POST /api/vendor-templates/suggest | No |
| Import vendor rows | POST /api/vendors/[vendorId]/files | No |
| Save / delete SFTP config | POST or DELETE /api/vendors/[vendorId]/sftp | Yes |
| Trigger SFTP sync | POST /api/vendors/[vendorId]/sftp/sync | Yes |
| Review vendor changes | GET /api/vendors/changes | No |
| Start enrollment | POST /api/enrollments | No |
| Create commission | POST /api/commissions | Yes |
| Approve commission | POST /api/commissions/[commissionId]/approve | Yes |
- 401 Unauthorized — no authenticated tenant user. All vendor, enrollment, and commission routes require a signed-in session.
- 403 Insufficient permissions — the action is admin-only and you are not an
org_owneroragency_admin. - 400 "No active mapping found for vendor" — apply a template (or create a mapping) before importing rows for that vendor.
- 400 Validation failed — the request body failed Zod validation; check the
detailsarray in the response for the specific field. - 404 Vendor not found — the
vendorIddoes not belong to your tenant.