Submit the plays an exchange says it served
POST /api/v1/plays/claims
https://app.tanba-ooh.kz/api/v1/plays/claims
Scope write:plays. Adtech organisations only (the administrator of an ad platform); a console session works too. The body is JSON, an object with a rows array, at most 5 MB or 50 000 rows.
A claim is what the platform says it served. The registry is not in the bid path and holds no order: it only checks the claim against the plays the players proved (see GET /api/v1/plays/claims/verification). Claims are kept apart from the plays of the players and are never billed.
Every row names a structure (structure_id or structure_code, not both), an approval (approval_number) or a creative file (creative_sha256, not both), a whole hour and the number of plays in that hour. deal_id and seller_account_id (your account on the exchange, as in source.schain) are optional. A row is accepted only when the operator of the structure has authorised your organisation, and that account when named, to sell it on that day. A row is stored under (organisation, structure, approval, hour, deal); sending it again replaces the earlier value. Rows are judged one by one and the accepted rows are stored even when others are refused. Reasons:
| Reason | Meaning |
|---|---|
structure_missing, structure_ambiguous, structure_not_found | No structure, both forms given, or no such structure. |
approval_missing, approval_ambiguous | Neither an approval nor a file, or both. |
approval_not_found, approval_not_for_structure | No signed approval with that number, or it does not cover the structure. |
creative_not_found, creative_ambiguous | No approval with that file for the structure in that hour, or several (name the number). |
seller_not_authorised | The operator has not authorised your organisation (and account) to sell this structure on that day. |
hour_invalid, hour_not_whole, hour_in_future, hour_too_old | Not an ISO 8601 hour, not on the hour, not begun, or begun more than 62 days ago. |
plays_invalid | Not a whole number of at least 0. |
deal_id_invalid, seller_account_invalid | Characters or length not allowed. |
duplicate_row | The same row appeared earlier in this batch. |
Authentication
API key in the Authorization header, or a console session.
Scope: write:plays
Request body
application/json
| Name | Type | Required | Description | Example |
|---|---|---|---|---|
rows | array of object | yes | The claim lines, one for each structure, approval, hour and deal. | |
rows[].structure_id | string (uuid) | Identifier of the structure; give this or structure_code, not both. | "b7e4a2c9-0d1f-4a68-8e35-91c7f2d40b16" | |
rows[].structure_code | string | Code of the structure; give this or structure_id, not both. | "ALM-0012" | |
rows[].approval_number | string | Number of the approval; give this or creative_sha256. | "TNB-2026-000123" | |
rows[].creative_sha256 | string | SHA-256 of the media file; the approval is the one that covers the structure in that hour. | "2419fe2d001c9185b3b903283894a5d955f45a57d1eaf1c6b787759650f00a17" | |
rows[].hour | string | ISO 8601, on the hour; one without an offset is Asia/Almaty time. | "2026-10-06T14:00:00+05:00" | |
rows[].plays | integer | Number of plays the platform says it served in that hour. | 118 | |
rows[].deal_id | string | Deal the plays ran under, characters A-Za-z0-9._:-; part of the identity of the line. | "deal-4411" | |
rows[].seller_account_id | string | Your account on the exchange; it must be one the operator authorised. | "acc-77" |
Example
{
"rows": [
{
"structure_code": "ALM-0012",
"approval_number": "TNB-2026-000123",
"hour": "2026-10-06T14:00:00+05:00",
"plays": 118,
"deal_id": "deal-4411"
},
{
"structure_code": "ALM-0012",
"creative_sha256": "2419fe2d001c9185b3b903283894a5d955f45a57d1eaf1c6b787759650f00a17",
"hour": "2026-10-06T15:00:00+05:00",
"plays": 120
}
]
}
Responses
200 The batch was read; see the rows for what was stored.
application/json
| Name | Type | Required | Description | Example |
|---|---|---|---|---|
batch_id | string (uuid) | yes | Identifier of the batch. | "0b1c3a52-6f0e-4c2e-9d3a-2f5d1e7a9c10" |
received | integer | yes | Number of rows read from the body. | 2 |
accepted | integer | yes | Number of rows stored. | 1 |
refused | integer | yes | Number of rows refused. | 1 |
rows | array of object | yes | One entry for each row, in the order of the body. | |
rows[].row | integer | yes | Position in the body, from 1. | 1 |
rows[].status | string | yes | Whether the row was stored. accepted, refused | |
rows[].reason | string | Present on refused rows. | "seller_not_authorised" |
Example
{
"batch_id": "0b1c3a52-6f0e-4c2e-9d3a-2f5d1e7a9c10",
"received": 2,
"accepted": 1,
"refused": 1,
"rows": [
{
"row": 1,
"status": "accepted"
},
{
"row": 2,
"status": "refused",
"reason": "seller_not_authorised"
}
]
}
Errors
Errors are problem documents (application/problem+json) with a stable code.
| Status | Meaning |
|---|---|
| 400 | An error as a problem document. |
| 401 | No valid session or API key (unauthenticated, session_expired, invalid_api_key). |
| 403 | The role or the key's scope does not allow this (forbidden, key_scope_denied, key_route_denied). |
| 413 | An error as a problem document. |
| 422 | Field errors (validation_failed). |
| default | An error as a problem document. |
Code samples
curl
curl -X POST 'https://app.tanba-ooh.kz/api/v1/plays/claims' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"rows": [
{
"structure_code": "ALM-0012",
"approval_number": "TNB-2026-000123",
"hour": "2026-10-06T14:00:00+05:00",
"plays": 118,
"deal_id": "deal-4411"
},
{
"structure_code": "ALM-0012",
"creative_sha256": "2419fe2d001c9185b3b903283894a5d955f45a57d1eaf1c6b787759650f00a17",
"hour": "2026-10-06T15:00:00+05:00",
"plays": 120
}
]
}'
Python
import requests
response = requests.post(
"https://app.tanba-ooh.kz/api/v1/plays/claims",
headers={
"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json",
},
json={
"rows": [
{
"structure_code": "ALM-0012",
"approval_number": "TNB-2026-000123",
"hour": "2026-10-06T14:00:00+05:00",
"plays": 118,
"deal_id": "deal-4411",
},
{
"structure_code": "ALM-0012",
"creative_sha256": "2419fe2d001c9185b3b903283894a5d955f45a57d1eaf1c6b787759650f00a17",
"hour": "2026-10-06T15:00:00+05:00",
"plays": 120,
},
],
},
)
print(response.status_code, response.text)
Go
package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"rows": [
{
"structure_code": "ALM-0012",
"approval_number": "TNB-2026-000123",
"hour": "2026-10-06T14:00:00+05:00",
"plays": 118,
"deal_id": "deal-4411"
},
{
"structure_code": "ALM-0012",
"creative_sha256": "2419fe2d001c9185b3b903283894a5d955f45a57d1eaf1c6b787759650f00a17",
"hour": "2026-10-06T15:00:00+05:00",
"plays": 120
}
]
}`)
req, err := http.NewRequest("POST", "https://app.tanba-ooh.kz/api/v1/plays/claims", body)
if err != nil {
panic(err)
}
req.Header.Set("Authorization", "Bearer YOUR_API_KEY")
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(resp.Status, string(data))
}