Your data in

One contract, four adapters, your data

Every source your agency touches — carrier pulls, portal captures, email, direct API calls — resolves to the same normalized payload before anything reasons over it. The same contract serves a single agency or a network sending data on behalf of many members.

The contract

NormalizedIngestionPayload

A source the platform has never seen is one adapter away — not a new pipeline, and not a change to anything downstream of it.

Policy Ingest API

Your systems POST policy and consumer data directly. Authenticated, idempotent, rate limited per agency.

Canopy Connect webhook

Carrier pulls arrive as they complete — policies, claims, vehicles, drivers, documents.

Browser extension

Producers capture carrier portal data in place, without an export or a file hand-off.

Email

Mailboxes connect through Microsoft Graph or Nylas. Threads, attachments, and carrier notices land as first-class records.

NormalizedIngestionPayload

Every source resolves to one contract: source type, agency, raw payload, consumer identifiers, policies, documents, metadata. Adding a source means writing one adapter, not a second pipeline.

Policy Ingest API

POST /api/v1/policy-ingest

Your systems submit a policy record directly. The response is immediate; analysis runs after and lands on your webhook.

Required headers

  • AuthorizationBearer sk_live_REDACTED

    Client secret, issued once at credential creation and never stored in plain text on our side.

  • X-Client-ID44444444-4444-4444-8444-444444444444

    Your agency identifier.

  • X-Request-ID55555555-5555-4555-8555-555555555555

    Unique per request, for tracing.

  • X-Request-Timestamp2026-08-17T12:00:00.000Z

    ISO 8601. Requests outside the replay window are rejected.

  • Idempotency-Key66666666-6666-4666-8666-666666666666

    Repeat a key and you get the original response back, not a duplicate ingest.

Request bodyIllustrative example
"pull_id": "11111111-1111-4111-8111-111111111111",
"first_name": "Clark",
"last_name": "Kent",
"email": "clark.kent@example.com",
"insurance_provider_name": "Daily Planet Mutual",
"team_id": "22222222-2222-4222-8222-222222222222",
"source": "external_api",
"external_reference_id": "example-reference-001"
200 OK responseIllustrative example
"success": true,
"submission_id": "77777777-7777-4777-8777-777777777777",
"consumer_id": "88888888-8888-4888-8888-888888888888",
"pull_id": "11111111-1111-4111-8111-111111111111",
"timestamp": "2026-08-17T12:00:01.234Z",
"message": "Policy data received and processing started",
"status_url": "/api/v1/policy-ingest/status/77777777-7777-4777-8777-777777777777"

Security model

Every request is credentialed, bounded, and logged

Nothing here is optional configuration you have to remember to turn on.

ControlWhat it does
Credentialed requestsBearer secret plus a client ID header. Secrets are stored only as bcrypt hashes and shown once at creation.
Replay protectionRequests carry a signed timestamp and are rejected beyond a five-minute window.
Idempotency keysA repeated key returns the original response instead of ingesting twice.
IP allowlistingOptional per-agency source-address restriction, enforceable as a hard requirement.
Per-agency rate limitsThroughput is bounded per tenant, so one integration cannot affect another.
Signed callbacksWebhooks to your endpoint carry an HMAC-SHA256 signature you verify before trusting the body.

Scale

A robust book loads the same way it runs

Loading years of existing records is not a separate code path from the traffic that follows it.

History loads without special handling

Replaying years of records uses the same endpoint as live traffic. Idempotency keys make a repeated submission return the original result instead of duplicating it.

Mailboxes backfill on request

A connected mailbox can be backfilled rather than starting from the day it was linked.

Ingestion does not block on analysis

Submission returns immediately and analysis runs behind it, so a large load does not stall on model calls.

Throughput is bounded per tenant

Rate limits are per agency, so a bulk load in one tenant cannot degrade another.

Spend is measured per call

Token usage and cost are recorded per request and reported in a cost dashboard.

Webhooks back

Results land on your endpoint, not ours

Each agency configures its own webhook URL and chooses which events to receive.

consumer_ai_complete

Consumer-facing analysis has finished for a submission.

agent_analysis_complete

Producer-facing analysis has finished for a submission.

Every callback carries an HMAC-SHA256 signature, computed against your webhook secret. Verify it before you trust the body — an unsigned or mismatched payload should be rejected, not processed.

Aggregators and networks

One integration pattern, repeated per member

A network sending data on behalf of many member agencies uses the same contract as a single agency does — once per member, with isolation between them.

Credentials and ingestion per member

Each member gets its own ingest credentials, rate limits, and webhook destination, so one member’s integration cannot disturb another.

Onboard a member without a deployment

Adding a member is provisioning and configuration, not a release. Database, settings, branding, and users are created per agency.
See how member isolation is enforced

Unstructured material

Not everything arrives as a payload

Two upload paths cover the material that never comes through an adapter — the declaration page someone emails you, and the guidance your agency writes for itself.

Document upload

Attach a file directly and it becomes part of the record for the entity it belongs to, extracted and searchable alongside structured data.

Knowledge base upload

Your SOPs, appetite guides, and procedures. Indexed for hybrid keyword and vector retrieval, so the AI applies your rules rather than generic ones.

What happens next

A payload doesn't stop at storage

Ingestion is the first of three steps before your team sees anything.

  1. Step 1

    Normalization

    Every source resolves to one contract: source type, agency, raw payload, consumer identifiers, policies, documents, metadata. Adding a source means writing one adapter, not a second pipeline.

  2. Step 2

    Consumer resolution

    Identifiers on the payload are matched against existing records for that agency, or a new consumer is created. Everything downstream is scoped to the resolved entity.

  3. Step 3

    Hand-off to analysis

    Analysis runs against a deliberately assembled entity dossier rather than whatever happened to be in the prompt.

See how the platform reasons over it