GUIDES

Receiving results

Configure delivery once and every event reaches your system as a signed webhook, a scheduled batch file, or both. PUT /delivery sets the configuration and GET /delivery returns it with recent webhook stats and recent batch runs. Each key's mode has its own configuration: a test key configures and sees test-mode delivery only.

PUT /delivery replaces the whole configuration. Example:

{ "webhook": { "url": "https://example.com/iv-webhooks", "events": ["document.*", "verdict.*"] },
  "batch": { "schedule": "daily", "hour_utc": 6, "format": "jsonl", "events": ["*"],
             "include_snapshot": true, "include_documents": false,
             "destination": { "type": "gcs", "bucket": "…", "prefix": "…" } } }

Send webhook, batch, or both. A block you leave out is removed. An unknown field, an unknown event name, or a body with neither block returns 422.

Webhooks

Set a url and an events list. An entry is an event name, a family such as document.*, or * for everything. Omit events and you get document.* plus verdict.*. The url must be https and resolve to a public host. A test key can also use http://localhost.

The response returns the signing secret once, as webhook.secret. The secret stays the same while the url is unchanged. A new url mints a new secret. Events that occurred before the webhook was configured, or before its url last changed, are not sent to it.

Each delivery is a JSON POST with these headers:

Header What it carries
X-IV-Event The event name. Dispatch on this
X-IV-Event-Id The event_id, also in the body
X-IV-Timestamp When we signed it, in Unix seconds
X-IV-Signature v1=<hex HMAC-SHA256 of "<timestamp>.<body>">
User-Agent InsuranceVerified-Webhooks/​1.0 (+https:/​/​insuranceverified.ai/​docs/​guides/​delivery)

To verify a delivery, compute the HMAC-SHA256 over the X-IV-Timestamp value, a ., and the raw request body, keyed with your secret. Compare v1=<hex digest> to X-IV-Signature in constant time, and reject a delivery whose timestamp is more than five minutes from your clock.

A 2xx response within 10 seconds marks the event delivered. Redirects are not followed. Anything else, or no response, retries: 1 minute after the first failure, doubling to at most 1 hour between tries, until 24 hours after the event occurred. Then the event is marked failed. GET /delivery shows webhook.delivery_stats: pending, delivered_24h, failed_24h, last_delivered_at, and last_failure.

Retries mean the same event can land twice, so store every event_id you have processed and drop the ones you have seen. A retried event can also land after newer ones. When an event and a read disagree, the read wins. GET the object.

Ignore unknown fields and unknown event names. v1 adds optional fields and event types without notice.

Batch files

Set a schedule of hourly or daily, with an hour_utc from 0 to 23 for daily, a format of jsonl or csv, and a destination. Batch events defaults to ["*"].

destination.type Where the files go
gcs Your bucket: set bucket and prefix
pull Our exports store. Read them through GET /​exports
s3, sftp Not available yet. PUT /​delivery returns 422

An hourly batch covers the previous clock hour and is produced after the hour ends. A daily batch covers the previous UTC day and is produced at hour_utc. The first scheduled batch covers the first period that ends after you configure it. Each run produces the latest complete period only, so backfill a missed period with POST /delivery/batch/run.

File When
events.<format> Always. Every event in the period that matches batch events, in the webhook envelope, ordered by occurred_at
coverage_lines.<format> and verdicts.<format> When include_snapshot is true, which is the default. Every coverage line of the insureds you engage, with insured_ref and as_of, and the latest engagement-level verdict per engagement: the verified verdict when one exists, else the surface check
documents/​<document_id>-<filename> When include_documents is true. Every file received under your account in the period
manifest.json Always. batch_id, schema_version, period_start, period_end, format, test, counts, and name, size_bytes, row_count, sha256 per file

In csv, nested values are JSON strings.

A gcs batch is written as <prefix>/<period>/<file>, where <period> is the period start in the form 2026-09-24T0000Z. A _SUCCESS marker is written last, so wait for it before you read. Each period has one batch, and re-running a period rewrites its files under the same batch_id. A failed batch retries on the same backoff for 24 hours, then becomes failed and queues delivery.batch_failed. The webhook receives it when your webhook events include it.

POST /delivery/batch/run produces a batch now. With no body, it produces the latest complete period. With since and until, both RFC 3339 with an offset, it backfills that period: until must be after since, no later than now, and at most 31 days after since. It returns 202 with the batch. GET /exports lists batches, newest first, and GET /exports/{batch_id} returns one. A produced batch carries a signed url per file, valid for ten minutes, for both destinations.

Proving it works

POST /delivery/webhook/test signs and sends a ping to your endpoint now, through the same signing path as every other event. It returns 202 with delivered, status_code, error, and duration_ms, or 409 when no webhook is configured. A ping your handler accepts means your signature check is right. A ping is sent whatever your events list says, and batch files leave it out.

Every event, what fires it, and what it carries is on Events.

Next