The most confusing postback URL often looks harmless:
https://track.example.com/p?click_id={subid}&status={status}&payout={payout}
Why does the left side say click_id while the right side says {subid}? Which one is the real click ID? And why might another tracker use cid={s2} for the same job?
The short answer is that a postback parameter has two owners. The receiving tracker defines the key on the left of =. The affiliate network sending the request defines the macro on the right. At runtime, the network replaces that macro with a real value. The names do not need to match; the value does.
This guide explains that mapping, the difference between click ID and sub ID, and the exact tests that prove a postback works. If you need the broader server-to-server concept first, start with what S2S postback tracking is.
The three parts people call “a macro”
Take this pair:
click_id={subid}
It contains three distinct things:
| Layer | Example | Who controls it | Job |
|---|---|---|---|
| Target parameter key | click_id= | The receiving tracker | Tells the receiver where to read the value |
| Source macro | {subid} | The sending network | Tells the sender which stored value to insert |
| Resolved runtime value | 8f2a91c0d3 | Created earlier in the click flow | Identifies the actual click |
After macro replacement, the request no longer contains braces:
https://track.example.com/p?click_id=8f2a91c0d3&status=deposit&payout=45.00
If the raw request still contains click_id={subid}, the network did not recognize or expand the macro. A browser may still return 200 OK, but attribution is broken.

Click ID vs sub ID: related, but not the same
A click ID is a unique identifier for one tracked click. It is the join key between the outbound click and the later conversion. If 10,000 people click, a tracker should create 10,000 click IDs.
A sub ID is a generic field used to carry or store a value. It might contain a tracker click ID, but it can also contain a placement, buyer code, creative angle or campaign label. sub1=facebook_feed is useful segmentation; it is not a unique click identifier.
This is why a network may ask you to pass your click ID into its subid, aff_sub, s2 or sub1 field. The network is not changing the identity. It is storing your click ID in an available slot so it can send the same value back after conversion.
Do not confuse either of them with:
- Campaign, ad set or ad ID: identifies a group of clicks, not one click. Use the Facebook URL parameter mapping or TikTok macro mapping to capture that hierarchy.
fbclidorttclid: a platform click identifier. It can help platform attribution, but your tracker still needs a stable internal click ID for its own conversion lookup.- Transaction ID: identifies one conversion. One click can produce registration, first deposit and redeposit transactions, each with a different transaction ID.
The complete click-to-postback round trip
Imagine DarkCore sends traffic to an affiliate network whose available storage field is aff_sub.
1. The tracker creates the click ID
A user opens the Track Link. DarkCore logs the source context and creates:
dc_01K2A7M9X4
2. The tracker passes it to the offer
The offer URL contains a DarkCore-owned outbound macro:
https://network.example/offer?aff_sub={click_id}
DarkCore expands its macro before redirecting:
https://network.example/offer?aff_sub=dc_01K2A7M9X4
The network receives the real value under its aff_sub key and stores it.
3. The network sends it back
In the network’s postback settings, the direction reverses:
https://track.example.com/p?click_id={aff_sub}&status={status}&payout={payout}&transaction_id={conversion_id}
Now click_id and transaction_id are keys understood by the receiving tracker. {aff_sub}, {status}, {payout} and {conversion_id} are macros understood by the sending network.
4. The tracker attributes the conversion
The live callback might be:
https://track.example.com/p?click_id=dc_01K2A7M9X4&status=ftd&payout=45.00&transaction_id=conv_7719
The tracker finds the original click, maps ftd to the intended conversion status, attaches the payout and uses conv_7719 to recognize a literal retry.
That round trip is the entire postback contract: send one exact click value forward, store it unchanged, return it under a key the tracker accepts.
Why macro syntax differs between trackers and networks
There is no universal macro standard. Each product owns its template engine and parameter vocabulary.
Keitaro’s official postback guide uses subid to find the click and documents aliases for incoming parameter names. Voluum’s documentation shows the same value changing labels across the route: a Voluum {clickid} can be stored in a network field such as s2, then returned to Voluum as cid={s2}. Affise documents {clickid} and {click_id} variants depending on the integration.
The practical rule is:
On the left, use the parameter name your receiving system accepts. On the right, use the macro syntax your sending system documents.
Never copy a whole postback template from another tracker just because the concepts look familiar. {click_id}, {clickid}, {subid}, ${click_subid} and {s2} may all refer to a click value in some platform, but they are not interchangeable template syntax.
Postback parameters DarkCore accepts
DarkCore accepts common aliases so a partner does not always need to rename its existing fields:
| Meaning | Accepted incoming keys |
|---|---|
| Click ID | click_id, clickid, cid, subid, sub_id |
| Status | status, goal, event |
| Payout | payout, sum, amount, revenue |
| Transaction ID | transaction_id, txid, tx_id, transactionid, conversion_id, conv_id |
| Conversion time | event_at, event_time |
These are incoming query keys, not a promise that every network understands macros with the same spelling. If a network documents {click_subid}, a valid mapping can be:
https://track.example.com/p?click_id={click_subid}&status={goal}&payout={commission}
Use the network’s exact macros on the right. Use one of the tracker’s accepted keys on the left.
Status, payout and transaction ID need separate mapping
Returning the click ID is necessary, but it is not a complete conversion record.
Status
Networks may send lead, reg, registration, sale, deposit, dep or ftd. Map raw network values into the conversion statuses used by your workspace. A successful click match with the wrong status can still route the event incorrectly or exclude it from the metric you optimize.
Payout
Pass the numeric commission, not a formatted string such as $45 USD. Confirm whether the network macro represents gross revenue, your commission or order value. A parsed number can still be the wrong business metric.
Transaction ID
Use the network’s unique conversion identifier whenever available. In DarkCore, a supplied transaction ID makes idempotency specific to that conversion and status. Without it, the safe fallback is the click ID plus canonical status. The distinction matters when one click may generate multiple real transactions.

