On this page
Guides / Conversions for Meta and Google Ads

Conversions for Meta and Google Ads

Tell Meta and Google Ads which purchases, appointments and leads came from your ads, through the gate that decides what qualifies.

Updated View .md

When an ad brings in someone who ends up buying, booking or leaving their details, the ad platform needs to know in order to optimize. With met.conversions you report that fact from your system —the one that knows the payment came in— and Met carries it to Meta (Conversions API) and to Google Ads.

You do not emit directly. Everything you report goes through the conversion gate, the same one the conversions proposed by the Met and by flows go through. The gate checks that there is an ad behind it, that the event is on the business's list and that the fact is backed up, and it tells you what it decided. That is what keeps a buggy integration from inflating campaign results.

There are two paths:

MethodWhat forIdentified by
conversions.report()A conversion by a contact who came in through a WhatsApp, Messenger or Instagram ad.contact_id
conversions.reportWeb()The server-side mirror of an event from your site's Pixel.The Pixel's event_id and the visitor's cookies or details

Before you start

A contact's conversion

const r = await met.conversions.report({
  contact_id: 4821,
  event_name: 'Purchase',
  value: 250000,
  currency: 'COP',
  bucket: 'pedido-10293',
});

if (r.decision !== 'accepted') console.log('Not sent:', r.decision, r.reason);
r = met.conversions.report(
    contact_id=4821,
    event_name="Purchase",
    value=250000,
    currency="COP",
    bucket="pedido-10293",
)
if r["decision"] != "accepted":
    print("Not sent:", r["decision"], r.get("reason"))
curl -X POST https://api.met.meteor.com.co/api/v1/conversions \
  -H "Authorization: Bearer $METEOR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"contact_id":4821,"event_name":"Purchase","value":250000,"currency":"COP","bucket":"pedido-10293"}'
FieldWhat it is
contact_idThe CRM contact (see CRM and contacts). It has to have come in through an ad: otherwise it comes out no_attribution.
event_nameAn event on the business's list. For WhatsApp, Meta asks for messaging names: Purchase, LeadSubmitted, InitiateCheckout… not the web Pixel ones (Lead, Contact).
value, currencyValue and three-letter ISO 4217 currency (COP, USD). A purchase requires them.
evidenceWhat you are basing it on, in one sentence ("paid invoice 10293"). Almost every event requires it.
bucketWhat makes the conversion unique: the order id, the appointment id. Without it, the unit is the contact: the same contact only converts once per event.

What the gate requires

EventFor it to go out
Purchasevalue greater than zero and a valid currency.
LeadSubmitted, InitiateCheckout, AddToCart, Schedule, ReviewProvided, QualifiedLeadevidence.
Any other event on the listevidence.

On top of that, a contact does not accept more than 10 conversions in 24 hours (the default cap): it is the brake for a flow stuck in a loop.

A web conversion (Pixel)

If your site fires the Pixel in the browser, also report it from your server with the same event_id: Meta merges the two and does not count it twice.

// In the browser: fbq('track', 'Purchase', { value: 250000, currency: 'COP' }, { eventID: 'ord-10293' });
const r = await met.conversions.reportWeb({
  event_name: 'Purchase',
  event_id: 'ord-10293',
  fbp: req.cookies._fbp,
  fbc: req.cookies._fbc,
  email: customer.email,
  event_source_url: 'https://mystore.co/thanks',
  client_ip_address: req.ip,
  client_user_agent: req.headers['user-agent'],
  value: 250000,
  currency: 'COP',
});
r = met.conversions.report_web(
    event_name="Purchase",
    event_id="ord-10293",
    fbp=request.cookies.get("_fbp"),
    email=customer_email,
    client_ip_address=visitor_ip,
    client_user_agent=visitor_user_agent,
    value=250000,
    currency="COP",
)
curl -X POST https://api.met.meteor.com.co/api/v1/conversions/web \
  -H "Authorization: Bearer $METEOR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"event_name":"Purchase","event_id":"ord-10293","fbp":"fb.1.1730000000.123","gclid":"Cj0KCQ…","value":250000,"currency":"COP"}'

What it returns

{ "decision": "discarded", "reason": "uncorroborated" }
decisionWhat happened
acceptedIt passed the gate and is on its way to the platform. eventId is the key it travels with.
pending_corroborationIt is waiting for a confirmation from the CRM. It does not happen through the API —your system is the source of the fact—: it happens to a purchase or a qualified lead proposed by the Met or a flow.
duplicateAn identical one already went out: same contact, event and bucket, or the same event_id on the web. It is not sent twice.
discardedIt does not go out. reason says why.
reasonWhat to do
integration_inactiveThe business does not have conversions turned on.
no_attributionThe contact did not come in through an ad (or their click is no longer usable).
not_in_taxonomyevent_name is not on the business's list.
uncorroboratedevidence was missing, or value and currency on a purchase.
rate_limitedThe contact already had 10 accepted conversions in 24 hours.
missing_wabaThe contact is on WhatsApp and the WhatsApp Business account is missing from the configuration.
no_match_keyA web conversion with no way of recognizing the visitor.

Hearing about delivery

accepted says it left the gate; delivery to Meta comes afterwards. Subscribe to the events (scope conversions:read; see Webhooks):

EventWhen
conversion.sentMeta received the conversion. Carries event_id, event_name and Meta's fbtrace_id.
conversion.discardedThe gate discarded a conversion, whether you, the Met or a flow proposed it. Carries reason.

Common errors

CodeWhat happened
400 validation_errorcontact_id or event_name is missing (event_id on the web), or a field exceeds its maximum length.
403 missing_scopeThe key does not carry conversions:write.
403 test_mode_restrictedA met_test_ key does not report conversions.