Docs menu · API reference

Docs / COD Order Protection

COD Order Protection

API reference: hold and webhook

The endpoints, headers and payloads, for stores and systems calling PixelFly directly.

You only need this page if you are integrating a custom system. GTM containers and the WooCommerce plugin call these endpoints for you — start from the overview instead.

Two endpoints, two different secrets

EndpointHeaderWhat it does
POST /cod/holdX-PF-Key: pf_live_…Holds a COD order at checkout
POST /cod/webhookX-Webhook-Secret: pfwh_…Confirms or rejects a held order

Both live on your tracking domain: your sGTM domain or custom domain, or https://track.pixelfly.io for proxy containers without one. Using the API Key where the webhook secret belongs (or the reverse) returns 401 — they are not interchangeable.

Holding an order

{
  "order_id": "12345",
  "event_time": 1699012345,
  "value": 1500.00,
  "currency": "BDT",
  "payment_method": "cod",
  "email": "customer@example.com",
  "phone": "01712345678",
  "name": "Rina Begum",
  "fbp": "fb.1....", "fbc": "fb.1....",
  "gclid": "CjwK...", "ga_client_id": "1234567890.1790000000", "ga_session_id": "1790933629",
  "contents": [{ "item_id": "101", "item_name": "Product", "price": 750, "quantity": 2 }]
}

value and currency are what make the order sendable later; order_id is how you confirm it. The identifiers (email, phone, fbp, gclid, the GA IDs) are captured now because they are gone by the time you confirm — they decide whether the platforms can credit the sale to the right ad.

Attribution fields worth sending

The example above shows gclid, but a hold stores any of these. Send whichever your site captured — they are gone by the time the order is confirmed, and each one is what lets that platform credit the sale.

PlatformFields
Google Adsgclid wbraid gbraid dclid
Metafbclid, plus the fbp / fbc cookies
TikTokttclid
Microsoftmsclkid
LinkedInli_fat_id
Snapchatsccid
GA4 / reportingga_client_id ga_session_id utm_source utm_medium utm_campaign utm_content utm_term

Browser tags can also call GET /cod/hold?k=<API Key>&d=<URL-encoded JSON>. If PixelFly is briefly unreachable the Worker queues the request and answers 202 {"action":"queued"} — a queued hold is not a lost one.

Confirming or rejecting an order

curl -X POST https://<your-tracking-domain>/cod/webhook \
  -H "Content-Type: application/json" -H "X-Webhook-Secret: pfwh_…" \
  -d '{"type":"order.status","order_id":"1042","status":"completed"}'

event_time is the original order time and is kept when the platform still accepts it. Meta refuses anything dated more than 7 days back, so a later confirmation is sent dated now rather than being dropped.

Which statuses confirm, reject or are ignored: see confirming orders. A confirmation that arrives before the hold is kept, and applied when the hold lands.

Confirming an order that was never held? Send value and currency with the webhook too, plus email and phone if you have them. Without them nothing can be sent, and the order waits as missing purchase data.

GTM tag templates

If you are calling these endpoints from GTM rather than your own backend, these templates do it for you.

The Data Client is what receives the confirmed order at /data in a server container. Made by Stape, not PixelFly — also available in GTM's Community Template Gallery, which is the copy we recommend.

We use cookies to enhance your experience, analyze site traffic, and for marketing purposes. By continuing to use our site, you consent to our use of cookies. Learn more