Core resources
Tracking Links
Issue the go.linkapprove.com redirect that turns a click into an attributed conversion.
The tracking link object
A tracking link is the bridge between a program you are approved on and a channel you own. Clicks are counted per link.
idintegerLinkApprove's identifier for the link. It is not part of the URL.
programIdintegerThe program the link promotes.
channelIdintegerThe channel the link was minted for. Clicks attach to it.
subIdstring | nullYour own attribution tag, stored on the link. Group the performance report by subId to see its clicks.
subId2string | nullA second, independent tag stored the same way. Useful for placement within a page.
urlstringThe link you place, https://go.linkapprove.com/{slug} where the slug is nine random letters and digits. This is the only URL a visitor should ever see.
destinationUrlstring | nullWhere the redirect lands. Null when the link points at the merchant's default landing page.
statusenumactive or paused. A paused link stops redirecting.
clicksintegerTotal clicks recorded. Updated in batches every ten minutes.
lastClickAtstring | nullISO 8601 timestamp of the most recent click, or null if never clicked.
createdAtstringISO 8601 timestamp of when the link was minted.
Conversions are not per link
program or channel.{
"id": 90124,
"programId": 4821,
"channelId": 12,
"subId": "spring-guide",
"subId2": "hero-banner",
"url": "https://go.linkapprove.com/k3Rm8Qw2Z",
"destinationUrl": "https://northpeak.com/collections/shells",
"status": "active",
"clicks": 4180,
"lastClickAt": "2026-08-18T11:07:35Z",
"createdAt": "2026-08-18T09:41:02Z"
}Create a tracking link
https://api.linkapprove.com/v1/tracking-linkslinks:writeLinks are cheap and permanent. Mint one per placement rather than reusing a single link everywhere, so your click reporting can tell them apart.
programIdintegerrequiredA program you are approved on for this channel.
channelIdintegerrequiredThe verified channel the traffic will come from. Clicks attach to it.
subIdstring1–64 letters, digits, dashes and underscores (^[A-Za-z0-9_-]{1,64}$).
subId2stringA second tag with the same rules, tracked independently.
destinationUrlstringAn http(s) URL of at most 255 characters on the program's merchantDomain or a subdomain of it. Only for programs with supportsDeepLinks: true.
Idempotent by content
A new link returns 201. If a link with the same programId, channelId, destinationUrl, subId and subId2 already exists, you get that link back with 200 instead, so retrying a create never mints a duplicate.
When it fails
404program_not_found: no such program.404channel_not_found: the channel does not exist or is not yours.403channel_not_verified: the channel is not approved, or has a verification step it has not completed.422destination_not_allowed: the program does not support deep links, ordestinationUrlis off the merchant's domain. See Deep links below.
Approval is enforced here
403 with program_not_approved. Check status on the program with that channelId first, or apply and wait for the decision.curl -X POST "https://api.linkapprove.com/v1/tracking-links" \
-H "Authorization: Bearer $LINKAPPROVE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"programId": 4821,
"channelId": 12,
"subId": "spring-guide"
}'https://api.linkapprove.com/v1/tracking-linksHeld in this tab's session storage only, and reused by every runner on the site.
This panel replays the documented sample response and does not call the API. Copy a code sample to send a real request with your key.
Sub IDs and attribution
subId and subId2 are yours. We store them on the link and never interpret them. They are not sent to the network and are not attached to conversions; they exist so your click reporting can answer "which newsletter sent this traffic?" without guessing from link IDs.
- Pick a scheme and keep it:
2026-08-newsletter,post-4471,sidebar-a. - Sub IDs are set at mint time and immutable afterwards. Mint a new link rather than rewriting one.
- Group the performance report by
subIdto see clicks sliced your way rather than ours. - Do not put anything personal in a sub ID. It shows up in reports.
Sub IDs count clicks, not conversions
groupBy=subId row carries clicks only. conversions and conversionRate are null and earnings is empty.{
"success": true,
"message": "Report fetched",
"data": {
"data": [
{
"subId": "spring-guide",
"clicks": 2840,
"conversions": null,
"conversionRate": null,
"earnings": []
},
{
"subId": "post-4471",
"clicks": 1102,
"conversions": null,
"conversionRate": null,
"earnings": []
},
{
"subId": "sidebar-a",
"clicks": 238,
"conversions": null,
"conversionRate": null,
"earnings": []
}
],
"count": 3,
"pages": 1
}
}Deep links
By default a link lands on the merchant's campaign landing page. Passing destinationUrl sends the visitor to a specific product or collection instead, which converts materially better when you are reviewing one item.
What the redirect does
The redirect at go.linkapprove.com is deliberately thin. It records the click asynchronously and issues a 302 immediately. There is no interstitial and no blocking work in the path.
- The URL must be http(s) and on the program's
merchantDomainor a subdomain of it. Anything else returns422withdestination_not_allowedand themerchantDomainit expected. - Existing query parameters are preserved; we append our tracking parameters rather than replacing the query string.
- Not every program supports deep links. Check
supportsDeepLinksfirst. Passing adestinationUrlfor a program that does not returns422destination_not_allowed. Omit it to land on the merchant's default page.
GET /k3Rm8Qw2Z HTTP/1.1
Host: go.linkapprove.com
HTTP/1.1 302 Found
Location: https://network.example/c/4821?pub=12&url=https%3A%2F%2Fnorthpeak.com%2Fcollections%2Fshells{
"success": false,
"message": "destinationUrl must be an http(s) URL on northpeak.com",
"error": {
"code": "destination_not_allowed",
"merchantDomain": "northpeak.com"
}
}List tracking links
https://api.linkapprove.com/v1/tracking-linkslinks:readReturns the tracking links issued to you, newest first, including the ones minted in the dashboard, not only through the API.
programIdintegerOnly links for this program.
channelIdintegerOnly links for this channel.
subIdstringOnly links minted with exactly this sub ID.
statusenumactive or paused.
pageinteger1-based page number. Defaults to 1.
sizeintegerResults per page, 1–100. Defaults to 10.
Click counts lag a little
clicks and lastClickAt are written in batches, so a click shows up within about ten minutes.curl "https://api.linkapprove.com/v1/tracking-links?page=1&size=10" \
-H "Authorization: Bearer $LINKAPPROVE_API_KEY"https://api.linkapprove.com/v1/tracking-links?page=1&size=10Held in this tab's session storage only, and reused by every runner on the site.
This panel replays the documented sample response and does not call the API. Copy a code sample to send a real request with your key.
Retrieve a tracking link
https://api.linkapprove.com/v1/tracking-links/{id}links:readReturns one tracking link. A link that does not exist or is not yours returns 404 tracking_link_not_found.
curl "https://api.linkapprove.com/v1/tracking-links/90124" \
-H "Authorization: Bearer $LINKAPPROVE_API_KEY"https://api.linkapprove.com/v1/tracking-links/90124Held in this tab's session storage only, and reused by every runner on the site.
This panel replays the documented sample response and does not call the API. Copy a code sample to send a real request with your key.