Ad Request API
Requests ads for a zone in real time. The endpoints are prefixed with /ad and require no authentication.
Prefer the SDK
The JS Ad SDK and the native SDKs call this API for you, including impression and click tracking. This page is for integrators who call it directly.
Before requesting, create a zone in the publisher console and get its zone_key (of the form zone_ab12cd34); see Publisher API · Zones.
Request an ad
GET https://aapi.adbnk.co/ad/request or POST https://aapi.adbnk.co/ad/request
Parameters can be sent as a query string, a JSON body or a form body.
| Param | Type | Required | Description |
|---|---|---|---|
zone | string | Yes* | Zone code zone_key |
zone_id | int | Yes* | Zone numeric ID (takes precedence if both are sent) |
limit | int | No | Number of ads to return, 1–5, default 1 (other values fall back to 1) |
page_url | string | No | URL of the page hosting the ad |
page_title | string | No | Page title |
page_keywords | string | No | Page keywords |
page_category | string | No | Page category |
page_type | string | No | Page type (article/video/product, etc.) |
page_tags | string | No | Page tags, comma-separated |
page_lang | string | No | Page language; also selects the language of the rendered html |
keywords | string / string[] | No | Extra content keywords |
content_url | string | No | Content URL |
* One of zone or zone_id is required.
Privacy signals (all optional; send them whenever you have them):
| Param | Type | Description |
|---|---|---|
gdpr | 0 / 1 | Whether GDPR applies |
gdpr_consent | string | IAB TCF v2 consent string |
us_privacy | string | IAB US Privacy (CCPA) string |
gpp / gpp_sid | string | IAB GPP string / applicable section IDs |
npa | 0 / 1 | 1 = non-personalized ads only |
tag_for_child_directed | 0 / 1 | Child-directed treatment |
tag_for_under_age | 0 / 1 | Under the age of consent |
Device data is collected automatically by the ADBNK SDKs. For the best fill and measurement, integrate through an SDK.
A path form is also supported: GET / POST /ad/request/{zone_key} (the zone_ prefix may be omitted).
curl "https://aapi.adbnk.co/ad/request?zone=zone_ab12cd34&limit=1&page_url=https%3A%2F%2Fblog.example.com%2Fpost%2F1"Impressions and clicks are measured by the SDK; a request on its own is not billable.
Multiple zones in one request
POST a JSON body with a zones array, each entry carrying zone_key or zone_id (the other parameters above apply to all zones):
{ "zones": [ { "zone_key": "zone_ab12cd34" }, { "zone_id": 6 } ], "page_url": "https://blog.example.com/post/1" }The response is data: { "batch": true, "results": [ ... ] }. Each result is a zone block shaped like a single-zone data (below), plus zone_key and zone_id. A zone that could not be served has ads: [] and an error string (zone_not_found, zone_unavailable, or another value; treat any error as a no-fill for that zone).
Response structure
{
"code": 0,
"message": "success",
"data": {
"schema_version": 2,
"min_sdk_version": "1.0.0",
"capabilities": ["deeplink", "mraid", "native_obj"],
"request_id": "req_8f3a2c9d1e7b",
"zone": {
"id": 5,
"code": "zone_ab12cd34",
"width": 300,
"height": 250,
"type": "BANNER",
"device": "ALL",
"refresh": 0
},
"ads": [
{
"id": "q1w2e3r4t5y6...",
"ad_id": 1001,
"creative_id": 2001,
"campaign_id": 3001,
"zone_id": 4001,
"type": "IMAGE",
"title": "Summer Sale",
"description": "Up to 50% off",
"button_text": "Shop Now",
"brand_name": "Example Shop",
"image_url": "https://imgs.abnk-res.top/creatives/1.jpg",
"image_url_2": "",
"video_url": "",
"icon_url": "",
"display_url": "example.com",
"landing_url": "https://example.com/sale",
"click_url": "https://track.adbnk.co/track/click/q1w2e3r4t5y6...",
"deeplink": null,
"fallback_url": null,
"impression_url": "https://track.adbnk.co/track/impression/q1w2e3r4t5y6...",
"width": 300,
"height": 250,
"html": "<!DOCTYPE html>...<span class=\"ad-badge\">AD</span>..."
}
]
},
"timestamp": 1752200000
}| Field | Description |
|---|---|
schema_version | Response schema version (currently 2). New fields are added without bumping it — ignore fields you don't recognize. |
min_sdk_version | Oldest SDK version that understands this response |
capabilities | Capabilities supported by this response (deeplink, mraid, native_obj) |
request_id | Request identifier; include it when contacting support |
zone | Zone config, see Zone object |
ads | Ads to display; empty on a no-fill |
data may contain other fields not listed here; ignore them.
No fill
When no ad is available, code is still 0 and data.ads is an empty array; check ads, not message. Web (non-app) requests may also get a retry hint in data.retry:
"retry": { "after_ms": 30000, "max": 1 }Wait at least after_ms milliseconds before requesting again, and retry at most max times (0 = don't retry).
Errors
code | message_key | Meaning |
|---|---|---|
400 | error.ad.zone_param_missing | Neither zone nor zone_id was sent |
404 | error.ad.zone_not_found | Zone does not exist |
403 | error.ad.zone_unavailable | Zone is disabled or not yet approved |
500 | error.internal | Server error; try again later |
Error responses have data: null. Decide success or failure from the code field in the body (0 = success). The HTTP status may be 200 even on error. message is human-readable text that may be localized; match on message_key. Treat any non-JSON or 5xx response as a temporary no-fill.
Creative structure
Each item in ads[] is one displayable ad. Fields without a value are null, an empty string, or omitted. An ad may carry other fields not listed here; ignore them.
| Field | Type | Description |
|---|---|---|
id | string | Opaque ad identifier. Don't parse it. |
ad_id / creative_id / campaign_id / zone_id | int | Numeric IDs, for your own logging and reporting |
type | string | Creative type, e.g. IMAGE / NATIVE / VIDEO / RICH_MEDIA. More may be added; skip types you can't display. |
title / description | string | Headline / description copy |
button_text | string | Call-to-action text |
brand_name | string | Brand name |
image_url / image_url_2 | string | Image URLs |
video_url | string | Video URL |
icon_url | string | Icon URL |
display_url | string | Display URL shown to users |
landing_url | string | Advertiser landing page, for display only. It may be null. Don't send users here directly. |
click_url | string | Click URL. Open it when the user clicks; it redirects to the landing page. Use it at most once per click. |
deeplink | string | App deep link to try first (when present) |
fallback_url | string | Where to go if the deep link fails to open (only present together with deeplink) |
impression_url | string | Impression tracking URL |
width / height | int | Creative size |
html | string | Fully rendered ad HTML, ready to display in an iframe/WebView |
native | object | Structured assets of a NATIVE ad (see below) |
html_content | string | Rendered template content of a RICH_MEDIA ad, for WebView display (when present) |
native object: title, description, sponsor, cta_text, icon (URL), image (URL), rating (1–5), price, likes. Any of them may be null.
Clicks with a deep link: request click_url, then try deeplink. If the deep link doesn't open, go to fallback_url, else landing_url, else the page click_url redirected to.
Impression and click tracking
Use impression_url and click_url exactly as returned: don't modify, prefetch or replay them. The SDK handles impression and click measurement. See Events & Conversion Reporting.
Zone object
data.zone always has id, code, width, height, type, device (PC / MOBILE / ALL) and refresh (auto-refresh interval in seconds, 0 = off). Some zone types also carry display settings (trigger, frequency, close button, etc.) configured in the publisher console; the SDK applies them, so direct integrators can ignore them.
VAST video ads
GET https://aapi.adbnk.co/ad/render/vast/{zone_key}
Returns VAST XML for VAST-capable video players. Version 3.0 is returned by default; add vast=4 for VAST 4.2. When there is no ad, an empty <VAST> document is returned. Get the ready-to-use VAST tag for a video zone from the publisher console ("Get code"). For pre-/mid-/post-roll scheduling, copy the VMAP tag from the same place.
| Param | Description |
|---|---|
vast | 4 = VAST 4.2 (default 3.0) |
skip | 1 = make the linear ad skippable |
linear / nonlinear / companion | 0 = leave that creative type out |
Rewarded ads
When the user finishes a rewarded ad, the SDK notifies your page so you can grant the reward:
<script>
// Either define a global handler…
window.onAdbnkReward = function (reward) {
// reward.zoneId, reward.userId, reward.customData, reward.rewardAmount,
// reward.rewardType, reward.transactionId, reward.timestamp,
// reward.signature, reward.keyId (send these to your server to check the reward)
}
// …or listen for the event
document.addEventListener('adbnk:reward', function (e) { /* e.detail has the same fields */ })
</script>- Put
data-reward-user-id(and optionallydata-reward-custom-data) on the rewarded zone tag — the console's "Get code" already includes them; they are passed back to you unchanged. - Grant each
transactionIdat most once. - Only grant rewards for callbacks that include a
transactionId. - Custom data can be up to 500 characters. A longer value is rejected with
400and no reward is issued. A user id longer than 255 characters is cut to 255.
When the reward is confirmed, adbnk:reward / onAdbnkReward also carry verified: true, adId, requestId and signedFieldsComplete. All id fields (zoneId, adId, requestId, transactionId, keyId) are strings. signedFieldsComplete: false means some fields were filled in from the values sent by the page rather than returned by our server; fields with no such value (for example rewardAmount, rewardType or timestamp) may then be absent.
If the reward could not be confirmed in the browser, the SDK does not fire adbnk:reward. It fires adbnk:reward_unverified (and calls window.onAdbnkRewardUnverified if you define it) instead, with detail { zoneId, verified: false, transactionId: null, reason, timestamp, code, message, retryable } (plus requestId when known). reason is unverified or not_eligible and is kept for compatibility only; use code (see Error codes). timestamp is the browser time in milliseconds. Each shown ad fires at most one of the two events.
Neither event is proof of a reward
adbnk:reward_unverified never means a reward, and adbnk:reward is only a claim from the browser. Grant anything of value only from the server-side callback (SSV) or after checking the reward on your server (below).
Check a reward on your server
Before you grant anything of value, check the reward on your server. Send the transactionId, signature and keyId from the reward to your server, and call this endpoint from there:
POST https://api.adbnk.co/ad/reward/verify
This endpoint is on the platform API host api.adbnk.co, not on the ad request host used above.
| Param | Type | Required | Description |
|---|---|---|---|
transaction_id | string | Yes | transactionId from the reward |
signature | string | Yes | signature from the reward, unchanged |
key_id | string | No | keyId from the reward. Recommended: see the failure rules below |
Request body (JSON):
{ "transaction_id": "rt_9f2c…", "signature": "…", "key_id": "…" }When the reward is genuine, the response has one of two shapes. Usually the reward is found in our records and the response carries the full record:
{
"code": 0,
"data": {
"valid": true,
"transaction_id": "rt_9f2c…",
"zone_id": "12345",
"ad_id": "…",
"request_id": "…",
"user_id": "u123",
"custom_data": "",
"reward_amount": 10,
"reward_type": "coin",
"issued_at": "2026-10-06T08:15:30Z",
"verified_at": "2026-10-06T08:15:31Z"
}
}In some cases the reward is confirmed by checking the signature instead (this needs key_id). The response then carries only valid and transaction_id:
{ "code": 0, "data": { "valid": true, "transaction_id": "rt_9f2c…" } }Don't assume zone_id, user_id or the other record fields are present.
- The fields come from our record of the reward, exactly as they were signed — not from your request. Use them, not values from the browser.
zone_idis the zone's numeric id, sent as a decimal string. Empty values may be returned as""ornull; treat both as empty.issued_atandverified_atare UTC, ISO 8601, ending inZ.- When you send
key_id, a transaction that doesn't exist and a signature that doesn't match both return{"valid": false, "transaction_id": "…"}, with no other fields; the response doesn't say which check failed. - When you leave out
key_idand the reward can't be matched, the request fails with400("Missing required parameters") instead. Sendkey_idif you want a uniform{"valid": false}answer. - Check that
zone_idanduser_idare the ones you expect, and grant eachtransaction_idonly once: checking the same reward again returnsvalid: trueagain. - A missing
transaction_idorsignaturereturns400.
The reward the SDK receives carries the signed fields zone_id, ad_id, request_id, user_id and custom_data as they were signed, along with transaction_id, signature and key_id. Treat it as a claim until your server has checked it.
Telegram Mini App
Inside a Telegram Mini App, show rewarded and interstitial ads from your code:
window.adbnk.telegram.init({ zoneId: 'zone_xxxxxxxx', userId: 'u123' }).show()
.then(function (result) { /* update your UI; grant rewards from the server callback */ })
.catch(function (e) { /* e.code is a public code such as NO_FILL, USER_DISMISSED or REWARD_UNVERIFIED; e.legacyCode keeps the earlier lowercase name (no_fill, closed, skipped, busy, wrong_format, reward_failed, not_active, destroyed, error) */ })On Telegram zones the server callback also carries tg_user_id (the Telegram user id) when it is available. It is signed like the other parameters: verify the signature over every query parameter except signature, key_id and any parameters that were already in the callback URL you configured — those are not signed. See Telegram Mini App for the full API, error codes and signature verification.
Server-side verification
Server-side signed reward callbacks (SSV) take effect once a callback URL is configured on the rewarded zone. Client-side events are not proof of a reward: adbnk:reward_unverified and the Telegram reward_failed error never mean a reward, and adbnk:reward is only a claim from the browser. Grant rewards only from the SSV callback or after a successful server-side check with POST https://api.adbnk.co/ad/reward/verify (Check a reward on your server) — with or without a callback URL.