Meta Conversions API
On this page
Server-side conversions for Facebook and Instagram ads, deduplicated against the Meta pixel by event id.
Verified against the Meta documentation on 2026-09-03: Using the API, Server Event, Customer Information Parameters, Custom Data, Deduplication.
Prerequisites#
- A Meta Business account with an ad account.
- A dataset (formerly "pixel") in Events Manager.
- Permission to generate a Conversions API access token for that dataset.
What to collect#
| Value | Where to find it | Stored as |
|---|---|---|
| Dataset (pixel) ID | Events Manager → Data Sources → your dataset → Settings. A 15–16 digit number, also shown in the URL. | Config |
| Conversions API access token | Events Manager → your dataset → Settings → Conversions API → Generate access token. Copy it once; Meta does not show it again. | Vault |
| Test event code (optional) | Events Manager → your dataset → Test events tab. A short code like TEST12345. | Config |
Also available:
- Graph API version — defaults to
v26.0. Conversions API versions are supported for at least two years, longer than the rest of the Graph API, so there is rarely a reason to change this. Bump it when you want a newer field. - Action source —
websiteunless the conversion genuinely happened somewhere else (app,phone_call,physical_store, …).
What SaaS Pro Max sends#
POST https://graph.facebook.com/v26.0/{datasetId}/events?access_token=…
Content-Type: application/json
{
"data": [{
"event_name": "Purchase",
"event_time": 1786… ,
"event_id": "<the SaaS Pro Max event id>",
"action_source": "website",
"event_source_url": "https://example.com/checkout",
"user_data": {
"em": "<sha256 of the lowercased, trimmed email>",
"ph": "<sha256 of the digits, country code included, no leading +>",
"fn": "<sha256>", "ln": "<sha256>",
"external_id": "<sha256 of the distinct id>",
"ct": "<sha256 of the lowercased city with punctuation removed>",
"st": "<sha256>", "country": "<sha256 of the ISO alpha-2 code>",
"fbc": "fb.1.<ms>.<fbclid>",
"fbp": "<the _fbp cookie>",
"client_user_agent": "…"
},
"custom_data": {
"value": 49, "currency": "USD",
"contents": [{ "id": "SKU-1", "quantity": 2, "item_price": 20 }],
"content_ids": ["SKU-1"], "content_type": "product",
"num_items": 2, "order_id": "…"
}
}]
}
Notes that matter:
- Everything in
user_datais SHA-256 hashed exceptfbc,fbpandclient_user_agent. Meta rejects a hashed click or browser identifier. - The phone is hashed as digits with the country code and no leading
+(16505551212). This is the opposite of TikTok, which wants the+. The two adapters therefore produce different hashes from the same number, by design. - The email is hashed as typed after case folding. Meta does not fold Gmail dots or plus-addressing — Google Ads does, so those hashes differ too.
fbcis the_fbccookie when the SDK captured one, and is otherwise rebuilt from the capturedfbclidasfb.1.<event time in ms>.<fbclid>.client_ip_addressis not sent. SaaS Pro Max hashes IPs at ingest and never stores them, so there is nothing truthful to put there.
Standard event names#
Use these in the mapping editor's "Meta standard event" column, spelled exactly:
AddPaymentInfo, AddToCart, AddToWishlist, CompleteRegistration,
Contact, CustomizeProduct, Donate, FindLocation, InitiateCheckout,
Lead, Purchase, Schedule, Search, StartTrial, SubmitApplication,
Subscribe, ViewContent.
Any other name is forwarded as a custom event: it works for reporting and audiences, but not for conversion optimisation.
Verifying#
- Add your test event code to the destination configuration.
- Open Events Manager → your dataset → Test events.
- Press Send test event on the destination page in SaaS Pro Max.
- The event appears in the Test events tab within a few seconds, labelled "Server".
- Check the Event Match Quality score on the dataset overview after real traffic has flowed for a day.
Remove the test event code afterwards. Meta stores events sent with one and uses them for targeting and measurement, so leaving it in place is not harmless — it just makes them harder to find.
Deduplication with the pixel#
Meta keeps the first copy of a given (event_id, event_name) pair for 48
hours. Send the SaaS Pro Max event id as the pixel's eventID and the same
event name in both places:
fbq("track", "Purchase", { value: 49, currency: "USD" }, { eventID: spmEventId });
If you cannot wire that up, use one source only.
Consent and the ads view#
If the pixel and this destination only fire after a visitor accepts
marketing cookies, Meta receives fewer conversions than your site records and
optimizes delivery on that smaller signal. The
Meta ads view flags it: when Meta reports no
results for the ad set's optimization event while your own analytics recorded
sign-ups from Meta visitors, it raises a Meta reports no … issue. Check the
consent flow and that this destination forwards the same event the ad set
optimizes for (for example CompleteRegistration or StartTrial).
Limitations#
- No
client_ip_addressand, unless a server SDK supplies$user_agent, noclient_user_agent. Expect a slightly lower match quality than a vendor SDK running inside your request handler. event_timemay be at most 7 days in the past. An older conversion is rejected — for a long sales cycle, forward the event when it happens rather than backfilling.- One event per request. Meta accepts up to 1,000, but batching would tie unrelated conversions' fates together for no gain at SaaS Pro Max's volumes.
- A rejected payload is not retried: it would be rejected identically.