HTTP events API
Send conversions and identity links from your server or any other backend: POST https://ingest.routingcat.com/v1/events.
The request
POST https://ingest.routingcat.com/v1/eventsAuthorization: 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_…, fromnpx 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_idoraccount_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
503or429: retry after the secondsRetry-Aftergives, 5 for a503.- No answer: retry the same events with the same ids; they count once.
- Any other
4xx: fix the request; the same one fails again.