Webhooks
Read-only listing of your organization’s webhook endpoints, plus the payload schema of every webhook event type. Concepts, signature verification rules and delivery semantics are on the Webhooks concepts page.
Webhook endpoints are created, edited, rotated, paused and deleted in the Intuizi console (My Organization > Webhooks), not over the API. The signing secret is shown once, in the console, at creation or rotation - it never appears in any API response.
The endpoint is authenticated and JSON-only. Send Authorization: Bearer <token> and Accept: application/json on the call. It uses the read rate
bucket (120 requests/min).
List Webhook Endpoints
GET /api/v2/webhooks/index
Lists the webhook endpoints registered for your company, newest first. Use it to confirm from code that a subscription exists and which event types it covers.
Auth: bearer token + Accept: application/json. Rate limit: read bucket
(120 requests/min).
curl "https://console.intuizi.com/api/v2/webhooks/index" \
-H "Authorization: Bearer <YOUR_TOKEN>" \
-H "Accept: application/json"Response
{
"status": "success",
"code": 200,
"message": "Resources fetched successfully.",
"data": [
{
"id": 3,
"name": "Ops receiver",
"url": "https://hooks.example.com/intuizi",
"events": ["audience.completed", "activation.completed"],
"schema_version": 1,
"is_active": true,
"last_delivery_at": "2026-07-21 09:14:02",
"created_at": "2026-07-02 11:20:41",
"updated_at": "2026-07-19 16:05:00"
}
]
}Response fields
| Field | Type | Description |
|---|---|---|
id | integer | The endpoint id. |
name | string | The label given in the console. |
url | string | The receiver URL deliveries are POSTed to. |
events | array | The event types this endpoint subscribes to. |
schema_version | integer | The payload envelope version this endpoint receives (currently 1). |
is_active | boolean | Whether the endpoint currently receives deliveries. false after a manual pause or an automatic disable. |
last_delivery_at | string or null | When the most recent delivery attempt (successful or not) finished. null if nothing was ever delivered. |
created_at | string | When the endpoint was registered. |
updated_at | string | When the endpoint was last changed. |
The signing secret is never present in any field, in any form.
Event payloads
Every delivery body is the versioned envelope described on the Webhooks concepts page:
{
"schema_version": 1,
"id": "evt_01K9Z4F0J6R8QW3T5Y7B2N4M6C",
"type": "audience.completed",
"created_at": "2026-07-21T14:05:11Z",
"company_id": 55,
"data": { }
}| Field | Type | Description |
|---|---|---|
schema_version | integer | Envelope version. Currently 1. |
id | string | The logical event id. Identical across retries and across all of your endpoints. Deduplicate on it. |
type | string | One of the six event types below. |
created_at | string | When the event was recorded, RFC 3339 UTC. Note: timestamps inside data use the API’s Y-m-d H:i:s format instead - they are different fields. |
company_id | integer | Your company id. |
data | object | The resource object, exactly as the matching GET returns it (the object itself, not the one-element data array of the GET envelope). |
audience.completed / audience.failed
data is the audience object of
Get Audience - the same
fields, same formats. audience.completed fires when the audience reaches
lifecycle status 104 Completed. audience.failed fires when the build
fails: at 107 Additional Info, where Intuizi stopped the build because it
cannot be built as defined, or at a 4xx lifecycle error status.
data.status.id tells them apart. The payload carries only the status id and
name, and Audience Manager shows the reason for a 107. Lookalikes arrive
through these same two events with data.is_lookalike set to true.
A lookalike you cancel
sends audience.failed with status 400 once the run stops, unless the
cancel arrived during publishing, in which case the run completes and sends
audience.completed.
{
"schema_version": 1,
"id": "evt_01K9Z4F0J6R8QW3T5Y7B2N4M6C",
"type": "audience.completed",
"created_at": "2026-07-21T14:05:11Z",
"company_id": 55,
"data": {
"id": 88,
"name": "Coffee lovers UK",
"status": { "id": 104, "name": "Completed" },
"is_cohort": false,
"is_lookalike": false,
"results_count": 431202,
"is_activation_allowed": 1,
"eligibility": {
"allowed": true,
"reasons": [],
"metrics": {"unique_eids": 431202, "unique_scids": null, "eid_scid_ratio": null, "is_affinity": false}
},
"source_audience": null,
"created_by": { "name": "Jane Doe", "email": "jane.doe@example.com" },
"project": null,
"operator": null,
"dataset": [
{ "analysis_type": "WebDomain", "start_date": "2026-07-01", "end_date": "2026-07-14" }
],
"created_at": "2026-07-21 13:58:41",
"updated_at": "2026-07-21 14:05:11"
}
}activation.completed / activation.failed
data is the activation object of
Get Activation.
activation.completed fires at 104 Completed - which comes after the
105 DataStreaming delivery phase, so when this event arrives
datastreams[].results.uri is ready to read. activation.failed fires when
the export fails: at 107 Additional Info, where the export stopped because
it cannot be processed as requested, or at a 4xx lifecycle error status.
Audience Manager shows the reason for a 107 on the activation.
{
"schema_version": 1,
"id": "evt_01K9Z4G8M2T6WA4V8X0D3P5R7T",
"type": "activation.completed",
"created_at": "2026-07-21T15:40:02Z",
"company_id": 55,
"data": {
"id": 123,
"description": "Coffee lovers UK -> S3",
"status": { "id": 104, "name": "Completed" },
"audience": { "id": 88, "name": "Coffee lovers UK" },
"created_by": { "name": "Jane Doe", "email": "jane.doe@example.com" },
"project": null,
"partner": { "name": "Amazon S3", "description": "Deliver to an S3 bucket" },
"pricing_model": {},
"datastreams": [
{
"name": "s3_export",
"status": "success",
"results": { "uri": "s3://your-bucket/exports/audience.csv.gz" }
}
],
"filters": { "freq_limit": false, "freq_min": null, "freq_max": null },
"filter_hash": null,
"created_at": "2026-07-21 14:20:10",
"updated_at": "2026-07-21 15:40:02"
}
}cohort.completed / cohort.failed
data is the cohort object of
Get Cohort. Cohorts run on their
own status scale (1-5), not the 1xx lifecycle: cohort.completed fires
at status 4 Completed, and cohort.failed at status 5 Not Available, the
status a failed import ends at.
{
"schema_version": 1,
"id": "evt_01K9Z4H2Q4V8YB6X0Z2F5R7T9V",
"type": "cohort.completed",
"created_at": "2026-07-21T12:12:44Z",
"company_id": 55,
"data": {
"id": 42,
"name": "Q3 customer file",
"status": { "id": 4, "name": "Completed" },
"total_eids": 184233,
"project": null,
"source": "file",
"source_audience": null,
"created_at": "2026-07-21 11:59:03",
"updated_at": "2026-07-21 12:12:44"
}
}webhook.test
Sent from the console’s “send test” action, regardless of the endpoint’s
subscriptions, so you can exercise your receiver and signature check. data
is a small fixed object (a message and the endpoint id), not a resource.
Verifying the signature
Every delivery carries Intuizi-Signature: t=<unix>,v1=<hex>[,v1=<hex>], where
each v1 is HMAC-SHA256 over "{t}.{raw_body}" keyed with your endpoint’s
secret. Verify against the raw body bytes, compare in constant time, accept
if any v1 matches, and reject timestamps more than 5 minutes from now.
During the 24 hours after a rotation two v1 values are present (new secret
first).
import hashlib, hmac, time
def verify(secret: str, header: str, raw_body: bytes, tolerance: int = 300) -> bool:
parts = dict()
signatures = []
for item in header.split(","):
key, _, value = item.partition("=")
if key == "t":
parts["t"] = value
elif key == "v1":
signatures.append(value)
timestamp = int(parts.get("t", "0"))
if abs(time.time() - timestamp) > tolerance:
return False
signed = f"{timestamp}.".encode() + raw_body
expected = hmac.new(secret.encode(), signed, hashlib.sha256).hexdigest()
return any(hmac.compare_digest(expected, sig) for sig in signatures)Respond 2xx quickly (within 10 seconds), then process asynchronously if your
handling is slow. Failed deliveries are retried up to 6 times over roughly 8.5
hours; see delivery semantics.