Skip to content
Webhooks
.md

Webhooks

Webhooks are the push half of the async model: instead of polling a resource until its status is terminal, register an HTTPS endpoint and Intuizi calls you the moment an audience, activation or cohort completes or fails. The payload carries the same object the matching GET endpoint returns, so no follow-up read is needed.

Registration is in the console

Webhook endpoints are created, edited, rotated, paused and deleted in the Intuizi console only, under My Organization > Webhooks. There is no write API: a webhook endpoint is durable organization configuration holding a signing secret, and an API token must never be able to silently retarget where your completion events are pushed.

The API exposes exactly one read, GET /api/v2/webhooks/index, so an integration can confirm from code that a subscription exists and which event types it covers. The signing secret never appears in any API response.

When you create an endpoint you choose:

  • the URL - must be https://, on the default port, using a public hostname (IP addresses, private hosts and redirecting URLs are rejected),
  • the event types it subscribes to (see the catalog below),
  • and you receive the signing secret exactly once, at creation. Store it immediately; afterwards only a masked fragment is shown. Rotating generates a new secret (also shown once) and keeps the old one valid for 24 hours so you can switch without dropping events.

Event catalog

Six event types, each sent once a resource has finished. 104 Completed is the only successful lifecycle state - 105 DataStreaming happens before it, so there is deliberately no “delivering” event, and no progress events.

Event typeFires whendata is the object returned by
audience.completedan audience or lookalike reaches lifecycle status 104 CompletedGet Audience
audience.failedan audience or lookalike fails: it stops at 107 Additional Info or reaches a 4xx lifecycle error status, including the 400 a cancelled lookalike ends atGet Audience
activation.completedan activation reaches lifecycle status 104 CompletedGet Activation
activation.failedan activation fails: it stops at 107 Additional Info or reaches a 4xx lifecycle error statusGet Activation
cohort.completeda cohort reaches status 4 CompletedGet Cohort
cohort.faileda cohort reaches status 5 Not Available: the import failedGet Cohort

Four catalog notes:

  • Lookalikes are audiences. A completed lookalike arrives as audience.completed with data.is_lookalike set to true - filter on that field if you handle them differently.
  • 107 Additional Info is a failure. A build that stops at 107 sends the same audience.failed or activation.failed event as a 4xx error state. Read data.status.id to tell them apart. The payload carries only the status id and name, and Audience Manager shows the reason.
  • Cohorts use their own status scale (1-5), not the 1xx lifecycle. See Status Codes.
  • Every failure sends an event. Besides 107 and the 4xx states, that covers a Lookalike Model run you cancel, which ends at 400 Error and sends audience.failed, and a failed cohort import, which ends at 5 Not Available and sends cohort.failed. A poll is only the fallback for a delivery that exhausts its retries - see Webhooks or polling?.

A webhook.test event can also be sent from the console at any time to exercise your receiver; it is delivered regardless of your subscriptions and its data is a small fixed object, not a resource.

The delivery

Every delivery is an HTTPS POST to your URL with these headers:

Content-Type: application/json
User-Agent: Intuizi-Webhooks/1
Intuizi-Event-Id: evt_01K9Z4F0J6R8QW3T5Y7B2N4M6C
Intuizi-Event-Type: audience.completed
Intuizi-Delivery-Id: dlv_01K9Z4F0J8H2V5X7C9E1G3J5L7
Intuizi-Delivery-Attempt: 1
Intuizi-Signature: t=1774102711,v1=8f3c...e91a

and this body:

{
  "schema_version": 1,
  "id": "evt_01K9Z4F0J6R8QW3T5Y7B2N4M6C",
  "type": "audience.completed",
  "created_at": "2026-07-21T14:05:11Z",
  "company_id": 55,
  "data": { }
}
  • data is the resource object exactly as the matching GET returns it - the object itself, not the single-element data array the GET envelope wraps it in. Field-level schemas are on the Webhooks API page.
  • Payloads are additive: new fields can appear in data without a schema_version bump, so your consumer must tolerate and ignore fields it does not recognize rather than rejecting the delivery. eligibility and totals were added to the audience object on 2026-08-23.
  • id identifies the logical event. It is identical across retries and across all of your endpoints that receive the same event.
  • The envelope created_at is RFC 3339 UTC (2026-07-21T14:05:11Z). Note the timestamps inside data use the API’s Y-m-d H:i:s format - they are different fields with different formats.

Respond with any 2xx status within 10 seconds. The response body is ignored (at most a short snippet is kept for the console delivery log). Redirects are not followed - a 3xx counts as a failed delivery.

Verifying the signature

Every delivery is signed with your endpoint’s secret so you can prove it came from Intuizi and was not altered. The Intuizi-Signature header carries a unix timestamp and one or more HMAC-SHA256 signatures over "{t}.{raw_body}":

Intuizi-Signature: t=1774102711,v1=8f3c...e91a

To verify:

  1. Read t and each v1 value from the header.
  2. Compute HMAC_SHA256(secret, t + "." + raw_body) over the raw request body bytes (before any JSON parsing).
  3. Compare against each v1 using a constant-time comparison. Accept if any matches.
  4. Reject if t is more than 5 minutes from your current time - this bounds replay of a captured delivery.

During the 24 hours after a secret rotation the header carries two v1 values (new secret first, then old), so a receiver holding either secret keeps verifying. Code samples in four languages are on the Webhooks API page.

Delivery semantics

  • At-least-once. A delivery can arrive more than once (for example when your server processed it but the response was lost). Deduplicate on Intuizi-Event-Id and make your handler idempotent.
  • Ordering is not guaranteed across events. Use the resource id and status inside data, not arrival order.
  • Retries. A failed delivery (non-2xx, timeout, or connection error) is retried up to 6 times over roughly 8.5 hours, with growing gaps (about 1 minute, then 5, 25, 2 hours, 6 hours after the first attempt). Intuizi-Delivery-Attempt tells you which attempt you are seeing.
  • Auto-disable. After 20 consecutive exhausted deliveries the endpoint is disabled automatically and its creator is notified in the console. Re-enabling is a console action and resets the failure counter.
  • The delivery log for each endpoint (status, attempts, response code, response snippet) is visible in the console next to the endpoint.

Webhooks or polling?

Use webhooks as the primary completion signal - they remove the wasted request budget and the discovery latency of polling. Keep a low-frequency poll (or an on-demand GET) as the fallback for the rare delivery that exhausts its retries: webhooks are a notification channel, not a source of truth. The resource itself, read via GET, is always the source of truth.