API reference
Every REST API v1 endpoint — offers, events, creatives, partner access, affiliates, advertisers, reports, clicks, conversions, postbacks, tracking links, deals, product feeds and the Google Ads linter — with parameters, fields and examples.
Last updated 16 min read
On this page
- Account
- GET /me
- Offers
- GET /offers
- GET /offers/{id}
- POST /offers
- PATCH /offers/{id}
- Events
- Partner access
- GET /offers/{id}/creatives
- Affiliates
- GET /affiliates
- GET /affiliates/{id}
- POST /affiliates
- PATCH /affiliates/{id}
- Advertisers
- Reports
- GET /reports
- GET /reports/timeseries
- Clicks
- GET /clicks
- GET /clicks?gclid=…
- GET /clicks/{click_id}
- Conversions
- GET /conversions
- GET /conversions/{id}
- POST /conversions
- PATCH /conversions/{id}
- PATCH /conversions
- Postbacks
- Tracking links
- GET /tracking-link
- Deals & product feeds
- GET /deals
- GET /product-feeds
- Google Ads
- POST /google-ads/lint
Base URL https://app.trackcrown.com/api/v1. Every request needs Authorization: Bearer atk_…
(Authentication & API keys). Conventions for money, times, IDs and date ranges
are in the API overview; paging in Pagination; error
codes in Rate limits & errors. The machine-readable description is
https://app.trackcrown.com/api/v1/openapi.json (OpenAPI).
In the examples $ATK holds your key.
Account#
GET /me#
Who is calling: the key, its workspace, the partner/advertiser it belongs to, its permissions and the rate-limit state.
curl https://app.trackcrown.com/api/v1/me -H "Authorization: Bearer $ATK"{
"data": {
"key": { "id": 7, "name": "BI export", "role": "analyst" },
"workspace": { "id": 1, "slug": "demo", "name": "Demo Network", "timezone": "Asia/Kolkata", "currency": "USD" },
"affiliate": null,
"advertiser": null,
"permissions": ["dashboard.read", "reports.read", "offers.read", "…"],
"rate_limit": { "limit": 600, "remaining": 598, "reset_sec": 41 }
}
}Offers#
GET /offers#
curl "https://app.trackcrown.com/api/v1/offers?status=active&limit=2" -H "Authorization: Bearer $ATK"{
"data": [
{
"id": 12,
"code": "Kx7Lm2Q",
"name": "Summer Sale — US",
"status": "active",
"visibility": "approval",
"advertiser_id": 3,
"category": "Retail",
"description": "",
"restrictions": "No incent traffic.",
"preview_url": "https://shop.example.com/summer",
"destination_url": "https://shop.example.com/summer?cid={click_id}&s1={sub1}",
"fallback_url": "",
"allowed_domains": [],
"currency": "USD",
"revenue_type": "rpa",
"revenue": "7.0000",
"payout_type": "cpa",
"payout": "5.0000",
"caps": { "conversions": { "daily": 100 } },
"targeting": { "countries_allow": ["US"] },
"conversion_method": "any",
"unique_per_click": true,
"attribution_days": 30,
"default_status": "approved",
"thumbnail_url": "",
"tags": ["retail"],
"is_featured": false,
"events": [
{ "id": 40, "code": "default", "name": "Conversion", "revenue_type": "rpa", "revenue": "7.0000",
"payout_type": "cpa", "payout": "5.0000", "is_default": true, "is_private": false, "allow_multiple": false }
],
"created_at": "2026-10-01T09:30:00.000Z",
"updated_at": "2026-10-08T14:02:11.000Z"
}
],
"next_cursor": null
}What each role sees:
- Partner keys get offers they can run or request — public and approval-required offers, plus private offers
they are approved for — with
payout_type/payoutafter their custom payout (CPC offers always show the offer's own per-click rate: custom payouts do not apply to click-priced offers), non-private events with their payouts, and three extra fields:access_status(approved,pending,rejectedornull),can_runandtracking_link(their ready-to-use link whilecan_runis true). Revenue, advertiser, destination URL, fallback, caps and allowed domains are never included. - Advertiser keys get their own offers with revenue fields (their cost) and every event, but no payout.
GET /offers/{id}#
{id} is the numeric id or the offer code. Returns {"data": {…offer…}} in the same shape as the list.
POST /offers#
Admin keys. Creates the offer and its default event (with the offer's revenue and payout); events adds more
events (goals). Omitted fields take the defaults shown.
curl -X POST https://app.trackcrown.com/api/v1/offers \
-H "Authorization: Bearer $ATK" -H "Content-Type: application/json" \
-d '{
"name": "Summer Sale — US",
"destination_url": "https://shop.example.com/summer?cid={click_id}&s1={sub1}",
"advertiser_id": 3,
"revenue": "7.00",
"payout": "5.00",
"targeting": { "countries_allow": ["US"] },
"events": [{ "code": "sale", "name": "Sale", "payout_type": "cps", "payout": "10", "revenue_type": "rps", "revenue": "15" }]
}'Returns 201 with {"data": {…offer…}}.
PATCH /offers/{id}#
Admin keys. Send only the fields to change (same fields as create, except code and events). Changing
revenue_type, revenue, payout_type or payout also updates the default event so every conversion path uses
the new terms.
Click-priced offers (payout_type: "cpc", revenue_type: "rpc") are credited per unique click at the offer's own
rate in reports and billing, so they do not support per-partner overrides on that side: switching an offer to cpc
(or rpc) while it has partner payout (or revenue) overrides returns 400 validation_failed with the field in
details.fields — remove the overrides in the panel first.
curl -X PATCH https://app.trackcrown.com/api/v1/offers/Kx7Lm2Q \
-H "Authorization: Bearer $ATK" -H "Content-Type: application/json" \
-d '{"status": "paused"}'Events#
curl -X POST https://app.trackcrown.com/api/v1/offers/12/events \
-H "Authorization: Bearer $ATK" -H "Content-Type: application/json" \
-d '{"code": "deposit", "name": "First deposit", "revenue": "40", "payout": "30"}'{ "data": { "id": 41, "code": "deposit", "name": "First deposit", "revenue_type": "rpa", "revenue": "40.0000",
"payout_type": "cpa", "payout": "30.0000", "is_default": false, "is_private": false, "allow_multiple": false } }Private events are hidden from partners and never fire their postbacks.
Partner access#
curl -X PUT https://app.trackcrown.com/api/v1/offers/12/affiliates/Pq3Rt8z \
-H "Authorization: Bearer $ATK" -H "Content-Type: application/json" \
-d '{"status": "approved", "note": "Welcome aboard"}'{ "data": { "affiliate_id": 7, "affiliate_code": "Pq3Rt8z", "affiliate_name": "Acme Media", "status": "approved",
"note": "Welcome aboard", "requested_at": "2026-10-09T10:00:00.000Z", "decided_at": "2026-10-10T08:15:30.123Z" } }GET /offers/{id}/creatives#
The offer's creatives (banners, HTML, text, links, e-mail), read-only.
Staff keys see every creative; advertiser keys those of their own offers; partner keys the active creatives of
offers they can run, with {tracking_link} replaced by their own tracking link and two extra fields: tracking_link
and html (ready-to-paste markup for image creatives).
curl "https://app.trackcrown.com/api/v1/offers/Kx7Lm2Q/creatives?kind=image" -H "Authorization: Bearer $ATK"{
"data": [
{ "id": 5, "offer_id": 12, "name": "Summer 300x250", "kind": "image", "url": "https://app.trackcrown.com/creative-files/…/summer-300x250.png",
"body": "", "width": 300, "height": 250, "status": "active",
"created_at": "2026-10-01T09:30:00.000Z", "updated_at": "2026-10-01T09:30:00.000Z" }
],
"next_cursor": null
}Affiliates#
Staff keys only (admin: read/write, analyst: read).
GET /affiliates#
Filters: status (active, pending, blocked, rejected), manager_id, tag, ids, q (name, company or
e-mail contains / exact code), limit (default 50, max 200), cursor.
curl "https://app.trackcrown.com/api/v1/affiliates?status=active&q=acme" -H "Authorization: Bearer $ATK"{
"data": [
{
"id": 7,
"code": "Pq3Rt8z",
"name": "Acme Media",
"status": "active",
"company": "Acme Media Ltd",
"contact_name": "Jane Doe",
"email": "ops@acme.example",
"phone": "",
"website": "https://acme.example",
"country": "US",
"messenger": "",
"traffic_sources": "Search, native",
"tier": "A",
"manager_id": 4,
"payment_method": "paypal",
"payment_details": { "paypal": "billing@acme.example" },
"payment_terms": "net30",
"min_payout": "50.0000",
"currency": "USD",
"notes": "",
"tags": ["search"],
"approved_at": "2026-09-30T12:00:00.000Z",
"created_at": "2026-09-29T08:00:00.000Z",
"updated_at": "2026-10-02T16:45:00.000Z"
}
],
"next_cursor": null
}payment_details is only included for admin keys.
GET /affiliates/{id}#
{id} is the numeric id or the affiliate code.
POST /affiliates#
Admin keys. name is required; every other field is optional: code (6-10 letters/digits, generated when
omitted), status (default active), company, contact_name, email, phone, website, country (ISO-2),
messenger, traffic_sources, tier, manager_id (a staff user of the workspace), payment_method (paypal,
wire, payoneer, crypto, other), payment_details (object of strings), payment_terms (default net30),
min_payout, currency (default: workspace currency), notes, tags.
curl -X POST https://app.trackcrown.com/api/v1/affiliates \
-H "Authorization: Bearer $ATK" -H "Content-Type: application/json" \
-d '{"name": "Acme Media", "email": "ops@acme.example", "country": "US", "payment_method": "paypal", "payment_details": {"paypal": "billing@acme.example"}}'Returns 201 with the affiliate. To let the partner sign in, invite a user for them from the panel.
PATCH /affiliates/{id}#
Admin keys. Send only the fields to change, e.g. {"status": "blocked"}. Setting status to active for the first
time records approved_at.
Advertisers#
Staff keys only.
curl -X POST https://app.trackcrown.com/api/v1/advertisers \
-H "Authorization: Bearer $ATK" -H "Content-Type: application/json" \
-d '{"name": "Shop Inc.", "website": "https://shop.example.com", "currency": "USD"}'{
"data": {
"id": 3,
"name": "Shop Inc.",
"status": "active",
"company": "",
"contact_name": "",
"email": "",
"phone": "",
"website": "https://shop.example.com",
"country": "",
"currency": "USD",
"account_manager_id": null,
"billing_terms": "net30",
"notes": "",
"tags": [],
"postback_token": "9f0c…",
"created_at": "2026-10-10T08:15:30.123Z",
"updated_at": "2026-10-10T08:15:30.123Z"
}
}postback_token (the advertiser's S2S token, see Server-to-server postback reference) is only included for admin keys.
Reports#
GET /reports#
Runs the same engine as the panel's report builder: one aggregate over clicks, impressions and conversions, grouped by up to three dimensions, with totals computed by the database (never by adding up rows).
Dimensions:
"Clicks only" dimensions are click attributes: impressions and conversions are not split by them. What each Google Ads dimension holds: ValueTrack reference.
Metrics: impressions, clicks, unique_clicks, bot_clicks, ctr, conversions (approved),
pending_conversions, rejected_conversions, cvr (approved ÷ unique clicks), revenue, payout, profit,
margin, epc, rpc, cpc, avg_sale_amount, sale_amount; staff keys also ad_cost, roas and net_profit
(below). Counts are numbers, money is a 4-decimal string, ratios are fractions (0.0315 = 3.15 %) or null when the
denominator is 0.
Ad costs (ad_cost, roas = revenue ÷ ad cost, net_profit = revenue − payout − ad cost; staff keys only):
media spend imported under Ad costs & ROAS, converted to the report currency at
the ECB rate of the cost date. A cost row splits only by date, hour, week, month, offer, affiliate,
advertiser, traffic_source, ext_campaign_id and ext_adgroup_id; with any other group_by the cost is reported
under the empty value. An in filter on another dimension excludes the cost, not_in keeps it, and event and status
filters leave it alone. Cost currencies without a usable rate are listed in other_currencies.
Partner keys only see their own traffic and never revenue, profit, margin, rpc, cpc, bot_clicks or the
advertiser dimension; payout is their earnings and epc is earnings per click. Advertiser keys only see their
own offers and never payout, profit, margin, rpc, cpc, bot_clicks or partner names; revenue is their
cost. Requesting a metric or dimension the role cannot see is a 400 invalid_parameter.
Currencies: every offer has its own currency and money is never added across currencies. Money columns
(revenue, payout, profit, epc, …) count only amounts in the report's currency (the currency parameter,
else the workspace currency); counts (clicks, conversions) cover every currency. The response's other_currencies
lists the other currencies that have money in the same range and scope — run the report again with
currency=EUR (for example) to see those amounts. The CSV export names the currency in every money header and
adds a note line when other currencies were left out.
curl "https://app.trackcrown.com/api/v1/reports?preset=last7&group_by=offer,date&metrics=clicks,conversions,revenue,payout,profit&sort=-clicks&filters=country:in:US|CA" \
-H "Authorization: Bearer $ATK"{
"data": [
{ "offer": "12", "offer_label": "Summer Sale — US", "offer_sub": "Kx7Lm2Q", "date": "2026-10-09", "date_label": "Oct 9, 2026",
"clicks": 1520, "conversions": 41, "revenue": "287.0000", "payout": "205.0000", "profit": "82.0000" }
],
"totals": { "clicks": 1520, "conversions": 41, "revenue": "287.0000", "payout": "205.0000", "profit": "82.0000" },
"columns": [
{ "key": "offer", "label": "Offer", "kind": "dimension", "format": "entity" },
{ "key": "date", "label": "Date", "kind": "dimension", "format": "date" },
{ "key": "clicks", "label": "Clicks", "kind": "metric", "format": "number" },
{ "key": "conversions", "label": "Conversions", "kind": "metric", "format": "number" },
{ "key": "revenue", "label": "Revenue", "kind": "metric", "format": "money" },
{ "key": "payout", "label": "Payout", "kind": "metric", "format": "money" },
{ "key": "profit", "label": "Profit", "kind": "metric", "format": "money" }
],
"total_rows": 1,
"next_offset": null,
"currency": "USD",
"other_currencies": ["EUR"],
"range": { "from": "2026-10-03T18:30:00.000Z", "to": "2026-10-10T18:30:00.000Z", "tz": "Asia/Kolkata" },
"group_by": ["offer", "date"],
"metrics": ["clicks", "conversions", "revenue", "payout", "profit"],
"date_basis": "conversion"
}CSV export of the same report:
curl -o report.csv "https://app.trackcrown.com/api/v1/reports?preset=last_month&group_by=affiliate&format=csv" \
-H "Authorization: Bearer $ATK"GET /reports/timeseries#
A gap-filled series — one point per day (interval=day, default) or hour (interval=hour, ranges up to 31 days) in
tz — for charts. Accepts from, to, tz, preset (default last30, or today for hours), metrics,
filters, offer_id, affiliate_id.
curl "https://app.trackcrown.com/api/v1/reports/timeseries?preset=last7&metrics=clicks,payout" -H "Authorization: Bearer $ATK"{
"data": [
{ "bucket": "2026-10-04", "clicks": 1288, "payout": "160.0000" },
{ "bucket": "2026-10-05", "clicks": 0, "payout": "0.0000" }
],
"interval": "day",
"metrics": ["clicks", "payout"],
"range": { "from": "2026-10-03T18:30:00.000Z", "to": "2026-10-10T18:30:00.000Z", "tz": "Asia/Kolkata" }
}Clicks#
GET /clicks#
The raw click log, newest first. Default range: today in tz; at most 93 days per request (use
reports for longer periods).
curl "https://app.trackcrown.com/api/v1/clicks?preset=today&limit=1000&offer_id=12" -H "Authorization: Bearer $ATK"{
"data": [
{
"click_id": "0192a6c3f1e04b7e9c2d8a1f3b5c7d9e",
"ts": "2026-10-10T08:15:30.123Z",
"link_type": "transparent",
"status": "redirect",
"status_reason": "",
"offer_id": 12,
"offer_label": "Summer Sale — US",
"affiliate_id": 7,
"affiliate_label": "Acme Media",
"smart_link_id": 0,
"is_unique": true,
"is_bot": false,
"is_datacenter": false,
"country": "US",
"city": "San Jose",
"device_type": "mobile",
"os": "Android",
"browser": "Chrome",
"traffic_source": "google",
"sub1": "campaign-a",
"sub2": "",
"source_id": "",
"gclid": "Cj0KCQjw…",
"ext_campaign_id": "123456789",
"ext_keyword": "running shoes",
"domain": "trk.example.com",
"destination": "https://shop.example.com/summer?cid=0192a6c3f1e04b7e9c2d8a1f3b5c7d9e"
}
],
"next_cursor": "MTc5MTYyNDUzMDEyMzowMTkyYTZjM2YxZTA0YjdlOWMyZDhhMWYzYjVjN2Q5ZQ",
"range": { "from": "2026-10-09T18:30:00.000Z", "to": "2026-10-10T18:30:00.000Z", "tz": "Asia/Kolkata" }
}Partner keys never receive destination (the offer's landing page). Advertiser keys never receive partner sub
IDs, source_id, smart_link_id or partner names.
GET /clicks?gclid=…#
Find the clicks that carried a Google click identifier — for offline-conversion reconciliation or to join a
parallel-tracking click. Pass one of gclid, gbraid or wbraid (1–512 URL-safe characters) and an explicit
from (and optionally to); the range may span at most 90 days. limit: default 100, max 1,000. No cursor.
curl "https://app.trackcrown.com/api/v1/clicks?gclid=Cj0KCQjw8eOLBhC1ARIsAOzx5cG&from=2026-09-15" -H "Authorization: Bearer $ATK"{
"data": [
{ "click_id": "0192a6c3f1e04b7e9c2d8a1f3b5c7d9e", "ts": "2026-10-10T08:15:30.123Z", "offer_id": 12, "affiliate_id": 7,
"gclid": "Cj0KCQjw8eOLBhC1ARIsAOzx5cG", "gbraid": "", "wbraid": "", "traffic_source": "google",
"link_type": "transparent", "domain": "trackcrown.com" }
],
"next_cursor": null,
"click_ids": ["0192a6c3f1e04b7e9c2d8a1f3b5c7d9e"],
"range": { "from": "2026-09-14T18:30:00.000Z", "to": "2026-10-12T18:30:00.000Z", "tz": "Asia/Kolkata" }
}Without from the request fails with 400 invalid_parameter. Partner and advertiser keys only find their own clicks.
GET /clicks/{click_id}#
Every stored column of one click (IP address and fraud flags for staff keys only), the extra parameters that were
not mapped to a column, and the click's conversions.
curl https://app.trackcrown.com/api/v1/clicks/0192a6c3f1e04b7e9c2d8a1f3b5c7d9e -H "Authorization: Bearer $ATK"{
"data": {
"click": { "click_id": "0192a6c3f1e04b7e9c2d8a1f3b5c7d9e", "ts": "2026-10-10T08:15:30.123Z", "offer_id": 12, "affiliate_id": 7,
"country": "US", "device_type": "mobile", "gclid": "Cj0KCQjw…", "…": "…" },
"extra": { "utm_source": "google" },
"offer": { "id": 12, "label": "Summer Sale — US", "sub": "Kx7Lm2Q" },
"affiliate": { "id": 7, "label": "Acme Media", "sub": "Pq3Rt8z" },
"conversions": [
{ "id": "8a6a2d0e-3c55-4c7e-9a43-0c1c2d8f0b11", "conv_ts": "2026-10-10T08:31:02.000Z", "event_code": "default",
"status": "approved", "status_reason": "", "payout": "5.0000", "revenue": "7.0000", "sale_amount": "0.0000",
"currency": "USD", "adv_txid": "ORDER-1001", "method": "s2s", "is_duplicate": false }
]
}
}Conversions#
Conversions are read from the system of record, so status changes are visible immediately (reports catch up within a few seconds).
GET /conversions#
By conversion time, newest first. Default range: last 7 days in tz.
curl "https://app.trackcrown.com/api/v1/conversions?preset=yesterday&status=pending" -H "Authorization: Bearer $ATK"{
"data": [
{
"id": "8a6a2d0e-3c55-4c7e-9a43-0c1c2d8f0b11",
"click_id": "0192a6c3f1e04b7e9c2d8a1f3b5c7d9e",
"offer_id": 12,
"offer_name": "Summer Sale — US",
"affiliate_id": 7,
"affiliate_code": "Pq3Rt8z",
"affiliate_name": "Acme Media",
"advertiser_id": 3,
"smart_link_id": null,
"event_id": 40,
"event_code": "default",
"status": "pending",
"status_reason": "",
"is_duplicate": false,
"revenue": "7.0000",
"payout": "5.0000",
"sale_amount": "0.0000",
"currency": "USD",
"adv_txid": "ORDER-1001",
"method": "s2s",
"click_ts": "2026-10-09T08:15:30.123Z",
"conv_ts": "2026-10-09T08:31:02.000Z",
"domain": "trk.example.com",
"link_type": "transparent",
"sub1": "campaign-a", "sub2": "", "sub3": "", "sub4": "", "sub5": "",
"source_id": "",
"traffic_source": "google",
"gclid": "Cj0KCQjw…", "gbraid": "", "wbraid": "", "fbclid": "",
"ext_campaign_id": "123456789", "ext_adgroup_id": "", "ext_ad_id": "", "ext_keyword": "running shoes", "ext_placement": "",
"country": "US", "region": "CA", "city": "San Jose",
"device_type": "mobile", "os": "Android", "browser": "Chrome",
"conv_ip": "198.51.100.20",
"params": { "adv1": "blue" },
"notes": "",
"created_at": "2026-10-09T08:31:02.000Z",
"updated_at": "2026-10-09T08:31:02.000Z"
}
],
"next_cursor": null,
"range": { "from": "2026-10-08T18:30:00.000Z", "to": "2026-10-09T18:30:00.000Z", "tz": "Asia/Kolkata" }
}Partner keys only see their own conversions of non-private events, without revenue, advertiser_id,
adv_txid, params, notes or conv_ip. Advertiser keys only see conversions of their offers, without payout,
partner names, sub IDs, source_id, conv_ip or notes.
GET /conversions/{id}#
One conversion by UUID, same shape and visibility rules.
POST /conversions#
Admin keys. Records a conversion by hand (method api). Payout and revenue are resolved exactly like an S2S
postback (custom payouts, event terms, percentages of sale_amount) unless you override them; an approved
conversion enqueues the partner's postbacks.
curl -X POST https://app.trackcrown.com/api/v1/conversions \
-H "Authorization: Bearer $ATK" -H "Content-Type: application/json" \
-d '{"offer_id": 12, "affiliate_id": 7, "event": "sale", "sale_amount": "200", "adv_txid": "ORDER-1001", "notes": "Phone order"}'Returns 201 with the conversion.
PATCH /conversions/{id}#
Admin keys. Approve, reject or pend one conversion: {"status": "rejected", "reason": "fraud"}. Approving enqueues
the partner postbacks that have not fired for this conversion yet; rejecting an approved conversion enqueues the
fire_on: reversal postbacks (once per conversion, with {old_status}, {old_payout}, … and {payout_delta}) and
the postbacks whose statuses include rejected. Duplicates can only be rejected. See
Reversals.
curl -X PATCH https://app.trackcrown.com/api/v1/conversions/8a6a2d0e-3c55-4c7e-9a43-0c1c2d8f0b11 \
-H "Authorization: Bearer $ATK" -H "Content-Type: application/json" \
-d '{"status": "approved"}'PATCH /conversions#
Admin keys. The same for up to 500 conversions at once:
curl -X PATCH https://app.trackcrown.com/api/v1/conversions \
-H "Authorization: Bearer $ATK" -H "Content-Type: application/json" \
-d '{"ids": ["8a6a2d0e-3c55-4c7e-9a43-0c1c2d8f0b11", "1f0e…"], "status": "rejected", "reason": "fraud"}'{
"data": {
"updated": [ { "id": "8a6a2d0e-3c55-4c7e-9a43-0c1c2d8f0b11", "status": "rejected", "status_reason": "fraud" } ],
"not_found": ["1f0e…"],
"skipped_duplicates": 0
}
}Postbacks#
Outgoing partner postbacks and pixels (see Postback macros for {payout}, {sub1}, …).
- Partner keys manage their own postbacks:
affiliate_idis always their account (omit it), offers must be ones they can run, and private events are not available. - Admin keys manage every postback of the workspace;
affiliate_id: nullfires for every partner's conversions. Analyst keys can read them. Advertiser keys have no access. - Conversion-API destinations (Meta, TikTok, Microsoft UET) are not part of these endpoints; manage them in the
panel (Meta Conversions API).
fire_onacceptsapproved,anyandreversal.
curl -X POST https://app.trackcrown.com/api/v1/postbacks \
-H "Authorization: Bearer $ATK" -H "Content-Type: application/json" \
-d '{"offer_id": 12, "url": "https://tracker.example.net/postback?cid={sub1}&payout={payout}&status={status}"}'{
"data": {
"id": 31,
"affiliate_id": 7,
"offer_id": 12,
"event_code": null,
"kind": "s2s",
"method": "GET",
"url": "https://tracker.example.net/postback?cid={sub1}&payout={payout}&status={status}",
"body": "",
"fire_on": "approved",
"status": "active",
"created_by_affiliate": true,
"created_at": "2026-10-10T08:15:30.123Z",
"updated_at": "2026-10-10T08:15:30.123Z"
}
}Tracking links#
GET /tracking-link#
Builds a link for an offer. Nothing is stored. The host is the tracking domain assigned to the partner and offer
(Tracking domains → Assignments: partner + offer, then partner, then offer), else the workspace default, unless
you pass host.
When the network forces a traffic-source template on the partner (Partner program → Traffic sources), its sub-ID and
source_id values replace the requested ones.
curl "https://app.trackcrown.com/api/v1/tracking-link?offer=Kx7Lm2Q&affiliate=Pq3Rt8z&sub1=campaign-a" -H "Authorization: Bearer $ATK"{
"data": {
"type": "affiliate",
"url": "https://trackcrown.com/r/Kx7Lm2Q/Pq3Rt8z?sub1=campaign-a",
"host": "trackcrown.com",
"offer": { "id": 12, "code": "Kx7Lm2Q", "name": "Summer Sale — US" },
"affiliate": { "id": 7, "code": "Pq3Rt8z" },
"warnings": []
}
}A transparent tracking template for Google Ads:
curl "https://app.trackcrown.com/api/v1/tracking-link?offer=Kx7Lm2Q&affiliate=Pq3Rt8z&type=transparent" -H "Authorization: Bearer $ATK"{
"data": {
"type": "transparent",
"url": "https://trackcrown.com/c/Kx7Lm2Q-Pq3Rt8z?gclid={gclid}&campaignid={campaignid}&adgroupid={adgroupid}&creative={creative}&keyword={keyword}&matchtype={matchtype}&network={network}&device={device}&placement={placement}&loc_physical_ms={loc_physical_ms}&targetid={targetid}&feeditemid={feeditemid}&extensionid={extensionid}&assetgroupid={assetgroupid}&loc_interest_ms={loc_interest_ms}&devicemodel={devicemodel}&target={target}&adtype={adtype}&merchant_id={merchant_id}&product_id={product_id}&url={lpurl}",
"host": "trackcrown.com",
"offer": { "id": 12, "code": "Kx7Lm2Q", "name": "Summer Sale — US" },
"affiliate": { "id": 7, "code": "Pq3Rt8z" },
"link_key": "Kx7Lm2Q-Pq3Rt8z",
"google_ads": {
"tracking_template": "https://trackcrown.com/c/Kx7Lm2Q-Pq3Rt8z?gclid={gclid}&…&url={lpurl}",
"certified": false,
"cert_status": "applied",
"final_url_suffix": "gclid={gclid}&campaignid={campaignid}&…&product_id={product_id}"
},
"warnings": ["Not yet certified by Google: new Google Ads accounts may only use certified trackers. Use Final URL suffix + SDK mode."]
}
}google_ads is present only when url is {lpurl}. The template contains no force_transparent parameter and every
core ValueTrack tag; trim it to the tags your campaign type fills, or build it in the panel's
template builder. The certification warning appears whenever google is
on and the domain is not certified.
For staff keys warnings also explains why clicks would currently go to the fallback (offer not active, partner not
active or not approved for a non-public offer). Partner keys get 403 not_approved until they may run the offer, and
404 for offers they cannot see. Advertiser keys cannot build links (403 forbidden). Without an active tracking
domain the answer is 409 no_tracking_domain.
Deals & product feeds#
GET /deals#
Coupons and promotions of advertisers. Partner keys: active deals inside their start/end dates, of offers the
partner can run, plus advertiser-wide deals. Advertiser keys: their own deals. Staff keys (advertisers.read): every
deal. Fields: id, advertiser_id, advertiser, offer_id, offer_name, title, description, coupon_code,
landing_url, starts_at, ends_at, status, updated_at. Partner keys get the same fields without
advertiser_id, status and updated_at.
curl "https://app.trackcrown.com/api/v1/deals" -H "Authorization: Bearer $ATK"GET /product-feeds#
Product catalogues (csv, tsv, xml, json) for product-level links, scoped like /deals. Fields: id,
advertiser_id, advertiser, offer_id, offer_name, name, feed_url, format, status, description,
updated_at (partner keys: without advertiser_id, status and updated_at).
Both return the whole list in one response (next_cursor is null).
Google Ads#
POST /google-ads/lint#
Static check of a Google Ads or Microsoft Advertising tracking template, final URL and Final URL suffix — the same
linter as the panel's template builder. Staff keys (admin or analyst). Body: template, final_url, suffix,
platform (google | microsoft), allow_uncertified. At least one of template and suffix is required.
curl -X POST https://app.trackcrown.com/api/v1/google-ads/lint \
-H "Authorization: Bearer $ATK" -H "Content-Type: application/json" \
-d '{"template":"https://trackcrown.com/c/demo?gclid={gclid}&force_transparent=true&url={lpurl}","final_url":"https://shop.example.com/"}'The response {"data": {"ok": …, "template": {"ok", "host", "length", "tags", "issues"}, "suffix": [issues]}} lists
issues as {code, severity, message, hint?. Every code is explained in
Template linter, simulator and tester.