Send purchases to your ad platforms
Send purchases, renewals, sign-ups and refunds from our servers to Google Analytics 4, Google Ads, Meta, TikTok, Microsoft Ads, Reddit and X.
In the dashboard
A server-side conversion is a sale that we report to an ad platform from our servers, after the invoice is paid. The browser tags report a purchase only when the buyer's browser stays open, allows the tag and is not blocked. Reporting from the server as well counts the sales that the browser missed, and it counts refunds, which no browser sees.
You give each platform the ID and secret that let us report to your account. We then send what happens on your storefront: each paid invoice, each new account and each refund. We send nothing for a platform you leave off.
Before you begin
Section titled Before you begin- You need the Owner or Admin role in the organization. Members with any other role cannot read or change these settings, because they hold platform secrets.
- You need an account on each platform you want to use, with its pixel or data source already made, and an access token or API secret for it. Set up each platform says where to find them.
- Your storefront must be one that Coritan serves, so the visitor's tracking cookies reach us with the order. A storefront you build yourself on the Storefront API needs to forward them, as How customers and orders are attributed describes.
What is sent
Section titled What is sentOne event goes to each platform that is on, for each of these things that happen:
| Event | When it is sent | Sent as |
|---|---|---|
purchase |
An invoice is paid and a service on it was still waiting for that payment: the buyer's first purchase of that service. | Google Analytics 4 purchase, Google Ads (the purchase label), Meta Purchase, TikTok CompletePayment, Reddit Purchase, X (the purchase event). |
upgrade |
A paid invoice charges for a plan change, an add-on or a one-time line on a service that is already active. | The same as a purchase. |
renewal |
A paid invoice bills a service that is already active for another period. Off until you turn on send_renewals for the platform. |
Google Analytics 4 renewal, Google Ads (the renewal label), Meta, TikTok and Reddit as a custom event named Renewal, X (the renewal event). |
free_server |
An order with nothing to pay, such as a free server, is settled. It is a lead and never a purchase. | Google Analytics 4 generate_lead, Google Ads (the lead label), Meta Lead, TikTok CompleteRegistration, Reddit Lead, X (the lead event). |
sign_up |
A customer account is made on your storefront. | Google Analytics 4 sign_up, Google Ads (the sign_up label), Meta and TikTok CompleteRegistration, Reddit SignUp, X (the sign_up event). |
refund |
A refund of a sale is booked on the invoice, for the amount that went back. | Google Analytics 4 refund only. |
chargeback |
A chargeback on a sale is lost and its money taken back. | Google Analytics 4 refund only. |
Nothing is sent for an invoice that reactivates a suspended service, for an invoice with nothing to pay on a service that is already active, or for an invoice with no service on it. An invoice paid before you turned a platform on is never sent to it. A refund or a lost chargeback is sent only for an invoice that was a purchase, an upgrade or a renewal when it was paid. A refund that you give as account credit is not sent, because no money went back to the buyer.
Every event for a purchase carries the same ID, purchase: followed by the invoice number, such as purchase:INV-000042. The browser tag sends the same ID, so a platform that receives the sale from both counts it once. Google Analytics 4 and Google Ads get the invoice number itself as the transaction ID. A renewal's ID starts with renewal:, a free server's with lead: and a sign-up's with sign_up:.
Meta, TikTok, Reddit and X have no event for a refund, and Google Ads can take one back only through its own API, which we do not use. Each of those platforms gets a delivery marked skipped that says so, so you can see why nothing went.
What the buyer allowed
Section titled What the buyer allowedWe copy the visitor's cookie choice onto the order when it is placed, and what we send depends on it. See Consent and privacy for how the choice is made.
- The buyer allowed marketing
- We send what the platform uses to match the sale to the ad: the SHA-256 hash of the email address, the phone number, the name and the address, the SHA-256 hash of the customer ID, the click ID the visit arrived with, the Meta browser IDs (
fbpandfbc), and the IP address and browser name of the order. Reddit gets the IP address hashed. - The buyer denied marketing, or we cannot tell what they chose
- We send nothing that names the buyer: no email, phone, name, address, customer ID, click ID, cookie, IP address or browser name. Meta, TikTok, Reddit and X are not sent the sale at all. Google Analytics 4 and Google Ads receive the count, the value and the invoice number only, and Google Analytics 4 sends no user ID.
- The buyer denied analytics
- Google Analytics 4 is not sent anything for that sale, and its client and session IDs are left out.
An invoice that did not begin as a storefront order has no choice on file: an invoice your team made, or a renewal. It uses the choice the customer made when they signed up, and when there is none, everything is denied. Nothing is ever sent as a plain email address or phone number. Meta, TikTok and X are sent the hashes they ask for, and Google Ads receives the hashed email only with marketing allowed.
Set it up in your dashboard
Section titled Set it up in your dashboardOwners and admins turn each platform on in the dashboard. Your team can do the same in the staff console, as Team and settings describes.
You need the Owner or Admin role, because the page holds platform secrets. A member with another role does not see the page, and its address opens Overview. You also need, from each platform's own site, the ID and the secret that Set up each platform names.
- In the dashboard, open the organization, then Settings, then Conversions.
- Find the platform's card. It names the platform and shows a badge: On, Test mode, Off, or Failing when the last event we sent it was refused. Under the name, Last event sent says what we last sent and when, and Last 30 days says how many of your first purchases from the last 30 days we sent it.
- Fill in the platform's settings, such as "Measurement ID" for Google Analytics 4 or "Pixel ID" for Meta. Each hint says where to find the value. Google Ads asks for "Conversion labels" and X for "Event IDs", one for each kind of event. Set at least "Purchase".
- Type the secret into its field, such as "API secret" or "Access token". X takes four values: "Consumer key", "Consumer secret", "Access token" and "Access token secret". Google Ads and Microsoft Ads take no secret. After you save, the card shows Saved where the field was, because we never show a secret again. Select Replace to type a new one, or Clear to remove it.
- Turn on Send events. Turn on "Send renewals" to send each paid renewal as its own conversion action. Turn on Test mode to mark every event as a test while you check the setup. Google Ads, X and Microsoft Ads have no test mode, so their cards have no such switch.
- Select Save changes. Each card saves alone, so what you typed in another card stays unsaved until you save that card. A setting that does not fit, or a platform turned on without what it needs, shows the API's sentence under the input it belongs to, and focus moves there.
- For a platform with a test mode, select Send test event. It sends one made-up purchase with the settings you saved, so it is off while a card has unsaved changes. Meta and TikTok need their "Test event code" first. The card says whether the platform accepted the event. A test is not counted in Last 30 days.
When it works, the page says "Meta Conversions API turned on." or "Meta Conversions API saved.", the badge reads On and the secret reads Saved. After the next paid invoice, Last event sent shows the purchase as Sent. A Skipped event carries the reason, such as a buyer who did not allow marketing.
For Microsoft Ads, turn on Send events and select Save changes. The page then shows Copy the file address now with the whole address of your file. Copy it into a schedule in Microsoft Advertising, as Send purchases to Microsoft Advertising describes. We show the address whole only that once. Later it shows with the token hidden, next to Last fetch, which says when Microsoft Advertising last read the file. If the address leaks, select Replace address…, type replace and select Replace address. The old address stops working at once, and the page shows the new one whole.
Set up each platform
Section titled Set up each platformEach platform has a kind, settings that are not secret (config) and, except for Google Ads and Microsoft Ads, one secret. The secret is write only: we seal it, never show it again, and the API answers only secret_set.
| Platform | kind |
config |
Secret |
|---|---|---|---|
| Google Analytics 4 | ga4 |
measurement_id |
The Measurement Protocol API secret: in Google Analytics, open Admin, Data streams, your web stream, then Measurement Protocol API secrets. |
| Google Ads | google_ads |
conversion_id and labels |
None. In Google Ads, open Goals, Conversions, then each conversion action and its tag setup: the ID starts with AW- and the label follows the slash. Make one conversion action for each of purchase, renewal, sign_up and lead that you want. |
| Meta | meta_capi |
pixel_id, test_event_code |
The access token: in Meta Events Manager, open your data source, then Settings and Conversions API. The test event code is on its Test events tab. |
| TikTok | tiktok_events |
pixel_code, test_event_code |
The access token: in TikTok Events Manager, open your web events, then Settings and Events API. The test event code is on its Test events view. |
reddit_ads |
pixel_id |
The conversion access token: in Reddit Ads, open Events Manager and your data source, then Conversions API. pixel_id is the Pixel ID there, not the ID of the ad account. |
|
| X | x_ads |
pixel_id and events |
Four OAuth values as one object: consumer_key, consumer_secret, access_token and access_token_secret, from an app in the X developer portal with Ads API access. events names the X event ID, which starts with tw-, for each of purchase, renewal, sign_up and lead. |
| Microsoft Ads | microsoft_ads |
conversion_name, lookback_days, browser_grace_minutes, email_only_rows |
None. We make an address for the file Microsoft Advertising imports. See Send purchases to Microsoft Advertising. |
Every platform also takes send_renewals, true or false, which is false until you set it.
An ID is checked as the browser tags check it, so a value that the tags accept is accepted here, and an ID you type in lower case where the platform uses capitals is saved in capitals. A Google Ads labels and an X events object replace the whole map each time. You turn a platform on with enabled: true once its settings and secret are saved.
curl -X PUT "https://api.coritan.com/api/v1/orgs/acme/conversions/ga4" \
-H "Authorization: Bearer $CORITAN_TOKEN" \
-H "Content-Type: application/json" \
-d '{"enabled": true, "secret": "AbCdEfGhIjKlMnOpQrStUv", "config": {"measurement_id": "G-ABC123DEF4"}}'
curl -X PUT "https://api.coritan.com/api/v1/orgs/acme/conversions/google_ads" \
-H "Authorization: Bearer $CORITAN_TOKEN" \
-H "Content-Type: application/json" \
-d '{"enabled": true, "config": {"conversion_id": "AW-123456789", "labels": {"purchase": "AbCdEfGhIjKlMn", "lead": "OpQrStUvWxYz01"}}}'
curl -X PUT "https://api.coritan.com/api/v1/orgs/acme/conversions/x_ads" \
-H "Authorization: Bearer $CORITAN_TOKEN" \
-H "Content-Type: application/json" \
-d '{"enabled": true, "config": {"pixel_id": "o1abc", "events": {"purchase": "tw-o1abc-o2def"}}, "secret": {"consumer_key": "...", "consumer_secret": "...", "access_token": "...", "access_token_secret": "..."}}'
The answer holds the saved settings and secret_set, and changed lists what this call changed. Send only the keys you want to change: a config key replaces the saved one, and null or an empty string removes it. An empty secret clears it. Saving what is already saved changes nothing and writes no audit entry. A value that does not fit answers 422 with detail, the sentence to show, and field, the input it belongs to:
{ "detail": "Meta pixel id must be 8 to 20 digits", "field": "config.pixel_id" }
Check that it works
Section titled Check that it works- Send a test event with
POST /conversions/{kind}/test. It sends one made-up purchase of one currency unit for a product calledTest product, with nothing about a person in it. Meta and TikTok send their test event code, Google Analytics 4 sends to its validation endpoint and Reddit sends its test flag, so nothing reaches live reporting. Settest_event_codefor Meta and TikTok first. - Read the answer:
okistruewhen the platform accepted the event, andhttp_statusanderrorcarry what it said when it did not. A test is not logged as a delivery and does not count toward coverage. - Look for the event in the platform: Meta and TikTok in their test events, Google Analytics 4 in DebugView.
- After the next real purchase, read
GET /conversions/deliveries. A purchase that went out has a delivery withstatussent.
You can turn on test_mode for a platform to send every real event as a test. Google Ads and X have no test mode, so a test would count as a real sale: their test call answers 422, and while either is in test mode nothing is sent to it. Microsoft Ads takes no events, so its test call answers 422 too.
You can send at most ten test events an hour for each platform, and the eleventh answers 429.
Read what was sent
Section titled Read what was sentGET /conversions lists the seven platforms, whether or not you set them up. Each entry has these parts besides its settings:
last_delivery- The newest event the platform was sent, with its
event,status,http_status,errorand the timeat, ornull. coverage- How many of your first purchases the platform was sent.
ordersis the invoices paid in the last 30 days that were a first purchase,sentis how many of them the platform'spurchasewas sent for, andrateissentoverorders, ornullwith no orders. A free server, a renewal and an upgrade are in neither number.
GET /conversions/deliveries lists every event, newest first. Filter it with kind, status (sent, failed or skipped) and invoice_number, which also finds the refunds and chargebacks booked on that invoice. limit takes 1 to 200 (50 by default) and offset pages through. Each row names its invoice, the event and the status:
sent- The platform answered with a success.
skipped- We chose not to send, and
errorsays why. Common reasons:Renewals are off for this integration.,The buyer did not allow marketing, so nothing is sent to Meta Conversions API.,The buyer did not allow analytics, so nothing is sent to Google Analytics.,No Google Ads conversion label is set for lead.,No X event ID is set for lead.,X needs a click ID or an email address to match a conversion, and this buyer gave none., andMeta Conversions API has no refund event. failed- The platform refused the event, or did not answer.
http_statusanderrorhold what it said, with your secret taken out. A timeout, a connection failure,408,429and any5xxare tried again, three attempts in all, and the last row endsGave up after 3 attempts.Any other answer is final at once.
A delivery that is sent or skipped is final, so a sale is never reported to a platform twice by us.
Send purchases to Microsoft Advertising
Section titled Send purchases to Microsoft AdvertisingMicrosoft Advertising does not take events. It fetches a file of offline conversions on a schedule, and we serve the file.
- In Microsoft Advertising, make an offline conversion goal and note its name.
- Turn Microsoft Ads on with
PUT /conversions/microsoft_adsand{"enabled": true, "config": {"conversion_name": "Offline Purchase"}}. The first time, the answer'sfeed_urlholds the whole address of your file, ending in atoken. Copy it now: later answers show it with the token hidden infeed_url_masked. - In Microsoft Advertising, open Conversions, Offline conversions, then Schedules, and add that address as the file to import.
The file lists a purchase when its invoice was paid in the last lookback_days (30 unless set), at least browser_grace_minutes ago (120 unless set) and after you turned Microsoft Ads on, and when the buyer allowed marketing. It lists first purchases and upgrades, and renewals when send_renewals is on. Each row holds the msclkid the buyer arrived with, your conversion_name, the time paid, the total, the currency and the hashed email. A buyer with no click ID is listed by the email alone when email_only_rows is on (the default) and the visit came from Microsoft. In test mode the file lists nothing.
The grace period gives the buyer's browser the first chance to report the sale with the UET tag from your tags. When the invoice shows paid, your storefront calls POST /storefront/conversions/microsoft/claim with the customer's token and {"invoice_id": 42}. The answer {"fire": true} comes once for each invoice, and the browser then fires the UET event and the file leaves that invoice out. Every other answer is {"fire": false}: the file already listed it, the invoice is unpaid or not a sale, or Microsoft Ads is off or in test mode. At most 10 claims an hour for one invoice and 600 an hour from one IP address.
Microsoft Advertising fetches the file with no sign-in: the token in the address is the credential. A wrong token, an organization with the integration off and an unknown organization all answer 404. Replace a lost or leaked address with POST /conversions/microsoft_ads/rotate-feed-token. The answer holds the new address, and the old one answers 404 from then on. Purchases the file already listed stay listed. Rotating before you first turned Microsoft Ads on answers 409.
Result
Section titled ResultAfter a customer pays, we queue the purchase in the same transaction that records the payment and send it from a background job. GET /conversions/deliveries then lists one row for each platform you turned on, with its status. The invoice number is the same in your platform's reports and in your invoices.
Troubleshooting
Section titled Troubleshooting- A delivery is
skippedwithThe buyer did not allow marketing - Meta, TikTok, Reddit and X are sent a sale only when the buyer allowed marketing. Google Analytics 4 and Google Ads still receive the count. The browser tags follow the same choice.
- A delivery is
failedwithHTTP 400orHTTP 401 - The platform refused the ID or the secret. Check the ID against the platform, make a new access token and save it again. The failure is final for that sale.
- Meta or TikTok answers a test with
422andTest mode sends a test event code - Set
config.test_event_codefrom the platform's test events page, then test again. - A Google Ads purchase shows no conversion
- We send Google Ads the click ID only when the buyer allowed marketing and the visit had one. Without it the request carries the invoice number, the value and the currency alone. Check that the
purchaselabel belongs to the conversion action you read, and read the delivery'sstatusfirst. - The same sale counts twice
- The browser tag and the server send the same event ID, so Meta, TikTok, Reddit and X count it once. For Google Analytics 4 and Google Ads, make sure the tag sends the invoice number as the transaction ID, which the storefront's tags do.
- Microsoft Advertising says the file is not found
- The address needs its token, and a rotated address replaces the old one. Turn Microsoft Ads on, copy
feed_urlfrom that answer, or rotate to get a new one. coverage.rateis lower than you expect- Count only first purchases paid in the last 30 days. A purchase whose buyer denied marketing is
skippedfor the platforms that need it, and a platform you turned on after the sale never receives it.
With the API
Section titled With the APIThe staff console's routes under /api/v1/orgs/{org_slug}/staff/marketing/conversions answer the same, for the Admin and Owner roles, and platform staff have the same routes for any organization in the admin console. All of them need an access token, sent as Authorization: Bearer $CORITAN_TOKEN.
| Operation | What it does |
|---|---|
GET /conversions |
The seven platforms with their settings, secret_set, last_delivery and coverage. |
PUT /conversions/{kind} |
Turn a platform on or off, set test_mode, change its config, set or clear its secret. |
POST /conversions/{kind}/test |
Send one made-up purchase in test mode. |
GET /conversions/deliveries |
The delivery log, filtered by kind, status and invoice_number. |
POST /conversions/microsoft_ads/rotate-feed-token |
A new address for the Microsoft Ads file. |
GET /conversions/microsoft/feed |
The file Microsoft Advertising fetches. No sign-in, a token query. |
POST /storefront/conversions/microsoft/claim |
Whether the thank-you page should fire the UET event. The customer's token. |
Every change is recorded in the audit log as conversions.updated (the settings that changed, never a secret), conversions.test_sent or conversions.feed_rotated.
Related
Section titled RelatedNext steps
Section titled Next steps- Add the browser tags for the same platforms, so the browser and the server count each sale once.
- Read how customers and orders are attributed to see which campaigns bring buyers.
- Follow your invoices to match a delivery to the invoice it came from.
API operations on this page
| Method | Path | What it does |
|---|---|---|
GET | /api/v1/orgs/{org_slug}/conversions | List the ad platforms purchases are sent to, and how each is doing |
GET | /api/v1/orgs/{org_slug}/conversions/deliveries | Read what each platform was sent, and why anything was not |
PUT | /api/v1/orgs/{org_slug}/conversions/{kind} | Turn an ad platform on or off and change its settings |
POST | /api/v1/orgs/{org_slug}/conversions/{kind}/test | Send a made-up purchase to an ad platform in test mode |
POST | /api/v1/orgs/{org_slug}/conversions/{kind}/rotate-feed-token | Replace the token in the Microsoft Ads file address |
GET | /api/v1/orgs/{org_slug}/conversions/microsoft/feed | Fetch the offline conversions file Microsoft Advertising imports |
POST | /api/v1/orgs/{org_slug}/storefront/conversions/microsoft/claim | Ask whether the thank-you page should report a purchase to Microsoft Ads |
GET | /api/v1/orgs/{org_slug}/staff/marketing/conversions | List the ad platforms purchases are sent to, and how each is doing |
GET | /api/v1/orgs/{org_slug}/staff/marketing/conversions/deliveries | Read what each platform was sent, and why anything was not |
PUT | /api/v1/orgs/{org_slug}/staff/marketing/conversions/{kind} | Turn an ad platform on or off and change its settings |
POST | /api/v1/orgs/{org_slug}/staff/marketing/conversions/{kind}/test | Send a made-up purchase to an ad platform in test mode |
POST | /api/v1/orgs/{org_slug}/staff/marketing/conversions/{kind}/rotate-feed-token | Replace the token in the Microsoft Ads file address |