Skip to content

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

FieldTypeDescription
idintegerThe endpoint id.
namestringThe label given in the console.
urlstringThe receiver URL deliveries are POSTed to.
eventsarrayThe event types this endpoint subscribes to.
schema_versionintegerThe payload envelope version this endpoint receives (currently 1).
is_activebooleanWhether the endpoint currently receives deliveries. false after a manual pause or an automatic disable.
last_delivery_atstring or nullWhen the most recent delivery attempt (successful or not) finished. null if nothing was ever delivered.
created_atstringWhen the endpoint was registered.
updated_atstringWhen 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": { }
}
FieldTypeDescription
schema_versionintegerEnvelope version. Currently 1.
idstringThe logical event id. Identical across retries and across all of your endpoints. Deduplicate on it.
typestringOne of the six event types below.
created_atstringWhen 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_idintegerYour company id.
dataobjectThe 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.