The basics
A versioned REST surface over HTTPS. All requests are tenant-scoped: the credential you authenticate with determines which organization's data you see, and nothing in a request body, path, or query string can widen that.
| Base URL | https://api.ebixcoi.com |
| Version prefix | /v1 (in every path) |
| Format | JSON request and response bodies; multipart for document upload |
| Errors | RFC 7807 application/problem+json with stable string codes |
| Calling context | Server-to-server only. No browser CORS is offered in this phase. |
Authentication
Two credential types are supported. Both are issued for your organization by Ebix administrators (ask your Ebix account team); they cannot be created from your own ebixcoi login.
1. API keys (simplest)
A long-lived bearer secret with read and/or write scopes. Keys look like ebx_ followed by 44 hex characters and are shown once at creation.
curl https://api.ebixcoi.com/v1/insureds \
-H "Authorization: Bearer ebx_YOUR_KEY"
2. OAuth 2.0 client credentials
For organizations that prefer short-lived credentials. Ebix creates an OAuth client for your organization (a ebxc_… client ID and a one-time ebxs_… client secret). Exchange them for a bearer access token valid for 1 hour:
curl -X POST https://api.ebixcoi.com/v1/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d grant_type=client_credentials \
-d client_id=ebxc_YOUR_CLIENT_ID \
-d client_secret=ebxs_YOUR_CLIENT_SECRET
{"access_token":"ebxo_...","token_type":"Bearer","expires_in":3600,"scope":"read write"}
Then call any endpoint with Authorization: Bearer ebxo_… exactly as you would with an API key. HTTP Basic authentication and a JSON request body are also accepted on the token endpoint. An optional scope parameter (space-delimited) requests a subset of the client's allowed scopes.
read; POST, PATCH, and DELETE require write. A credential without the needed scope receives 403 forbidden.Onboarding workflow
Your tenant is configured by an Ebix onboarding manager before API work starts — company settings and the standard risk profiles already exist. The integration flow follows this order of operations:
Discover risk profiles
GET /risk-profilesCreate business units
POST /business-unitsCreate insured / vendor
POST /insuredsUpload COI
POST /…/coi-documentsRead compliance status
GET /…/complianceSync updates & webhooks
POST /webhooks| Step | Call | Purpose |
|---|---|---|
| 1 | GET /v1/risk-profiles | Discover the pre-configured risk (insurance) profiles and capture the UUID to associate. Risk profiles are read-only via the API. |
| 2 | POST /v1/business-units | Create (or GET to list) the organizational units insureds belong to. |
| 3 | POST /v1/insureds | Create the vendor/insured with insurance_profile_id and business_unit_id set. Bulk: POST /v1/insureds/bulk (up to 500 rows, per-row outcomes). |
| 4 | POST /v1/insureds/{id}/coi-documents | Upload the certificate of insurance (multipart, 15 MB max). Processing is asynchronous: you get 201 immediately and the document moves to review as extraction completes. |
| 5 | GET /v1/insureds/{id}/compliance | Read compliance status, deficiencies, and scoring once evaluation runs. |
Example: create an insured
curl -X POST https://api.ebixcoi.com/v1/insureds \
-H "Authorization: Bearer ebx_YOUR_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 1b9d6bcd-bbfd-4b2d-9b5d-ab8dfbbd4bed" \
-d '{
"name": "Acme Mechanical LLC",
"external_id": "VEND-88421",
"insurance_profile_id": "RISK_PROFILE_UUID",
"business_unit_id": "BUSINESS_UNIT_UUID",
"contact_email": "coi@acmemech.example"
}'
Example: upload a COI
curl -X POST https://api.ebixcoi.com/v1/insureds/INSURED_UUID/coi-documents \
-H "Authorization: Bearer ebx_YOUR_KEY" \
-F "file=@certificate.pdf"
Conventions you should build against
Errors
Every error is an RFC 7807 problem document with a stable code:
{
"type": "https://developers.ebixcoi.com/errors/validation_error",
"title": "Validation Error",
"status": 422,
"code": "validation_error",
"detail": "internal_id not found in tenant",
"request_id": "..."
}
Common codes: unauthorized (401), forbidden (403), not_found (404), conflict / idempotency_conflict (409), validation_error (422), rate_limited (429). The single exception is the OAuth token endpoint, which follows the OAuth 2.0 standard error format ({"error": "invalid_client", …}) for interoperability.
Pagination
List endpoints return {"data": […], "next_cursor": "…"}. Pass ?cursor= to fetch the next page. Default page size 50, maximum 500 via ?limit=. Cursors are opaque; do not parse them.
Rate limits
600 requests/minute and 10,000 requests/hour per organization, with a per-credential hourly ceiling. Every authenticated response carries X-RateLimit-Limit-Hour, X-RateLimit-Remaining-Hour, and X-RateLimit-Reset; a 429 includes Retry-After.
Idempotency
Send an Idempotency-Key header (any UUID) on writes. Replaying the same key with the same body within 24 hours returns the original response; the same key with a different body returns 409 idempotency_conflict. The multipart document upload does not honor idempotency keys; design retries around the returned document id instead.
Deletes are archives
DELETE on business resources (insureds, business units, documents) archives the record; nothing is destroyed and history remains queryable in the ebixcoi app. Integration configuration (external ID mappings) is likewise soft-deleted, and the same external identifier can be re-registered afterwards.
Request tracing
Every response carries an X-Request-Id. Log it; quote it in support requests. Your administrators can see the same id in the Request Log inside the ebixcoi app.
External ID mappings
If your system has its own identifiers for vendors, register them so future syncs can address records by your IDs:
curl -X POST https://api.ebixcoi.com/v1/external-mappings \
-H "Authorization: Bearer ebx_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"system": "yourerp",
"external_kind": "vendor",
"external_id": "VEND-88421",
"internal_kind": "insured",
"internal_id": "INSURED_UUID"
}'
Bulk registration: POST /v1/external-mappings/bulk (up to 500 rows).
Compliance status
Each insured carries two independent statuses — don't conflate them:
lifecycle_status—active/inactive/archived: whether the vendor record is active in EbixCOI.compliance_status— the insurance-compliance verdict, returned byGET /v1/insureds/{id}/compliance.
compliance_status is computed automatically by the compliance engine — it is not a value a broker enters by hand — and it is an insured-level aggregate across all of the vendor's coverages versus their assigned risk profile (not a per-policy status). It updates on its own as evidence changes (a certificate is approved, a policy expires, requirements change), so a read always returns the current value in real time with no calculation delay — safe to poll at vendor registration or check-in. Values:
not_evaluated— the default. No risk profile assigned yet, or not yet evaluated. A brand-new vendor returns this as a200; the endpoint does not404for an existing insured (a404means the ID is unknown or belongs to another tenant).no_coverage— has a risk profile, but no certificate of insurance on file yet.compliant— meets all requirements.compliant_with_minors— meets requirements except minor or waived items.non_compliant— one or more required items are missing or deficient.
Webhooks
Register HTTPS endpoints (POST /v1/webhooks/subscriptions with an API key that has the write scope, or ask your Ebix account team) to be notified when things happen in ebixcoi, instead of polling.
A subscription carries one or more event filters: either a whole category (compliance.*) or a single event (compliance.became_noncompliant). Each subscription receives a one-time signing secret (whsec_…) used to verify that deliveries genuinely came from ebixcoi.
Available events
| Filter | Event | Fires when |
|---|---|---|
insured.*Vendor & insured lifecycle | insured.created | A new insured is added (app, API, bulk import, or integration) |
insured.updated | An insured's profile details or business-unit membership change. The event data carries business_units (an array of {id, name, parent_id}), not a single business_unit_id | |
insured.archived | An insured is archived | |
insured.placed_on_hold | An active hold is put on an insured | |
insured.hold_released | The hold on an insured is lifted | |
coi_document.*Certificate processing pipeline | coi_document.uploaded | A new certificate is received (API, portal, or email intake) |
coi_document.extraction_completed | AI extraction finishes and the document enters the review queue | |
coi_document.extraction_failed | Extraction fails and the document needs attention. A document moved to the exception queue sends no event. | |
coi_document.approved | A reviewer approves the document; its coverages become active evidence | |
coi_document.archived | A document is archived | |
compliance.*Evaluation outcomes | compliance.evaluated | A compliance evaluation completes for an insured |
compliance.became_compliant | An insured transitions to compliant | |
compliance.became_noncompliant | An insured transitions to non-compliant (new deficiencies) | |
compliance.status_changed | An insured's compliance status changes to any other status, including no_coverage and not_evaluated | |
policy.*Coverage lifecycle | policy.activated | An approved coverage version becomes active evidence. Today it is delivered only to tenants that also have a subscription matching coi_document.approved (for example coi_document.*) |
external_mapping.*Identifier registry changes | external_mapping.created | An external ID mapping is registered |
external_mapping.deleted | An external ID mapping is removed |
Wildcard filters (category.*) are recommended: your endpoint automatically receives any new events added to that category later. Subscriptions can be paused, resumed, and revoked at any time via the API (an API key with the write scope) or by your Ebix account team.
Full reference & support
Every endpoint, schema, parameter, and error is documented in the complete API reference (OpenAPI 3.1).
Questions or unexpected responses: contact your Ebix RCS service consultant and include the X-Request-Id of the affected call.