Conversion definitions
A definition says what counts and how each platform calls it. Conversions without a definition are possible (manual entries), but only definitions map to platform events.
PUT /v1/projects/{project}/conversion-definitions/{key} (scope project:admin) creates or replaces
one (scopes conversions:write + config:write); GET …/conversion-definitions lists them; MCP conversions_definitions_list reads them.
{
"name": "Demo booked",
"trigger": { "kind": "event", "event": "booking" },
"source": "booking",
"value": 500,
"currency": "EUR",
"providers": {
"meta": { "enabled": true, "eventName": "Schedule" },
"linkedin": { "enabled": true, "conversionRule": "12345678" },
"google_ads": { "enabled": true, "conversionAction": "customers/1234567890/conversionActions/987654321", "feedName": "Demo booked (Server)" },
"tiktok": { "enabled": true, "event": "Contact" }
},
"enabled": true,
"requireServerConfirmation": false
}Triggers
trigger.kind | Created when | Event id | Origin |
|---|---|---|---|
manual | only explicitly: REST POST …/conversions, server SDK, MCP conversions_mark, dashboard – never from the browser | yours (or generated) | server / mcp / dashboard |
beacon | the browser conversion beacon POST /v1/cb (x3.conversion(), reportBooking()) – and explicitly like manual. The beacon is refused (404) for every other kind | the page's (shared with the pixel) | web |
event (+ optional props that must match) | the browser or server sends that event | <pageview id>:<n> | web |
goal | a session reaches the goal for the first time | goal:<session>:<key> | web |
lead (+ optional form) | a lead is created by identify() or POST …/leads | lead:<lead id> | web / server |
Automatic event ids are deterministic, so a retried batch never creates a second conversion.
Source
source is stored on every row and is a filter in reports. Values: quiz, booking,
whatsapp_manual, manual, event, goal, lead, api. The CPI preset uses quiz, booking and whatsapp_manual so historical reports
stay comparable.
Platform mapping
| Platform | Field | Where to find it |
|---|---|---|
| Meta | eventName – a standard event (Lead, Schedule, Contact, CompleteRegistration, Purchase, …) or a custom name | use the same name as your browser pixel for deduplication |
conversionRule – numeric id or urn:lla:llaPartnerConversion:<id> | Campaign Manager → Conversion tracking → rule details | |
| Google Ads | conversionAction (API) and/or feedName (CSV feed: the action's exact name) | Goals → Conversions → action (ctId in the URL) |
| TikTok | event – SubmitForm, Contact, CompleteRegistration, Lead … | Events Manager of the pixel |
A platform without mapping, or with enabled: false, gets status not_configured for this
definition – no error.
Requiring server confirmation
Public-key traffic can be forged. For definitions whose uploads influence bidding, set
requireServerConfirmation: true: web-triggered rows are stored as held and dispatched only when
your server confirms them – either conversions.create with the **same eventId** or
PATCH …/conversions/{id}/status {"status":"pending"}. Held rows expire after 7 days
(skipped).
Independent of this flag, web-originated conversions always pass the abuse guards: the session must
exist with at least one pageview and engagement, it must not be test traffic, at most one conversion
per session and definition, and at most settings.conversions.webDailyCap (default 500) per project
and day.
Typical setups
| Site | Definition | Trigger |
|---|---|---|
| Lead-gen with a quiz | quiz_lead | lead with form: "quiz" (your server calls leads.create with conversion) |
| Calendar booking | demo_booked | event booking (SDK booking plugin) or the /v1/cb beacon |
| WhatsApp / phone | whatsapp_contact | manual – confirmed via MCP conversions_mark with a time window |
| Newsletter | newsletter | goal newsletter_signup |
| Form via SDK forms plugin | contact_form | event form_submit with props: {"form": "contact"} |