EnglishTracker integrationHow tracking works

How tracking works

AlterCPA TOP is a postback source. When a lead changes state, we fire an HTTP request to the URL you configured for that event — straight into your tracker. We only send postbacks; we never receive them.

The {click} you embed in your deep link is the bridge: it travels from your ad → your tracker → AlterCPA TOP → back to your tracker when we fire the postback. Your tracker uses it to match our postback to its original click record.

The five events (= lead statuses)

EventFires whenConditional?
waitSubscriber pressed Start in the botNo — always fires
holdJoin request submitted (approval-required chats)No — always fires
approveSubscriber joined, or request was approvedNo — always fires
cancelSubscriber left voluntarilyOnly within the unsub window
trashSubscriber was kicked or bannedOnly within the unsub window

A leave after the unsub window still moves the lead to cancel / trash but fires no postback. The window is configured per campaign.

Macro reference

Macros are substituted into your postback URLs before we fire them. They also work in the CPA button URL in the welcome message.

MacroValue
{click}The click id from the deep link — the join to your tracker
{status}wait / hold / approve / cancel / trash
{campaign}Campaign code
{user}Your AlterCPA TOP user id
{lead}Internal lead id — useful as a dedup key
{subscriber}Subscriber’s Telegram user id
{username}Subscriber @username (may be empty if the user has none)
{chat}Tracked chat id
{time}UNIX timestamp of the event

Unknown macros are left untouched. Empty values become empty strings.

Global vs per-campaign templates

You have two places to set postback URLs:

  1. Profile (global) — five templates set once and reused everywhere.
  2. Campaign (per-campaign) — five templates for a specific campaign.

The rule is all-or-nothing per campaign:

  • Campaign sets any of its five templates → uses its own set as-is (empty fields in the campaign mean “no postback for that event”).
  • Campaign sets none → falls back to the global templates from your Profile.

This means if you override one postback on a campaign you have to set all five you care about on that campaign — there’s no per-event fall-through.

Delivery rules

  • GET only. We issue a plain HTTP GET. Every tracker we target (AlterCPA Lite, Keitaro, Binom, …) accepts GET postbacks.
  • Public hosts only. Your URLs are checked against an SSRF blocklist — loopback, private/RFC1918 ranges, link-local, and cloud-metadata IPs are all refused. Only public hostnames and IPs are accepted.
  • Retried with backoff. Failures are re-queued at 1 min → 5 min → 30 min → 2 h → 6 h. After the last retry the event is logged as failed.
  • Success = HTTP 2xx (and a {"status":"ok"} body for AlterCPA Lite).
  • Idempotent per lead/event — we don’t re-fire an event for the same lead unless a new transition actually occurs.

The unsub window

Join ─────────────────────── Leave
  │◀─────── unsub window ──▶│
  │                         │
  ▼                         ▼
Leave inside window:    Leave outside window:
  cancel / trash            cancel / trash
  (postback fires)          (postback suppressed)

Window of 0 means “always fire” (no expiry). Typical values: 1 day, 7 days, 30 days. Set per campaign in the editor.

Next steps

Choose your tracker to get a ready-to-paste postback setup: