Skip to content

traffic.cx documentation

Payments API

Send payments to traffic.cx from any server, for providers without a connector or your own billing.

Updated 14 October 2026

Use it for your own billing or a provider without a native connector. Native guides are available for Stripe, Dodo Payments, Lemon Squeezy and Polar.

Send payments only after your server has verified them with your billing system. Keep the API key on your server; never put it in browser code. Examples use placeholder credentials and a fictional site/order: replace them with your own test site's values before running requests.

Get a key

Owners and admins create keys in Team → API keys. Give the key the Send payments permission (payments:write). A key works for every site of its team.

Creating API keys requires a paid plan. First install the tracker and use the checkout handoff to save attribution IDs with your order. Send those saved IDs when the payment succeeds, rather than reading IDs from a different thank-you-page visit.

Record a payment

POST https://api.traffic.cx/v1/payments

bash

curl -X POST https://api.traffic.cx/v1/payments \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "site": "tcx_yoursite",
    "transaction_id": "order_1001",
    "amount": 49.00,
    "currency": "USD",
    "pageview_id": "9f2c4a1be07d3355",
    "email": "ada@example.com"
  }'
FieldRequiredMeaning
siteyesThe site's ID (tcx_…, in Settings → General)
transaction_idyesYour ID for the payment, up to 255 characters. Sending it again updates the payment instead of adding another.
amountyesA positive number, up to 4 decimals, in currency
currencyyesThree-letter ISO code, such as USD or EUR
kindnoone_time (default), subscription_start, renewal or refund
refund_ofrefundsThe transaction_id of the payment refunded. Send the refunded amount as a positive number.
timestampnoWhen it was paid: ISO 8601 or Unix seconds. Default: now. Not in the future.
pageview_idnotrafficcx.pageviewId() from the visit that led to the payment
tcx_vidnoThe tcx_vid cookie (cookie mode)
email / customer_idnoWho paid, so renewals keep the credit of their first payment. Stored only as a keyed hash and a masked hint.

The answer says whether the payment was attributed. This is an illustrative response; the values depend on your recorded visit and site's reporting currency:

json

{
  "ok": true,
  "transaction_id": "order_1001",
  "attributed": true,
  "amount_reporting": "49.0000",
  "currency_reporting": "USD",
  "channel": "Organic Search",
  "source": "Google"
}

201 for a new payment, 200 for an update. Errors are { "error": "…", "path": "field" } with 400 (a field), 401 (no valid key), 403 (no payments:write) or 404 (a site of another team).

An unattributed payment is still recorded. A deduplicated payment can instead return { "ok": true, "duplicate_of": "…" }. Reuse the same transaction ID when retrying the same payment; choose a different ID for each renewal and refund. The response reflects attribution at that moment; late visit data can be matched by later retries.

Remove a payment

bash

curl -X DELETE "https://api.traffic.cx/v1/payments/order_1001?site=tcx_yoursite" \
  -H "Authorization: Bearer YOUR_API_KEY"

Renewals and refunds

bash

# A renewal: the same customer, so it keeps the credit of the first payment
curl -X POST https://api.traffic.cx/v1/payments -H "Authorization: Bearer YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"site":"tcx_yoursite","transaction_id":"order_1002","kind":"renewal","amount":49,"currency":"USD","email":"ada@example.com"}'

# A partial refund of order_1001
curl -X POST https://api.traffic.cx/v1/payments -H "Authorization: Bearer YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"site":"tcx_yoursite","transaction_id":"refund_77","kind":"refund","refund_of":"order_1001","amount":20,"currency":"USD"}'

Deleting removes a previously reported payment from revenue; it is not how you represent a real customer refund. For a refund, record the separate positive refund amount with kind: "refund" and refund_of, as above. Deletion does not issue money back to a customer.

Verify and troubleshoot

  1. Record a test visit, save its pageview ID, and use a separate test site and a team key with payments:write.
  2. Send one payment, confirm the response, then find its transaction ID and source in Revenue.
  3. Retry the same transaction ID. Confirm that it updates the existing payment rather than increasing the count.
  4. Send a renewal with the same customer identifier, then a partial refund with its own ID. Confirm the original payment's attribution is retained when those records have no new visit link.

For 400, check the returned field path, supported currency, positive decimal amount, ID length and timestamp. For 401/403, check the key and permission; for 404, verify the site belongs to the key's team. If the payment is Unattributed, use the attribution troubleshooting steps.

API request validation, updates, refunds and access checks are covered by local tests. No request in this guide has been sent to a real customer account as part of publication.

Need a hand with your setup?

Contact supportPlans and trial details