COIflow API
A simple, read-only REST API for pulling your agency's certificates, coverage lines, and insureds into your AMS, BI tools, or internal dashboards.
Base URL
https://coiflow.app/api/public/v1
All responses are JSON. All times are ISO-8601 UTC. All endpoints are read-only (GET).
Authentication
Create a key under Settings → API in the COIflow app. Keys are scoped to your agency and show only once at creation — store them in your AMS or password manager immediately.
Pass your key in the Authorization header on every request:
curl https://coiflow.app/api/public/v1/health \ -H "Authorization: Bearer coif_live_XXXXXXXXXXXXXXXXXXXXXXXX"
The X-API-Key header is also accepted for AMS connectors that don't support bearer auth.
Scopes: read:insureds, read:certificates, read:coverages. All three are granted by default. Rotate or revoke any key at any time; revocation takes effect within seconds.
Errors & status codes
200— success401— missing, malformed, or revoked key403— key is missing the required scope429— rate limit exceeded (see below)500— server error; safe to retry with backoff
{ "error": "Invalid or revoked API key." }Rate limits
Hard limit of 120 requests per minute per agency across all API keys. Requests above the limit return 429 with Retry-After: 60.
Every response includes these headers so your client can self-throttle:
X-RateLimit-Limit— requests allowed per 60s windowX-RateLimit-Remaining— requests left in the current windowX-RateLimit-Reset— unix timestamp when the window resets
Every call is logged and visible to your agency owner under Settings → API → API request log, including status code, endpoint, duration, and the last error message — share this with COIflow support when troubleshooting AMS sync failures.
On 429 or 5xx, retry with exponential backoff (1s, 2s, 4s, 8s, max 60s) and respect any Retry-After header.
Pagination & incremental sync
All list endpoints accept limit (default 100, max 500) and offset. Responses include a pagination.next_offsetyou can pass back to fetch the next page, or null when complete.
For incremental sync, pass updated_since=2026-06-17T00:00:00Zon /insureds and /certificatesto receive only records modified after that timestamp.
Endpoints
GET /api/public/v1/health
Authorization: Bearer coif_live_…
{
"ok": true,
"agency_id": "a1b2c3d4-…",
"scopes": ["read:insureds","read:certificates","read:coverages"],
"server_time": "2026-06-18T16:42:00.000Z"
}- limitnumber— 1–500, default 100
- offsetnumber— default 0
- updated_sinceISO-8601— only records modified at or after this time
GET /api/public/v1/insureds?limit=100&updated_since=2026-06-17T00:00:00Z
{
"data": [{
"id": "…",
"business_name": "Riverside Builders LLC",
"contact_name": "Sam Patel",
"email": "ops@riverside.example",
"phone": null,
"worst_status": "verified",
"compliance_score": 92,
"missing_coverages": [],
"created_at": "2026-04-02T14:11:09Z",
"updated_at": "2026-06-18T13:02:00Z"
}],
"pagination": { "limit": 100, "offset": 0, "total": 217, "next_offset": 100 }
}- insured_iduuid— filter to one insured
- statusstring— verified, expiring, gap, lapsed, needs_review
- updated_sinceISO-8601— incremental sync filter
- limit / offsetnumber— pagination
GET /api/public/v1/certificates?status=expiring
{
"data": [{
"id": "…",
"insured_id": "…",
"carrier": "Hartford",
"cert_type": "General Liability",
"status": "expiring",
"reason": "Expires within 30 days",
"certificate_holder": "Acme Holdings LLC",
"expiration_date": "2026-07-04",
"parse_confidence": 0.94,
"parsed_at": "2026-06-12T09:13:22Z",
"created_at": "2026-06-12T09:12:55Z",
"updated_at": "2026-06-12T09:13:22Z"
}],
"pagination": { "limit": 100, "offset": 0, "total": 14, "next_offset": null }
}- insured_iduuid— filter to coverages under one insured
- certificate_iduuid— filter to one certificate
- limit / offsetnumber— pagination
GET /api/public/v1/coverages?insured_id=…
{
"data": [{
"id": "…",
"certificate_id": "…",
"coverage_type": "general_liability",
"policy_number": "GL-9912034",
"effective_date": "2026-01-01",
"expiration_date": "2027-01-01",
"each_occurrence": 1000000,
"aggregate": 2000000,
"combined_single_limit": null,
"additional_insured": true,
"waiver_of_subrogation": false
}],
"pagination": { "limit": 100, "offset": 0, "total": 3, "next_offset": null }
}AMS sync guide
COIflow's API is designed for safe polling on a schedule from your AMS or middleware. Follow this pattern and you'll stay well within rate limits with zero data loss.
- Pick a cadence. Hourly is plenty for most agencies. For near-real-time workflows, every 5 minutes is safe.
- Persist a cursor. Store the timestamp of your last successful sync (e.g.
last_synced_at). Initialize it to a date well before your agency started using COIflow. - Pull deltas. Call
/insuredsand/certificateswithupdated_since=<last_synced_at>, paginating withnext_offsetuntil it isnull. - Hydrate coverages. For each new or changed certificate, call
/coverages?certificate_id=…(orinsured_id=…if you prefer to refresh per-client). - Commit the cursor. Only advance
last_synced_atafter every page has been written to your AMS. If a step fails, you'll re-pull the same window on the next run — every endpoint is idempotent. - Retry transient errors. Treat
429and5xxas retryable with exponential backoff (1s → 60s). Treat401/403as permanent — alert an admin to rotate the key. - Set a sane
User-Agentlike"AcmeAgency-AMSSync/1.2"so we can help you debug if traffic ever looks off.
cursor = read_cursor() or "2025-01-01T00:00:00Z" now = utc_now_iso() offset = 0 while true: res = GET "/api/public/v1/certificates?updated_since=" + cursor + "&offset=" + offset upsert_into_ams(res.data) if res.pagination.next_offset is null: break offset = res.pagination.next_offset for cert in changed_certificates: cov = GET "/api/public/v1/coverages?certificate_id=" + cert.id upsert_coverages(cov.data) write_cursor(now)
Need a connector for a specific AMS (AMS360, Applied Epic, HawkSoft, EZLynx, QQCatalyst)?Tell us what you need — we'll prioritize the most-requested platforms.