Skip to content

REST API overview

The official SDKs implement this API for you. Use it directly to build a client for another platform, to write integration tests, or to debug what the SDK sends. A machine-readable description is available as OpenAPI 3.1.

Base URL https://ads.qartvelo.com/api/v1
Format JSON request and response bodies, Content-Type: application/json
Methods All endpoints are POST
Authentication The public app key plus a session token; no cookies, no API keys
Caching Responses carry Cache-Control: no-store, private
Endpoint Purpose
POST /sdk/initialize Validate app key + package name, get a session token and the remote configuration
POST /ads/request Get an ad for a placement, or an explicit no-fill with the fallback to use
POST /events/impression Record (and bill) one impression
POST /events/click Record one click for an accepted impression
POST /events/reward Record the rewarded outcome, exactly once
POST /events/fallback Telemetry: the client fell back to another network
initialize ──> session_token (1 h) + config
│
ads/request (placement, format, session_token) ──> fill: request_id + ad.impression_token
│ └─> no_fill: fallback = admob | none
impression (request_id, impression_token) once, while the ad is valid (30 min)
click (request_id, impression_token) at most once, after the impression
reward (request_id, impression_token, completion) rewarded placements only
  • Timestamps are ISO-8601 UTC with Z, for example 2026-10-07T18:40:00Z.

  • Public ids are prefixed strings: campaign cmp_12, creative cr_34, ad ad_3f2a9c01d4e5b6a7, request req_01k9....

  • Session and impression tokens are opaque. Do not parse, modify or log them; pass them back verbatim.

  • Money never reaches the client.

  • Compress responses at the edge; keep HTTP keep-alive enabled. The SDKs use a single connection pool.

  • Errors use one envelope, except event rejections (see Errors and limits):

    {"error":{"code":"placement_not_found","message":"Placement [game_end] does not exist in this app."}}

Every call below runs in test mode, so nothing is billed. Replace the app key and package with yours.

Terminal window
B=https://ads.qartvelo.com/api/v1
KEY=app_xxxxxxxxxxxxxxxxxxxxxxxx
PKG=com.example.app
# 1. Initialize in test mode
S=$(curl -s -X POST $B/sdk/initialize -H 'Content-Type: application/json' \
-d "{\"app_key\":\"$KEY\",\"package_name\":\"$PKG\",\"platform\":\"android\",\"test_mode\":true}" \
| jq -r .session_token)
# 2. Request an interstitial
AD=$(curl -s -X POST $B/ads/request -H 'Content-Type: application/json' \
-d "{\"app_key\":\"$KEY\",\"placement\":\"game_end\",\"format\":\"interstitial\",\"session_token\":\"$S\",\"test_mode\":true,\"screen_width\":1080,\"screen_height\":2400}")
echo "$AD" | jq .
RID=$(echo "$AD" | jq -r .request_id); TOK=$(echo "$AD" | jq -r .ad.impression_token)
# 3. Impression, then a click at least one second later
curl -s -X POST $B/events/impression -H 'Content-Type: application/json' \
-d "{\"request_id\":\"$RID\",\"impression_token\":\"$TOK\"}"
sleep 1
curl -s -X POST $B/events/click -H 'Content-Type: application/json' \
-d "{\"request_id\":\"$RID\",\"impression_token\":\"$TOK\"}"
# 4. A replay is rejected: {"status":"rejected","reason":"duplicate"} (HTTP 409)
curl -s -X POST $B/events/impression -H 'Content-Type: application/json' \
-d "{\"request_id\":\"$RID\",\"impression_token\":\"$TOK\"}"
# 5. Force a no-fill to exercise the fallback path
curl -s -X POST $B/ads/request -H 'Content-Type: application/json' \
-d "{\"app_key\":\"$KEY\",\"placement\":\"game_end\",\"format\":\"interstitial\",\"session_token\":\"$S\",\"test_mode\":true,\"test_force_no_fill\":true}"
# {"status":"no_fill","request_id":"req_...","fallback":"admob","reason":"test_no_fill"}

A custom client must behave like the SDKs to keep traffic valid:

  • Send the impression only when the creative is actually on screen, once, and before the ad’s expires_at.
  • Send a click only after a user tap, at most once per impression, and not within one second of the impression.
  • Send a reward event only for rewarded placements, once, with the real completion state; grant the reward only on completion.
  • Treat every rejected event response as final; retry only network errors, 5xx, 408 and 429 (honour Retry-After).
  • Never show an ad after expires_at, and do not reuse a request_id or token.
  • Initialize again when a call returns session_expired or invalid_session.