Integrations

Sales webhook

One private URL for every sale or conversion that happens off your page. A checkout like Funnelish, a deal won in your CRM, a sale in your own app, or a Zapier step posts here, and DataCops sends it to your ad platforms with the original ad click.

What it is

Your tracking script sees what happens on your pages. It cannot see a sale that is paid on another company's servers, or a deal that closes days later in your CRM. The sales webhook is the door for those: the tool that knows about the sale tells DataCops, and DataCops delivers it as a real conversion.

Every sale goes through the same checks as the rest of DataCops: consent, the bot and fraud verdict, and one sale counted once per ad platform. It arrives as its own event, like SignupCops, so you can see it, pause it or remap it in TagCops and CAPI Flow.

Get your URL

In the DataCops dashboard open Configuration → Sales Sources → Your webhook and copy the URL. It is private, so treat it like a password and never put it in front-end code. If it leaks, make a new one on the same page.

Stuck? Press Copy for AI agent on that page. It copies this whole guide with your URL already filled in, ready to paste into ChatGPT or your automation tool's AI.

What to send

Funnelish needs nothing: DataCops reads its order webhook as it is. Anything else posts one flat JSON object per sale. Only event and email or phone are required. Every other field is the same one SignupCops' identifyUser() takes, and the more you send, the better the match on your ad platforms. camelCase names (firstName, dateOfBirth, externalId) work too. * Send email or phone, at least one.

FieldNeededWhat it is
eventRequiredStandard names are sent automatically: Purchase, Lead, CompleteRegistration, Schedule, Subscribe, StartTrial, Contact, SubmitApplication, AddToCart, InitiateCheckout, ViewContent, Search, CustomizeProduct, Donate, FindLocation. Your own name, like "Deal Won", is mapped once in TagCops first.
emailRequired *The person. How the sale is matched to them and their ad click.
phoneRequired *With country code. * Send email or phone, at least one.
valueOptionalThe amount, as a number.
currencyOptional3-letter code. Default USD.
order_idOptionalYour own id. The same id twice counts once, so retries are safe.
testOptionaltrue shows the post in DataCops but never sends it to your ads.
first_nameOptionalPerson.
last_nameOptionalPerson.
date_of_birthOptionalYYYY-MM-DD.
genderOptionalm or f.
external_idOptionalYour own customer id.
emailsOptionalExtra email addresses, as a list.
phonesOptionalExtra phone numbers, as a list.
streetOptionalAddress.
cityOptionalAddress.
stateOptionalAddress.
zipOptionalAddress.
countryOptional2-letter code.
predicted_ltvOptionalExpected lifetime value, as a number.
content_nameOptionalProduct or plan name.
content_categoryOptionalProduct category.
content_idsOptionalProduct ids, as a list.
content_typeOptionalproduct or product_group.
num_itemsOptionalNumber of items, as a number.
gclid, wbraid, gbraidOptionalGoogle ad click ids you stored.
fbclid, fbc, fbpOptionalMeta click id and browser ids you stored.
ttclidOptionalTikTok ad click id.
li_fat_idOptionalLinkedIn ad click id.
lead_idOptionalMeta lead ad id.
subscription_idOptionalYour subscription id.
fb_login_idOptionalFacebook login id.
madidOptionalMobile advertiser id.
job_titleOptionalB2B.
company_nameOptionalB2B.
curl -X POST "YOUR_URL" \
  -H "Content-Type: application/json" \
  -d '{
    "event": "Purchase",
    "email": "[email protected]",
    "phone": "+15125550100",
    "value": 2000,
    "currency": "USD",
    "order_id": "deal-1042",
    "first_name": "Jane",
    "last_name": "Doe",
    "date_of_birth": "1990-04-02",
    "gender": "f",
    "street": "1 Congress Ave",
    "city": "Austin",
    "state": "TX",
    "zip": "73301",
    "country": "US",
    "external_id": "cust-5521",
    "predicted_ltv": 5000,
    "content_name": "Annual plan",
    "num_items": 1,
    "fbclid": "IwAR...",
    "gclid": "Cj0KCQ...",
    "test": false
  }'

Only event and email or phone are required. Leave out any field you do not have.

Set it up in your tool

ToolSteps
FunnelishAutomations, new automation, trigger On purchase, action Webhook, paste the URL, save. Nothing to map.
ZapierAdd a Webhooks by Zapier step, action POST, paste the URL, payload type json, then add event, email, value, currency and order_id as data.
MakeHTTP module, Make a request, method POST, body type Raw, content type JSON, body as in the example below.
n8nHTTP Request node, method POST, Send Body as JSON, the same fields.
HubSpot workflowAction Send a webhook, method POST, paste the URL, map event, email, the deal amount as value and the deal id as order_id.
Your own app or CRMOne POST with a JSON body, as in the example below.

Already holding leads until your CRM confirms them? The same URL also releases a held lead. See the qualification gate.

Where it shows up

  • TagCops and CAPI Flow: a Sales webhook row, sending as Purchase, appears as soon as the first sale arrives.
  • Events: each sale with where it was delivered.
  • Your webhook → Log: every post, in plain words.

Check it worked

Press Send a test on the Setup tab, or send a post with "test": true. It appears in the Log within seconds and is never sent to your ads. Each post shows as one of these:

In the LogMeaning
Sale sent to your adsDelivered, with the platforms it went to and whether the ad click was found.
Sale received, not sentArrived, but not sent, with the reason: no ad platform connected, no consent, or an event name that is not mapped yet.
Test order receivedA test, shown but never sent.
Same order again, counted onceA repeat of an order id we already have.
Could not read this postSomething was missing or wrong, with the exact reason, for example "Missing amount".
Was this page helpful?