Skip to main content
The browser snippet already captures pageviews, clicks, and form submits automatically. Some facts are only known on your backend — a payment cleared, a policy was issued, a refund was processed. The server-side events API lets your backend send those facts directly into Dáva, joined onto the same journey the visitor’s browser started.
This is additive, not a replacement. Server-side events enrich an existing journey — they never create one. A journey always starts with a browser-attributed entry (via the tracking snippet); the server confirms what happened on it.

Authentication

Every request needs a Bearer API key. Create one under Settings → Workspace → Settings & Integrations (API Keys card) — copy the plaintext value immediately, it is shown once. Use a Test key while integrating and switch to Live for production traffic.

Joining the visitor’s journey

Pass dava_session_id — the same session ID the browser snippet is already using — so the event lands on the visitor’s existing journey instead of standing alone.
How you get that value from the browser to your backend is up to you (hidden form field, cookie, custom header, or your own API call). Then include it as dava_session_id in the event body.
If dava_session_id is missing or does not match a session in your workspace, the event is still stored — but only as an Unmatched Server Event, kept for diagnostics and never attributed to a journey. Check the session_match field in the response (“matched” or “unmatched”) to confirm your integration is threading the session ID correctly.

Identity

At least one of anonymous_id, contact_id, or hashed_email is required — the request is rejected with 400 otherwise. dava_session_id handles journey attribution; these fields drive identity-cluster matching (linking the same person across visits/devices), a separate concern.

Sending a single event

On a custom-domain install (your own hostname configured per tracking snippet installation), omit subdomain — Dáva resolves the domain from the request’s Host header instead.

Request fields

source is not a request field. Dáva derives it internally from the ingestion path ("api" for all /v1/events deliveries). Any source value sent in the request body is silently ignored.

Deduplication

Duplicates at the delivery layer are expected — a network retry, a queue redelivery, or your own backend firing the same webhook handler twice. Dáva stores every delivery it receives for the same underlying action, but reports it as one canonical event. Two events are treated as the same action when they share a dedup key, checked in this order:
  1. event_id (top-level) — your stable per-event dedup key. E.g. "policy_POL123". Any opaque string up to 128 characters — no UUID constraint.
  2. transaction_id (top-level) — the business transaction this event belongs to. E.g. "POL123". Takes priority over the same value embedded in properties.
  3. properties.transaction_id — or one of its aliases quote_id, policy_id, order_id. Use whichever name matches your domain (an insurer sends policy_id, an e-commerce store sends order_id).
  4. external_id — your safe-retry idempotency key, if none of the above is present.
If none is present, the event is stored as-is with no dedup applied — every request creates a new event. Backward-compatible: existing callers experience no change. A caller sending only external_id still deduplicates at priority 4. A caller sending only properties.transaction_id still deduplicates at priority 3. Both orderings are preserved exactly. When a second delivery matches an existing key:
  • The response is 200 (not 201) with deduped: true and the same event_id as the first delivery.
  • Any field you send with a non-null value (value, currency, properties) updates the stored event — a null/absent field never erases a value that was already there. This lets a browser-side event with no value get enriched by a later server confirmation carrying the real amount, without one delivery overwriting the other’s data.
  • created_at in the response reflects the original delivery’s timestamp, not the retry.
For cross-path dedup (a browser-snippet event and a server-side confirmation of the same purchase), use a shared business ID: supply it as top-level transaction_id from your server and as properties.order_id (or quote_id/policy_id) from the browser side — both resolve to the same dedup key. Top-level event_id is ideal when your system already assigns a stable per-event ID (e.g. a policy number prefixed with policy_, giving "policy_POL123").

Response

201 on first receipt, 200 if the event deduplicated against a prior delivery (deduped: true) — see Deduplication above.

Sending multiple events

Up to 1000 events per request, processed asynchronously — each event is independent, so one invalid event in the batch does not fail the others.
Poll the job with GET /v1/events/batch/{job_id}:

Errors