Integrating ToroAds: API, Postbacks and Server-to-Server Tracking

A developer's guide to the three integration points that matter: outgoing postbacks so your systems learn about conversions in real time, the offer feed API for building your own offerwall, and the read-only reporting API for pulling your numbers into your own dashboard.

Integrating ToroAds: API, Postbacks and Server-to-Server Tracking
A
Admin
Published August 4, 2026

If you are running paid traffic, building your own offerwall, or feeding conversion data into an internal dashboard, the browser is the wrong place to do it. Pixels get blocked, cleared, and fired twice. A server-to-server callback does not.

This is the developer-facing guide to the three integration points on ToroAds: outgoing postbacks, the offer feed API, and the reporting API. It assumes you can make an HTTP request and read JSON.

Why server-to-server

A conversion happens on the advertiser's infrastructure, minutes or hours after your visitor left your page. There is no browser session left to fire a pixel from, which is why client-side conversion tracking in affiliate marketing has always been a compromise.

Server-to-server tracking removes the browser from the loop entirely. The platform makes an HTTP request to a URL you control, from a server, carrying the parameters you asked for. It works with ad blockers, with cookie restrictions, on mobile apps, and hours after the fact.

If you buy traffic and do not send postbacks, you are optimising on yesterday's export. Your ad platform cannot learn which creative produced revenue unless something tells it.

Integration 1: outgoing postbacks

This is the one most publishers need and the one that takes the least work.

You configure a postback URL per SmartLink and per app placement. When a conversion is approved and credited, the platform fires a request to that URL with the parameters you embedded in it. Your endpoint records it, forwards it to your ad platform, or both.

A postback URL is just a URL with placeholders:

https://your-server.com/toroads/conversion
  ?sub_id={sub_id}
  &offer={offer_id}
  &payout={payout}
  &country={country}
  &txid={transaction_id}

Four rules for the receiving endpoint:

Respond fast, process later. Return 200 immediately and push the work onto a queue. A slow endpoint gets retried, and retries are how duplicates enter your data.

Deduplicate on the transaction identifier. Treat the conversion ID as the idempotency key and store it with a unique constraint. Assume every callback can arrive more than once, because eventually one will.

Accept out-of-order arrivals. A conversion released from review can arrive after a conversion that happened later. Order by the timestamp in the payload, not by the order you received things.

Log the raw request before parsing it. When something disagrees three weeks from now, the raw log is the only artefact that settles it.

The single most valuable field is your sub-ID, covered below.

Integration 2: the offer feed API

Use this when you are building your own offerwall UI rather than embedding the hosted one, or when you want offers rendered natively inside your app.

Authentication is a per-app API key, issued once your app's API access is approved, passed as a query parameter. There are three versions; v2 returns offerwall offers and v3 returns content-locker offers, both with cleaner payloads than v1.

curl "https://toroads.com/api/v2/offers/{app_id}/{user_id}\
?api=APP_API_KEY&country_code=US&platform=android"

The path carries your app placement ID and your own end-user identifier, which is what conversions are attributed to later. Optional query parameters let you pass the end-user IP (the country is resolved from it), or set the country and platform explicitly, and filter by offer type.

The response is a list of offers already filtered by country, device and your app's configuration:

{
  "offers": [
    {
      "id": 1234,
      "name": "Play Game X, reach level 10",
      "description": "Install and reach level 10 within 7 days.",
      "image": "https://cdn.example.com/offers/1234.png",
      "offer_type": "CPI",
      "payout": "2.40",
      "countries": ["US", "CA", "GB"]
    }
  ]
}

Two things to note. Offers are addressed by internal ID; the upstream provider and their offer ID are never exposed, so you cannot accidentally leak your supply chain to a competitor through your own frontend. And the user_id you pass is the attribution key: it must be stable across reinstalls and it must not be user-editable, or you will be granting rewards to the wrong accounts.

Public resources such as content lockers and SmartLinks are addressed by UUID rather than sequential ID, so nothing about your account volume is inferable from a URL.

Integration 3: the reporting API

Read-only, GET only, and strictly self-scoped: results always describe the token's owner, and there is no parameter that lets a token read somebody else's numbers.

Authentication is a Sanctum bearer token minted on your API Tokens page, and it needs the read ability, which new tokens get by default.

