Every certificate read to the last endorsement — verdicts in about 60 seconds

REST API

Everything the dashboard does, from your own systems: create vendors, upload certificates, read extraction results and compliance status. Included in the Portfolio plan and during the free trial.

Authentication

Create a key in Settings → API keys (owner only; shown once, stored hashed) and send it as a bearer token. Limits: 5,000 requests/day per organization, 10 active keys.

curl https://YOUR-DOMAIN/api/v1/vendors \
  -H "Authorization: Bearer coi_YOUR_KEY"

Errors are JSON: {"error": {"code": "...", "message": "..."}} with conventional status codes (401 bad/expired key, 403 plan limit or scope, 404, 429 rate limit).

Scopes & expiration

Keys are created as full access or read-only. Read-only keys can call every GET endpoint (list vendors, poll certificates) but any POST/PATCH/DELETE returns 403 insufficient_scope — use them for dashboards, BI pulls and monitoring. Keys can optionally expire (90 days / 1 year) for rotation policies; an expired key returns 401 key_expired. Every API write is attributed to its key by label in the organization's activity log.

Vendors

GET/api/v1/vendors

List vendors with live compliance status. Query params: q (name search), status (compliant, issues, expiring_soon, expired, no_certificate, processing, error), page, per_page (max 100).
{
  "data": [{
    "id": 12,
    "name": "Acme Roofing LLC",
    "contact_email": "office@acmeroofing.com",
    "agent_email": "certs@summitins.com",
    "upload_url": "https://YOUR-DOMAIN/u/3f9c…",
    "status": "issues",
    "compliance": {
      "issues": ["Waiver of subrogation is required but not found on the certificate or endorsements."],
      "earliest_expiry": "2026-11-01",
      "certificate_id": 87
    },
    "created_at": "2026-07-11 18:22:05"
  }],
  "page": 1, "per_page": 25, "total": 41
}

POST/api/v1/vendors

Create a vendor. Body: {"name": "...", "contact_email"?, "agent_email"?, "notes"?}. Returns 201 with the vendor, or 403 plan_limit at your plan's vendor cap.

GET/api/v1/vendors/:id

One vendor with compliance status.

PATCH/api/v1/vendors/:id

Update name, contact_email, agent_email, notes — send only the fields you're changing.

DELETE/api/v1/vendors/:id

Delete the vendor, its certificates and stored files. Irreversible.

Certificates

POST/api/v1/vendors/:id/certificates

Upload a certificate PDF as multipart/form-data with a file field (8 MB max). Returns 202 with the certificate in processing — extraction (including endorsement-page review) runs asynchronously.
curl -X POST https://YOUR-DOMAIN/api/v1/vendors/12/certificates \
  -H "Authorization: Bearer coi_YOUR_KEY" \
  -F "file=@certificate.pdf"

GET/api/v1/vendors/:id/certificates

List a vendor's certificates, newest first.

GET/api/v1/certificates/:id

Poll after upload until status is done (parsed extraction populated: policies, limits, dates, endorsement findings with quoted evidence) or error. Typically 15–60 seconds.

Typical integration

  1. Sync vendors from your system of record with POST /vendors (idempotency: search first with ?q=).
  2. Push incoming certificate PDFs with POST /vendors/:id/certificates, poll the certificate until done.
  3. Surface status + compliance.issues in your UI, or gate work orders on status == "compliant".
  4. Send vendors their upload_url so new paper files itself.

Outbound webhooks (certificate processed, vendor became non-compliant) are planned — tell us if you need them and we'll prioritize.