Documentation
Everything Oriva accepts, down to the field: the tracking code commands, the server API, the list of events and what each one becomes at each platform. To connect a platform step by step, use the Integrations pages, or Shopify if that is your store. If you code with an AI assistant, give it this page or its text version, /en/llms.txt.
Two ways to send an event
| Tracking code (browser) | Server API | |
|---|---|---|
| Key | pk_, public, in the page | sk_, secret, on your server |
source | browser | server |
| Triggers an affiliate postback | No | Yes |
ip and user_agent | Read by Oriva from the connection | Yours to provide (the visitor's) |
Key
- Tracking code (browser)
pk_, public, in the page- Server API
sk_, secret, on your server
source- Tracking code (browser)
browser- Server API
server
Triggers an affiliate postback
- Tracking code (browser)
- No
- Server API
- Yes
ipanduser_agent- Tracking code (browser)
- Read by Oriva from the connection
- Server API
- Yours to provide (the visitor's)
A pk_ key can only send browser events, an sk_ key only server events. The affiliate postback only fires on a server sale: a public key is visible to everyone, so it must not be able to create a commission.
The tracking code
You'll find it, already filled in with your subdomain and key, in the “Tracking code” step of your workspace. It loads oriva.js from your tracking subdomain (t.<your-domain>) and exposes one function, oriva(command, …). You can call it before the script has loaded: calls are queued and replayed.
<script async src="https://t.<your-domain>/oriva.js"></script>
<script>window.oriva=window.oriva||function(){(oriva.q=oriva.q||[]).push(arguments)};oriva('init',{key:'pk_…'});</script>oriva('init', options)
Already in the code you were given. Sends a page_view on load.
| Option | What it does |
|---|---|
key | Your pk_ key. Required. |
host | The tracking subdomain. Defaults to the one oriva.js is loaded from. |
page_view | false to skip the automatic page_view. |
consent_wait | Maximum time, in milliseconds, that events wait for your banner to give consent back when the page loads. 1500 by default, 0 to not wait. |
key- What it does
- Your
pk_key. Required.
host- What it does
- The tracking subdomain. Defaults to the one
oriva.jsis loaded from.
page_view- What it does
falseto skip the automaticpage_view.
consent_wait- What it does
- Maximum time, in milliseconds, that events wait for your banner to give consent back when the page loads.
1500by default,0to not wait.
oriva('consent', { ads })
Oriva starts without ad consent. Until you have called oriva('consent', { ads: true }), events are still sent, but without a visitor cookie, click id, email or phone, and nothing is sent to Meta, TikTok, Google Ads or ChatGPT Ads.
oriva('consent', { ads: false }) withdraws consent and clears the visitor cookie. Consent is only kept in memory: on every page, your banner has to give it back. To leave it time to do so, events wait for its signal for up to 1.5 seconds when the page loads (the consent_wait option), then go out without consent if it has not come. They go out at once if the visitor leaves the page. Examples for Axeptio, Didomi, Cookiebot, tarteaucitron, Complianz and CookieYes.
oriva('identify', data)
Remembers the visitor's email, phone or other data for every following event on the page. They are normalized and hashed with SHA-256 in the browser, before they leave. Call it before a lead or a purchase, for example when the form is submitted.
oriva('identify', { email: 'jane@example.com', phone: '06 12 34 56 78' });oriva('track', name, data)
Sends an event.
oriva('track', 'purchase', {
event_id: 'commande-1001',
value: 49.9,
currency: 'EUR',
order_id: '1001',
content_ids: ['sku-42'],
});event_id: your stable reference. Without it, the code generates a random one, and the same sale also sent by your server will be counted twice at the platforms.value: in units, not in cents (49.9means 49.90).currency: 3-letter ISO code. When absent, Oriva uses your domain's currency.user_data: likeidentify, but for this event only.- Any other key goes into
custom_data(see what is forwarded to the platforms).
On purchase, refreshing the thank-you page sends the same event_id again: the sale is not counted twice.
What the code captures on its own
Only with ad consent, when the page loads:
- the click ids in the URL:
fbclid,ttclid,gclid,gbraid,wbraid,msclkid,aff_click_id,oppref; - the
utm_source,utm_medium,utm_campaign,utm_content,utm_termparameters; subid,s1,s2,s3,s4,s5;- the cookies of the pixels already on the page:
_fbc,_fbp(Meta),_ttp,ttclid(TikTok),__oppref,__obref(OpenAI).
You don't have to do anything for that.
The server API
POST https://t.<your-domain>/api/v1/collect
X-Oriva-Key: sk_…
Content-Type: application/jsonOne event per request, with the fields below. Full example and good practices. Your secret key stays on your server, in an environment variable.
The fields of an event
Valid for the server API. The tracking code fills in event_id, source, occurred_at, url, referrer, consent, visitor_id and the click ids itself.
| Field | Required | Notes |
|---|---|---|
event_id | Yes | Text, 128 characters at most. Unique per domain: a second request with the same event_id is accepted but ignored. |
name | Yes | One of the events, or custom:<name>. |
source | No | browser or server, browser by default. Must match the key. |
occurred_at | No | ISO 8601 date with time zone. Now by default. At most 7 days in the past and 5 minutes in the future. |
value | No | Positive number, in units and not in cents: 49.9 means 49.90. |
currency | No | 3-letter ISO code (EUR). When absent, Oriva uses your domain's currency. |
consent | No | { "ads": true } or { "ads": false }. When absent, Oriva treats the visitor as having refused. |
visitor_id | No | UUID: the visitor's or_vid cookie, to tie the sale to their visit. |
user_data | No | Object: email, phone, first_name, last_name, zip, external_id. See Personal data. |
custom_data | No | Free-form object, 8 KB at most. See custom_data. |
click_ids | No | Object: fbclid, ttclid, gclid, gbraid, wbraid, msclkid, aff_click_id, fbc, fbp, ttp, oppref, obref. |
utm | No | Object: source, medium, campaign, content, term. |
sub_ids | No | Object: subid, s1, s2, s3, s4, s5. |
url, referrer | No | Absolute URL. Filled in by the tracking code. |
ip, user_agent | No | Server only: the visitor's, never your server's. Rejected on a browser event. |
event_id- Required
- Yes
- Notes
- Text, 128 characters at most. Unique per domain: a second request with the same
event_idis accepted but ignored.
name- Required
- Yes
- Notes
- One of the events, or
custom:<name>.
source- Required
- No
- Notes
browserorserver,browserby default. Must match the key.
occurred_at- Required
- No
- Notes
- ISO 8601 date with time zone. Now by default. At most 7 days in the past and 5 minutes in the future.
value- Required
- No
- Notes
- Positive number, in units and not in cents:
49.9means 49.90.
currency- Required
- No
- Notes
- 3-letter ISO code (
EUR). When absent, Oriva uses your domain's currency.
consent- Required
- No
- Notes
{ "ads": true }or{ "ads": false }. When absent, Oriva treats the visitor as having refused.
visitor_id- Required
- No
- Notes
- UUID: the visitor's
or_vidcookie, to tie the sale to their visit.
user_data- Required
- No
- Notes
- Object:
email,phone,first_name,last_name,zip,external_id. See Personal data.
custom_data- Required
- No
- Notes
- Free-form object, 8 KB at most. See custom_data.
click_ids- Required
- No
- Notes
- Object:
fbclid,ttclid,gclid,gbraid,wbraid,msclkid,aff_click_id,fbc,fbp,ttp,oppref,obref.
utm- Required
- No
- Notes
- Object:
source,medium,campaign,content,term.
sub_ids- Required
- No
- Notes
- Object:
subid,s1,s2,s3,s4,s5.
url,referrer- Required
- No
- Notes
- Absolute URL. Filled in by the tracking code.
ip,user_agent- Required
- No
- Notes
- Server only: the visitor's, never your server's. Rejected on a
browserevent.
An empty string counts as absent. Unknown fields are ignored.
Events
| Event | Sent to the platforms | What it is |
|---|---|---|
page_view | No | A page view. Sent automatically by the tracking code. |
view_content | No | A product page or other content viewed. |
add_to_cart | If you turn it on for the destination (Meta, TikTok, ChatGPT Ads) | An add to cart. |
initiate_checkout | If you turn it on for the destination (Meta, TikTok, ChatGPT Ads) | The start of checkout. |
lead | Yes | A contact: form, quote request, list signup. |
purchase | Yes | A purchase. |
complete_registration | Yes | An account creation. |
subscribe | Yes | A paid subscription started. |
start_trial | Yes | A trial started. |
custom:<name> | Yes | Any other event that matters to you: an outbound click, a download. |
page_view- Sent to the platforms
- No
- What it is
- A page view. Sent automatically by the tracking code.
view_content- Sent to the platforms
- No
- What it is
- A product page or other content viewed.
add_to_cart- Sent to the platforms
- If you turn it on for the destination (Meta, TikTok, ChatGPT Ads)
- What it is
- An add to cart.
initiate_checkout- Sent to the platforms
- If you turn it on for the destination (Meta, TikTok, ChatGPT Ads)
- What it is
- The start of checkout.
lead- Sent to the platforms
- Yes
- What it is
- A contact: form, quote request, list signup.
purchase- Sent to the platforms
- Yes
- What it is
- A purchase.
complete_registration- Sent to the platforms
- Yes
- What it is
- An account creation.
subscribe- Sent to the platforms
- Yes
- What it is
- A paid subscription started.
start_trial- Sent to the platforms
- Yes
- What it is
- A trial started.
custom:<name>- Sent to the platforms
- Yes
- What it is
- Any other event that matters to you: an outbound click, a download.
The first four are for your Oriva dashboard. They are not sent to any platform. The others become conversions, under these names:
| Oriva event | Meta and TikTok | ChatGPT Ads |
|---|---|---|
lead | Lead | lead_created |
purchase | Purchase | order_created |
complete_registration | CompleteRegistration | registration_completed |
subscribe | Subscribe | subscription_created |
start_trial | StartTrial | trial_started |
add_to_cart | AddToCart | items_added |
initiate_checkout | InitiateCheckout | checkout_started |
custom:<name> | <name> | <name>, as a custom event |
lead- Meta and TikTok
Lead- ChatGPT Ads
lead_created
purchase- Meta and TikTok
Purchase- ChatGPT Ads
order_created
complete_registration- Meta and TikTok
CompleteRegistration- ChatGPT Ads
registration_completed
subscribe- Meta and TikTok
Subscribe- ChatGPT Ads
subscription_created
start_trial- Meta and TikTok
StartTrial- ChatGPT Ads
trial_started
add_to_cart- Meta and TikTok
AddToCart- ChatGPT Ads
items_added
initiate_checkout- Meta and TikTok
InitiateCheckout- ChatGPT Ads
checkout_started
custom:<name>- Meta and TikTok
<name>- ChatGPT Ads
<name>, as a custom event
- Google Ads: a destination follows a single event, the one you choose when you create it (any of those that go to the platforms). To follow a lead and a purchase, create two destinations.
- Affiliate postback: every event that goes to the platforms, or a single one if you pick one, and only if they come from your server.
custom:<name>:<name>is 1 to 64 characters long, made of lowercase letters, digits,_and-, and starts with a letter or a digit (custom:clic_partenaire). For ChatGPT Ads, first create a conversion event with the exact name (clic_partenaire) in your ads manager: without it, OpenAI accepts the request but counts nothing.
custom_data
Oriva stores everything you put there (up to 8 KB), but only forwards part of it:
- Meta and TikTok only receive these keys:
content_ids,content_id,content_name,content_type,content_category,contents,num_items,order_id,predicted_ltv,search_string,status,delivery_category,quantity,query. Any other key stays with Oriva. - ChatGPT Ads receives the same ones, plus
plan_idonsubscribeandstart_trial. - Google Ads does not read
custom_data. - Postback:
payoutfeeds the{payout}variable of your URL. All the variables.
order_id is also used by the Health tab to spot the same order sent by both the browser and the server.
Personal data
Fields accepted in user_data: email, phone, first_name, last_name, zip, external_id.
Oriva never keeps these values in clear text: they are normalized, then hashed with SHA-256 before they are written. You can send them in clear text or already hashed (64 hexadecimal characters): an already hashed value is kept as is, provided you normalized it the same way:
- everything: leading and trailing spaces removed, lowercase;
- phone: digits only, with the country code, without
+(33612345678). A number that starts with0and has no country code is read as French; - postal code: no spaces or hyphens, 5 characters at most;
external_id: case kept.
Without ad consent, user_data is not stored at all.
Responses and errors
Success: 202.
{ "ok": true, "event_id": "commande-1001", "deduped": false }deduped: true: this event_id was already known, the event is ignored. buffered: true: Oriva set it aside during an incident and will write it as soon as possible. In both cases, don't send it again.
Errors: always { "ok": false, "error": "…" }.
| Status | error | What it means |
|---|---|---|
400 | invalid_payload | A field is invalid. issues gives the path and the reason for each one. |
400 | invalid_payload:ip_and_user_agent_are_server_only | ip or user_agent sent on a browser event. |
401 | missing_api_key | No key, neither in the X-Oriva-Key header nor in ?k=. |
401 | invalid_api_key:malformed | The key does not have the right format. |
401 | invalid_api_key:unknown | Unknown key. |
401 | invalid_api_key:revoked | Revoked key. |
401 | key_scope:public_key_cannot_send_server_events | A pk_ key sending a server event. |
401 | key_scope:secret_key_cannot_send_browser_events | An sk_ key sending a browser event. |
403 | origin_not_allowed | Call from a browser, on a site other than your domain. |
429 | rate_limited | Too many calls. retry_after and the Retry-After header tell you how many seconds to wait. |
400- error
invalid_payload- What it means
- A field is invalid.
issuesgives the path and the reason for each one.
400- error
invalid_payload:ip_and_user_agent_are_server_only- What it means
iporuser_agentsent on abrowserevent.
401- error
missing_api_key- What it means
- No key, neither in the
X-Oriva-Keyheader nor in?k=.
401- error
invalid_api_key:malformed- What it means
- The key does not have the right format.
401- error
invalid_api_key:unknown- What it means
- Unknown key.
401- error
invalid_api_key:revoked- What it means
- Revoked key.
401- error
key_scope:public_key_cannot_send_server_events- What it means
- A
pk_key sending aserverevent.
401- error
key_scope:secret_key_cannot_send_browser_events- What it means
- An
sk_key sending abrowserevent.
403- error
origin_not_allowed- What it means
- Call from a browser, on a site other than your domain.
429- error
rate_limited- What it means
- Too many calls.
retry_afterand theRetry-Afterheader tell you how many seconds to wait.
Only a 429 can be retried as is. A 400 or a 401 will fail the same way until the request or the key changes.
The read API
Pro and Agency plans. An rk_ token, created in the app (account menu, API), to pull your numbers into your own tools: a spreadsheet, a client report, an alert. It can't change anything. To send events, use the server API and an sk_ key, on every plan.
curl -H "Authorization: Bearer rk_…" \
https://www.orivaforge.com/api/v1/read/propertiesAll routes are GET and answer in JSON. Amounts in cents, dates in ISO (UTC). :id is a domain's id, returned by the first route.
No code needed: the API page of the app gives you a ready-to-paste Google Sheets script that fills a tab every morning, keeps a history and can warn you on Slack when a destination starts failing.
Your domains
GET /api/v1/read/properties: The account's domains, with the id to pass to the other routes.
[
{
"id": "0192f3a4-7b1c-7d2e-9f10-2a3b4c5d6e7f",
"domain": "boutique.fr",
"name": "boutique.fr",
"status": "active"
}
]Health
GET /api/v1/read/properties/:id/health: The same state as the Health tab: each destination, the checks to fix, collection.
{
"diagnostics": [
{ "code": "DESTINATION_FAILING", "severity": "high", "message": "…" }
],
"destinations": [
{
"name": "Meta",
"kind": "meta_capi",
"displayStatus": "failing",
"sent": 41,
"failed": 5,
"lastFailureError": "HTTP 400: OAuthException code 190 …",
"deliveredRate": 0.89
}
],
"pulse": { "lastEventReceivedAt": "2026-09-27T06:58:12.000Z", "browserEvents24h": 1320 }
}Key figures
GET /api/v1/read/properties/:id/summary: Conversions, revenue, spend, ROAS and the gap with the platforms over the period.
- from, to: ISO dates (2026-09-01), last 30 days by default, 90 days at most.
{
"conversions": 128,
"purchases": 97,
"revenueByCurrency": [
{ "currency": "EUR", "revenueCents": 684250, "spendCents": 210000, "roas": 3.26 }
],
"platformGap": {
"total": -12,
"orivaConversions": 88,
"platformConversions": 100,
"ratio": -0.12,
"matchedRows": 14
}
}Delivery log
GET /api/v1/read/properties/:id/conversions: Recent conversions and their status at each destination.
- limit: 50 by default, 200 at most. Newest first.
[
{
"id": "0192f3b8-…",
"occurredAt": "2026-09-27T06:41:03.000Z",
"eventName": "purchase",
"valueCents": 5990,
"currency": "EUR",
"campaign": "rentree-2026",
"orderId": "1042",
"deliveries": [
{ "destinationName": "Meta", "destinationKind": "meta_capi", "status": "sent", "error": null }
]
}
]Click to conversion delay
GET /api/v1/read/properties/:id/attribution-delays: Per campaign, the median delay and the one by which 8 conversions in 10 had arrived.
- from, to: same as for the key figures.
[
{ "campaign": "rentree-2026", "conversions": 42, "medianDelayMs": 5400000, "p80DelayMs": 172800000 }
]Limits and errors
- 60 calls per minute and per token.
- 90 days at most per call, 30 by default.
- 200 conversions at most per call.
| Status | error | What it means |
|---|---|---|
401 | missing_token | No Authorization: Bearer <token> header, or it is malformed. |
401 | invalid_token | Unknown or revoked token. |
403 | plan_restricted | The account is no longer on a Pro or Agency plan. |
404 | not_found | This domain doesn't exist, or doesn't belong to the token's account. |
429 | rate_limited | More than 60 calls per minute. The Retry-After header says in how many seconds to retry. |
401- error
missing_token- What it means
- No
Authorization: Bearer <token>header, or it is malformed.
401- error
invalid_token- What it means
- Unknown or revoked token.
403- error
plan_restricted- What it means
- The account is no longer on a Pro or Agency plan.
404- error
not_found- What it means
- This domain doesn't exist, or doesn't belong to the token's account.
429- error
rate_limited- What it means
- More than 60 calls per minute. The
Retry-Afterheader says in how many seconds to retry.
Errors use the { "error": "…" } format. Only a 429 can be retried as is.
Further reading
- Integrations: connect each platform and each kind of site.
- Shopify and the guide to the Shopify cutoff.
- Double counting between the pixel and the server API.
- The text version of this page, for your AI assistant.
Try Oriva for free.
14 days to connect your site and watch your sales reach your platforms.
Start free trial