Sending orders and refunds from your server
Ad platforms count sales with cookies; when most visitors decline cookies, Google Analytics and Google Ads see only a small part of the sales your ads bring. When your server sends orders to adall, adall counts every sale, decides with real revenue and profit, and uploads the sales that have consent to Google itself. This page lets your developer do the whole setup; it takes about half a day.
1. Get the key
In the panel, open Settings › Connections › Send orders straight to adall › Setup details for your developer and press Create key. You get a key (X-Adall-Key) and a secret; the secret is shown once.
- Put both in your server's environment variables (e.g.
ADALL_KEY,ADALL_SECRET). Not in code, not in the repository, not in an admin setting. - If the key leaks, revoke it in the same place and create a new one; requests with the old one are refused at once.
2. When to send what
- When a payment is final: one
orderevent. Not a cart or a payment attempt: when the money is collected. - When a card refund is made: one
refundevent; for a partial refund only the refunded amount. Also send refunds made in your payment provider's dashboard (e.g. Stripe'scharge.refundedwebhook). - Parts paid with gift cards, balance or points are not a sale;
valueis what the customer was actually charged.
3. Event fields
event_id(required, up to 128): the event's permanent id. Sent twice, it counts once; e.g.order-<order no>,refund-<refund id>.type(required):orderorrefund.occurred_at(required): when the payment or refund happened, ISO 8601, within the last 400 days.reference(required): your order number. A refund carries its order's number.value.amount_minorandvalue.currency(required): amount in minor units (699.00 =69900) and the three-letter uppercase currency.profit.amount_minor(optional, recommended): the order's profit in the same currency (sale − cost of goods). If you do not know the cost, leave it out; adall then decides with revenue.country: the order's country (billing or shipping, two letters). Country decisions use it.click_ids: ids of the click the visitor came from:gclid,gbraid,wbraid(Google),fbclid,fbc,fbp(Meta),msclkid,ttclid. Read them from the landing URL and keep them until the order.utm:source,medium,campaign,term,content. On Google campaigns adall builds,utm_campaignis the campaign id; adall puts the sale on its campaign with it. Like the click id, keep it with the order even without consent: it is not personal data. If most orders come without a campaign, adall cannot decide on its own count.customer.email_sha256: SHA-256 of the lowercased, trimmed e-mail.customer.external_id: your customer number. Plain e-mails or phone numbers are refused.consent: step 5 below.session.landing_url,session.first_touch_at: the first visit's address and time (optional).
4. Signature and request
POST https://live.adall.io/api/v1/events, body {"schema_version":1,"events":[…]}; up to 100 events per request.
X-Adall-Key: your key.X-Adall-Timestamp: current Unix seconds. Requests more than five minutes off are refused; keep your server clock right.X-Adall-Signature:sha256=+ hex HMAC-SHA256(secret,"{timestamp}.{body}"). The signed body must be the exact bytes you send: encode the JSON first, sign that text, send that text.
Ready code: Code examples.
5. Consent: if you do not know it, do not send it
adall uploads an order to Google or Meta only when consent.ad_user_data is granted. With no consent block, there is no consent: the order counts in adall's decisions but does not reach the platform, and the panel says so.
- At payment, store your cookie banner's (consent platform's) advertising/marketing choice on the order and send it:
grantedordeniedforad_user_data,ad_personalization,ad_storage, thesource(e.g.veribenim), andproof_idandgiven_atwhen you have them. - Never send consent you do not know as
granted. When unknown, leaveconsentout. - If consent is withdrawn later, report it with the endpoint on Consent.
6. Queue, retries, never block the order
- Send from a background job (a queue), not inside the payment request. adall being unreachable must never affect the order, the payment or the delivery.
- The answer is
202withaccepted,duplicateorrejected(+errors) per event.duplicateis success. 429,5xxor a network error: retry a few minutes later with the sameevent_id(e.g. 3 tries, 1 and 10 minutes apart). Make a new timestamp and signature on each try.409 ERR_REPLAYED_REQUEST: the same signed request was already handled; treat it as delivered.401: wrong, revoked key or signature, or a skewed clock. Retrying does not fix it; alert your team, because every order after it is lost.422or a per-eventrejected: a field breaks a rule; logerrors.
7. Send the past once
After setup, send the last 90 days of paid orders once in the same format (batches of 100, at most 600 requests a minute). The event_id stays the same, so running it again is safe.
8. Turn on the upload to Google
Events count in adall's decisions as soon as they arrive; sending them on to Google needs a one-time setup. In the panel press Settings › Conversion settings on Google › Set up adall's conversions on Google and pick "Sale". Google Ads gets an "Adall · Purchase" conversion that is first checked in test mode; after validated uploads adall takes it live by itself (in "Advice" mode, you approve going live).
9. Check it works
- Place a real order on the live site (or a small test order).
- In Settings › Connections › Send orders straight to adall, "N events in the last 24 hours" goes up and the "last event" time updates.
- The key list shows the key's "last used" time.
- With step 8 done, an order with an ad click and consent reaches the "Adall · Purchase" conversion in Google Ads (first as a test; Google's report can lag up to 3 hours). An order without consent never goes to Google; adall still counts it.
- If the count does not move, look at adall's answer in your server logs:
401means the key,rejectedmeans a field.