Skip to content

HTTP events API

Send conversions and identity links from any backend, as routingcat.track() and routingcat.identify() do from your app: POST https://ingest.routingcat.com/v1/events.

The request

POST https://ingest.routingcat.com/v1/events
Authorization: Bearer sk_…
Content-Type: application/json
[{"type": "identity_link", "id": "idl:acct_42", "visitor_id": "v_7QmX2kP9sLw4nT8rBc1dEf", "account_id": "acct_42"},
{"name": "purchase", "id": "in_1Q2w3E4r5T", "account_id": "acct_42", "value": 29.99, "currency": "USD", "items": [{"id": "price_pro_monthly", "unit_value": 29.99}]}]
  • The key: the server events key, sk_…, from npx routingcat keys server, sent as a bearer token. It writes events and identity links for one site and one environment, and reads nothing. Events sent with the production key count in results; the preview key’s stay out.
  • The body: one event, or an array of 1 to 100. Each event is checked on its own, so one bad event never blocks the others.
  • Counting toward results: an event needs visitor_id or account_id. One with neither is kept, and counted apart as having no key.

An event

An event holds these fields and no other: one it doesn’t take is refused, naming it, and the field meant where one is near, such as visitor_id for visitorId or occurred_at for occured_at. Your own data goes in properties.

Field Type Meaning
type identity_link identity_link for a link from a visitor to an account. Absent for an event.
name string The event’s name, as your objective or outcomes declare it: 1 to 64 characters, none of them a control character, + or /, and no space at either end. Names are compared in Unicode’s NFC form, so é typed either way is one name. Required for an event.
id string The dedup key, 1 to 256 characters, with no control character and no space at either end. Required, because providers deliver some events twice: an event sent again with the same name and id counts once, as RoutingCat first received it, so a retry is safe and a later copy changes nothing. An identity link’s id is required, and ignored: RoutingCat keys a link by its account and its visitor.
visitor_id v_ id or empty, or null The visitor, from the rc_vid cookie: v_ and 22 more characters, as RoutingCat writes it. Null or empty reads as absent.
account_id string or empty, or null Your app’s id for the account, 1 to 128 characters, with no control character and no space at either end: a record id, never an email address. Null or empty reads as absent.
value number A number. With currency, money in major units: 29.99 for $29.99. Without, a plain quantity, summed apart from money.
currency string The ISO 4217 code, in either case: USD or usd.
properties object An object of at most 8,000 bytes, recorded with the event.
items list of any Line items, as below. An invalid item, or one past the 200th, is dropped and counted, and the event kept.
occurred_at time or number When it happened: RFC 3339, or Unix seconds. Absent, the time it arrives. At most 5 minutes ahead of its arrival, and 400 days behind it.
source posthog posthog for an event a PostHog destination forwards. Absent, the source is your server.

Line items

Field Type Meaning
id string The item, such as a price or product id: 1 to 128 characters.
quantity number How many: 1 when absent.
unit_value number One unit’s value, in the event’s currency.

Limits

What At most
Events in a request 100
A request 256,000 bytes
An event 64,000 bytes
properties 8,000 bytes
Line items in an event 200
occurred_at ahead of its arrival 5 minutes
occurred_at behind its arrival 400 days

A byte limit counts the body as sent, in UTF-8; KB here is 1,000 bytes.

The answer

202 once the events are durably queued, with a result for each:

{"accepted": 1, "rejected": [{"index": 1, "code": "missing_id", "message": "id, the dedup key, is required."}], "warnings": []}
Field Meaning
accepted How many events were accepted.
rejected Each refused event: its index in the array, its code and a message.
warnings Each accepted event with a warning: its index, its code and a count.

Accepted means queued: an event sent twice is dropped later, the first copy received kept, so the answer never says whether an event was new.

Codes

Code The event Meaning
invalid_event Refused Not an event, or an event with a field it doesn’t take; the message names the field, and the one meant.
missing_id Refused No id.
missing_name Refused An event without a name.
missing_visitor_id Refused An identity link without visitor_id.
missing_account_id Refused An identity link without account_id.
properties_too_large Refused properties over 8,000 bytes.
event_too_large Refused An event over 64,000 bytes.
in_future Refused occurred_at more than 5 minutes ahead.
too_old Refused occurred_at more than 400 days before the event arrived.
items_dropped Kept Line items dropped, invalid or past the limit; count says how many.

Refusals

A refused request has a JSON body with code and message, and nothing of it is kept.

Status Code When What to do
400 invalid_body The body is not one event, or an array of events, as JSON. Fix the body.
401 unauthenticated No key, or not one RoutingCat issued. Send the server events key as Authorization: Bearer <key>.
403 credential_revoked, credential_expired The key was revoked or has expired. A replaced key keeps working for 24 hours. Use the current key, from npx routingcat keys server.
403 credential_blocked The key’s site does not accept data. Ask RoutingCat.
403 wrong_credential A key this endpoint does not take, such as the deploy key. Use the server events key.
405 method_not_allowed Not a POST. Send a POST.
413 too_large Over 256,000 bytes or 100 events. Send fewer events at a time.
503 site_unavailable, enqueue_failed, keymap_unavailable RoutingCat cannot take the events right now. Retry after Retry-After.

Retries

  • 503 or 429: retry after the seconds Retry-After gives, 5 for a 503.
  • No answer: retry the same events with the same ids; they count once.
  • Any other 4xx: fix the request; the same one fails again.