Docs

Conversions overview

The concept page Server-side conversions explains what 3x does. This section explains how to set it up and operate it.

Setup in four steps

  1. Destinations – one per platform, with credentials, mode and transport: Meta, LinkedIn, Google Ads, TikTok.
  2. Definitions – what counts as a conversion and how it maps to each platform (Definitions).
  3. Recording – automatically from events, goals or leads, or explicitly from your server, the MCP server or the dashboard.
  4. Test – dry_run → test → live (Test modes).

Destinations

GET /v1/projects/{project}/destinations lists the four providers; PUT …/destinations/{provider} updates one (scope project:admin):

{
  "enabled": true,
  "mode": "test",
  "transport": "direct",
  "settings": { "pixelId": "1234567890123456", "apiVersion": "v26.0", "testEventCode": "TEST12345" },
  "secrets": { "accessToken": "EAAB…" }
}
FieldValues
modelive (send for real), test (platform test endpoints/validate-only), dry_run (build payloads, log a PII-free summary, send nothing)
transportdirect (3x calls the platform API, default), composio (through the project's Composio ad connection), feed (Google Ads CSV feed only)
secretsstored encrypted (AES-256-GCM); responses only contain secretsSet and masked secretsHint. Send null to remove a secret

POST …/destinations/{provider}/test sends a synthetic test event in test mode and reports the platform's answer.

The deployment caps every destination: X3_CONVERSIONS_MODE (dry_run by default outside X3_ENV=production) and the kill switch X3_CONVERSIONS_DISABLED=1.

Composio transport

ProviderThrough ComposioNotes
MetaMETAADS_SEND_CONVERSION_EVENTSneeds a Meta connection whose token can access the pixel
Google AdsuploadClickConversions via the Composio proxyuses the Google connection; loginCustomerId for MCC access
LinkedIn/rest/conversionEvents via the Composio proxyneeds rw_conversions on the LinkedIn auth config
TikTok–direct only

A provider is either direct or Composio, never both. Select the connection with adConnectionId.

Recording from your server

import { createX3Server, requestContext } from "@3x-engine/sdk/server";

const x3 = createX3Server({ apiUrl: process.env.X3_API_URL!, apiKey: process.env.X3_SECRET_KEY! });

await x3.conversions.create({
  definition: "demo_booked",
  sessionId,                 // from getIds() in the browser, sent with your form
  eventId: `booking:${bookingId}`,
  email, phone, firstName, lastName,
  value: 500, currency: "EUR",
  ...requestContext(request), // IP, user agent, _fbp/_fbc/_ttp (after consent)
});

See Server helper for request context (IP, user agent, _fbp/_fbc) and the combined leads.create({ conversion }) call.

Watching the pipeline

  • Dashboard → Conversions: last conversions with per-platform status, retry button, filters.
  • GET /v1/projects/{project}/conversions?provider=meta&provider_status=failed (scope conversions:read).
  • MCP conversions_list, conversions_mark, conversions_retry, conversions_update_status, conversions_definitions_list.
  • Troubleshooting lists every status and error with its fix.