curl -H "Authorization: Bearer <token>" \
     -H "Accept: application/json" \
     "https://toroads.com/api/v1/reports/summary?from=2026-07-12&to=2026-07-18"

Two endpoints are available. reports/summary returns range totals, and reports/daily returns the same metrics broken down per day, zero-filled so missing days do not silently vanish from a chart.

{
  "summary": {
    "from": "2026-07-12",
    "to": "2026-07-18",
    "timezone": "UTC",
    "clicks": 1234,
    "leads": 56,
    "earnings": "78.90",
    "epc": "0.0639",
    "unlocks": 41
  }
}

Three constraints worth designing around:

  • Days are UTC, running 00:00 to 24:00, matching the "today" shown across the dashboard. If your internal reporting uses local days, convert deliberately rather than assuming they line up.
  • The maximum range is 92 days per request. Paginate longer backfills.
  • Rate limits apply, defaulting to 60 requests per minute per publisher. Cache aggressively; these numbers do not change fast enough to justify polling every second.

Also note that leads counts approved, credited conversions. Held conversions are not in it, which is the correct behaviour for a revenue report and a common source of confusion when comparing against a raw conversion count.

Sub-IDs: get this right first

Everything above becomes more useful if your sub-ID discipline is good, and close to useless if it is not.

A sub-ID is a value you attach to a click that flows through to the conversion and comes back in your postback. Whatever you put in it is what you will be able to segment by later.

Put something structured in it. A single opaque identifier that maps to a row in your own database beats a human-readable string, because you can attach as many attributes to that row as you want without changing the link:

https://toroads.com/sl/{uuid}?sub_id=a7f3c1

where a7f3c1 is a key in your own table holding the campaign, creative, placement, geo group and cost. When the postback arrives with sub_id=a7f3c1, you have everything.

Publishers who do this from day one can answer "which creative was profitable" in month two. Publishers who do not spend that month rebuilding history they never recorded.

Handling reversals

Conversions can be reversed after being credited: an advertiser charges back, or a review concludes against it.

If your system pays out to your own users, this matters a great deal. Decide your policy before launch, not after your first reversal:

  • Claw back the user's reward and accept the support load
  • Absorb the loss and treat it as a cost of doing business
  • Hold user rewards for a short window before releasing them

Any of the three is defensible. What is not defensible is having no policy and improvising per user, which is how reward economies lose credibility.

Handle the reversal path on day one. It is a few hours of work at the start and a reconciliation project later.

Security expectations

The platform's side is already covered: postback callbacks are authenticated per provider, inbound source IPs can be restricted per traffic source, rate limits apply to clicks, postbacks and reports, and visitor context arriving from the edge is signed so it cannot be forged in transit.

Your side needs three things:

Verify the request. Use a secret path segment or a shared token in your postback URL and reject anything that does not match. An unauthenticated conversion endpoint is a public API for inflating your own numbers, and somebody will find it.

Never trust the client for money. Rewards are granted by your server, after your server receives the callback. Not by the app, not by the WebView, not by a JavaScript success handler.

Keep tokens server-side. API keys and bearer tokens belong in your backend. A key shipped in a mobile binary is a key that will be extracted.

Reconciling your numbers with the platform's

Two systems counting the same events will eventually disagree, and the useful question is not whether they diverge but by how much and in which direction.

Compare weekly, not daily, and compare the same definition on both sides. The most common false alarm is counting held conversions on your side against credited conversions on the platform's; those are supposed to differ, and the gap is exactly your review pipeline.

If a real discrepancy appears, the raw postback log settles it in minutes. That is the entire reason to keep one.

A testing checklist

Before you call an integration finished:

  1. Fire a duplicate postback and confirm your endpoint records one conversion, not two.
  2. Fire an out-of-order pair and confirm your ordering logic holds.
  3. Take your endpoint down for a minute and confirm nothing is lost permanently.
  4. Confirm your sub-ID survives the full round trip from click to postback.
  5. Compare a week of your own totals against the reporting API and reconcile any gap before it becomes a habit.
  6. Reset a test device and confirm your user identifier does not change.

Start building

The API documentation is available inside the dashboard, and API access for app placements is enabled on request.

Create your ToroAds account to generate a token, or read the offerwall guide if you are integrating rewarded offers into an app. Questions about a specific integration are best sent through the contact page.

Related Articles

Continue reading from the ToroAds blog.

Ready to put these strategies to work? Start earning with ToroAds