Capturia measures its ads and site traffic with the Meta pixel and Google Analytics. You can decline at any time. Learn more

FR

Events

2 endpoints

post/v1/events

Push a custom event that triggers automations

Generic inbound webhook per account: an external source (Zapier, Make, n8n, a client backend, a third-party tool) pushes a named event with its data. Capturia resolves the contact (external_id → phone → email), enriches the contact non-destructively, fills in the mapped custom fields, records the event on the contact, then starts the automations whose "Custom event" trigger listens for this event name — with the payload available in messages through {{event.<key>}}.

Contact resolution

At least one identifier is required (external_id, email or phone). If no contact matches, a minimal contact is created — unless contact.create_if_missing is false, in which case the request returns 404 contact_not_found without recording anything. If the identifiers only match an archived contact, the event is recorded on it (for traceability) but the contact is not modified and no automation is enrolled (contact_archived: true).

Receiving an event does not establish any communication consent. A contact created through this path cannot receive SMS/email until consent is captured through another flow; a triggered automation that tries to send without consent is blocked by the execution engine's guards.

Optional HMAC signature

In addition to the API key, the request can carry a signature X-Capturia-Signature: t=<unix>,v1=<hex> — an HMAC-SHA256 of ${t}.${raw body} computed with the raw API key as the secret, with a 5-minute anti-replay window. As soon as the header is present, validation is strict (fail-closed): an invalid signature = 401 invalid_signature. Without the header, the API key alone authenticates the request.

Idempotency

The Idempotency-Key header is optional but recommended for retries: a second request with the same key and the same payload returns the original response without ingesting the event again (stored for 24h; a different payload = 409 idempotency_conflict). In addition, automation enrollment has its own 5-minute deduplication per contact and per automation.

Custom error codes

  • 429 — rate_limited_ip when the IP rate limit (120 req/min) is reached, with header X-RateLimit-Scope: ip. Per-key limit: 60 req/min (adjustable per key).
Required scopes: events:ingest

Request body

PropertyTypeRequiredDescription
eventstringrequiredEvent name, in the account's namespace. Compared as-is (case-sensitive) to the name configured on the automations' "Custom event" trigger.
contactEventIngestContactrequired—
payloadobjectoptionalArbitrary event data. Each top-level key is available to automation messages through {{event.<key>}} (a nested object is serialized as JSON). The stored content is capped (number of keys, depth, total size).
custom_fieldsobjectoptionalCustom fields of the contact, keyed by the definition's name (same contract as /v1/leads/capture). A key with no matching definition is silently ignored. Additive merge: the new value wins on collision.
source_labelstringoptionalFree-form label identifying the source (shown on the contact).

Responses

StatusDescription
200

Event ingested (status: ingested). enrolled_executions tells you how many automations started; 0 means no active automation listens for this event name — the event is still recorded on the contact.

400

The request is malformed (missing header, invalid JSON, invalid parameter).

401

Unknown API key or invalid format.

403

Authorization denied. Two causes, distinguished by code: insufficient_scope (the key lacks the required scope — details.required_scope) or feature_not_available (the public API or the targeted module isn't included in the account's plan — details.feature names the feature, e.g. public_api, quotes). A plan denial is final for the key: don't retry; the account must change plans.

404

The requested resource doesn't exist (or isn't within the tenant's scope).

409

A previous request with the same Idempotency-Key used a different payload, or is still being processed.

422

Parameter or body validation failed.

429

The per-window request quota has been exceeded for this API key or endpoint.

500

Unexpected server error. Always include the request_id when contacting support.

Example request

curl -X POST 'https://api.capturia.io/v1/events' \
  -H 'Authorization: Bearer cap_live_<your-key>' \
  -H 'Content-Type: application/json' \
  -d '{
  "event": "abandon_panier",
  "contact": {
    "external_id": "user-4821",
    "external_source": "mon-backend",
    "email": "[email protected]",
    "first_name": "Alex"
  },
  "payload": {
    "montant": 249.99,
    "produit": "Forfait Pro",
    "url_panier": "https://boutique.example.com/panier/abc123"
  },
  "custom_fields": {
    "plan_vise": "pro"
  },
  "source_label": "Boutique en ligne"
}'
post/v1/event-registrations

Register a contact for an event

Registers an existing contact of the account for a published event (webinar, challenge, summit, online event). The person then receives the event's messages, just as if they had registered through its page.

One registration per person and per edition: a second call for the same contact and the same edition returns the same registration with 200 and created: false, without resending the confirmation. It updates the language, and re-registers a person who had said they would not attend; a person who asked to stop receiving messages stays opted out. The call is therefore safe to retry, without an Idempotency-Key header.

Requires the plan's Event support module (403 feature_not_available otherwise) and the contacts:write scope.

Rejections

  • 404 resource_not_found with details.resource: contact (contact missing, merged or from another account), event or edition.
  • 422 business_rule_violation with details.rule: event_not_published (draft), event_closed (event archived, edition cancelled, or no upcoming edition), event_edition_ended (edition ended).
  • 400 validation_error: invalid body, or event_id and event_slug both present or both missing.
Required scopes: contacts:write

Request body

PropertyTypeRequiredDescription
contact_idstringrequiredContact to register.
event_idstringoptionalIdentifier of the event.
event_slugstringoptionalAddress of the event, as it appears in its registration link.
edition_idstringoptionalTarget edition. If omitted: the event's next open edition, as on its registration page.
languagestringoptionalLanguage of the messages. If omitted: the event's first language.

Responses

StatusDescription
200

The contact was already registered for this edition; the same registration is returned.

201

Registration created.

400

Parameter or body validation failed.

401

Unknown API key or invalid format.

403

Authorization denied. Two causes, distinguished by code: insufficient_scope (the key lacks the required scope — details.required_scope) or feature_not_available (the public API or the targeted module isn't included in the account's plan — details.feature names the feature, e.g. public_api, quotes). A plan denial is final for the key: don't retry; the account must change plans.

404

The requested resource doesn't exist (or isn't within the tenant's scope).

415

The Content-Type header is missing or not supported for this endpoint.

422

The request is syntactically valid but violates a business rule.

429

The per-window request quota has been exceeded for this API key or endpoint.

500

Unexpected server error. Always include the request_id when contacting support.

503

Service temporarily unavailable (maintenance, external dependency down, degraded infrastructure). Clients should retry with exponential backoff.

Example request

curl -X POST 'https://api.capturia.io/v1/event-registrations' \
  -H 'Authorization: Bearer cap_live_<your-key>' \
  -H 'Content-Type: application/json' \
  -d '{
  "contact_id": "9b8a7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
  "event_slug": "defi-5-jours",
  "language": "fr"
}'