A pass/fail test for the full chain
Do not sign off with “the URL opened” or “the endpoint returned 200.” Record evidence at every handoff:
| Test | Pass condition | Pass? |
|---|---|---|
| Original click | The tracker logs one new click and creates a click ID | ☐ |
| Outbound offer URL | The network receives the exact click ID, with no literal {click_id} left | ☐ |
| Network storage | Its click/conversion log shows that same value in the configured sub field | ☐ |
| Raw postback | The returned value is byte-for-byte identical under an accepted click key | ☐ |
| Status | The raw status maps to the intended canonical conversion | ☐ |
| Transaction | A unique conversion ID is present when the network provides one | ☐ |
| Revenue | Payout is numeric and represents the agreed business value | ☐ |
| Retry | Repeating the same transaction does not duplicate conversion or revenue | ☐ |
| Reporting | The conversion appears on the original click, campaign and stream | ☐ |
Use the Postback URL Builder and S2S tester to assemble a callback and generate a safe test command. Then verify the raw ingress log and the final conversion row. A 200 OK only confirms how the endpoint responded; it does not prove the click was found, the status was right or the payout meant what you thought it meant.
For a complete outbound-link-to-callback example, use the affiliate tracking link guide. If Keitaro owns the click, follow the dedicated Keitaro postback setup for subid, status training, payout and tid.
Common failure patterns
- Literal braces return in production. The sender did not recognize the macro. Check its documentation and the field in which postback macros are actually supported.
- The click ID changes case, length or encoding. Treat it as an opaque string. Do not parse, trim or rebuild it between systems.
- A campaign ID is returned as
click_id. Thousands of clicks collapse onto one non-unique value, so attribution cannot be trusted. - The forward mapping works, the return mapping does not. Offer URL macros belong to the tracker; postback macros belong to the network. The direction changed, so the template engine changed too.
- Only registration is visible. Deposit may use a separate URL field or a raw status that was never mapped.
- Every retry adds revenue. Add a stable transaction ID and verify idempotency with the exact same callback twice.
- Sensitive data is stored in sub IDs. Do not pass email, phone, name or another direct identifier in query parameters. URLs are routinely stored in access logs and partner dashboards.
FAQ
Is subid the same as click_id?
Not by definition. click_id describes the role of a value: uniquely identify one click. subid describes a flexible storage field. A sub ID becomes the carrier of a click ID only when you deliberately put that click ID into it.
Must the names on both sides of = match?
No. click_id={subid} is valid when the receiver expects click_id and the sender stores your click value under subid. Matching the resolved value is what matters.
Can I use one postback URL for every conversion status?
Yes, if the network expands a status macro and your tracker maps every value you need. If the network provides separate callback fields per goal, configure each one explicitly.
Why did the postback return 200 but no conversion appeared?
Many endpoints intentionally acknowledge malformed, unknown or duplicate callbacks with a generic success response to prevent retry storms and information leakage. Check the raw ingress result, click lookup, status mapping and final conversion record.
The durable mental model
Stop memorizing macro spellings and trace ownership instead:
- Who creates the click value?
- Under which key does the next system receive and store it?
- Which macro does that system use to return the stored value?
- Which incoming key does the tracker accept?
- Which transaction ID prevents a retry from becoming extra revenue?
Once those five answers are written down, different tracker syntaxes stop being mysterious. They are simply adapters around one invariant: the same click identifier must survive the entire round trip unchanged.