Read a statement and check its evidence
A statement tells an operator what was billed for a period and on what evidence. Every figure in it can be traced to stored records, and the records can be checked without trusting the platform. This guide shows how to read the statement and how to check the evidence offline.
Reference pages: Evidence and offline checking and Approval envelope and revocation list formats.
Get the statement
In the console, open Billing, choose the period and download the statement as a PDF in Kazakh, Russian or English. The same figures are in the integration API, with the scope read:billing:
curl -H 'Authorization: Bearer tnbk_EXAMPLE_secret' \
'https://app.tanba-ooh.kz/api/v1/billing/periods/0b1c3a52-6f0e-4c2e-9d3a-2f5d1e7a9c10'
The statement ends with a basis line, for example basis: 96240 plays, evidence tier: mtls, model: billing-v0. It states how many plays the bill rests on, which evidence tier gave them and which multiplier model turned plays into billing units. Evidence is frozen with its period: a closed period always shows the figures it was closed with.
Read the lines
Each line of the answer is one charge:
| Field | Meaning |
|---|---|
kind | impression for plays, approval_single and approval_prepaid for approval fees, lab for a laboratory fee |
source_ref | For a play line, the structure and the hours it covers; for a late line, the structure and the month; for a fee line, the approval number |
quantity | Billing units. For plays it is the number of plays multiplied by the multiplier of the structure's format in the model; billing-v0 is 1.000 for every format, so units equal plays |
amount_kzt, vat_kzt | The amount in tenge as a decimal string, without VAT, and the VAT |
tiers | The evidence tiers that gave the plays of the line |
model | The multiplier model; empty for a fee line |
Two blocks next to the lines keep the picture honest:
reported_not_billedis the plays that were reported in the period but are outside the bill: tiers that are not in the billable set, and the rows an operator imported from its own CMS (tierimport, never billable). You see the gap before anyone decides about it.shortfallslists closed months for which fewer plays are on file now than were billed. They are shown to the authority and never credited automatically.
A play line named <code> late <yyyy-mm> bills, once, plays of an earlier closed month that arrived after that month was closed, at the tariff of that month.
Evidence tiers
The tier is the channel the plays came on, and it fixes how far they are trusted.
| Tier | Channel |
|---|---|
mtls | A player with a client certificate, signing its batches (Send proof of play) |
signed | A player or agent with a registered key |
attested | The operator's CMS, vouching for its players with a signed batch |
native | A further channel that carries a per-device credential |
import | Rows an operator imported from its own CMS through play import; kept apart and never billed |
For one structure, approval and hour, plays are never added across tiers: the tier with the most plays gives the figure, so a screen reported by both its player and a CMS is billed once. The tiers that decide the bill are a setting of the platform owner.
Check the evidence yourself
Everything below needs only tanba-verify, which you can download on the Downloads page, and root.pem, the platform root certificate that approvals, revocation lists, anchors and seals chain to. The root for the test contour comes with the test environment; the set of root certificates will be published on the Downloads page when the production root exists.
1. The daily seal of the received statistics
Every Almaty day, shortly after midnight, the platform seals the statistics batches it received the day before: one Merkle root over the batches, signed with its status key, chained to the seal of the day before and recorded in the public ledger. Only counts and the root are public.
curl -o seal.json https://verify.tanba-ooh.kz/v1/stats-seals/2026-10-13
tanba-verify seal seal.json --ca root.pem
OK means that the signature is the status key's and chains to the root, that the body is the signed one, and that the ledger proof leads from the seal to the root of its ledger day. Exit code 0 is good, 2 means something is bad, and 6 means the seal is sound but no ledger day holds it yet: fetch it again later. A batch among the batches of a seal can be checked with --batch-proof, which takes a file with the Merkle path of that batch; no public call serves such a file yet.
2. The ledger day and Bitcoin
The seal is a leaf of the ledger day on which it was made. That day's digest is timestamped in Bitcoin. Recompute the digest from the inputs and check the proof:
curl -o ledger-2026-10-14.json https://verify.tanba-ooh.kz/v1/ledger-days/2026-10-14
curl -o ledger-2026-10-14.ots https://verify.tanba-ooh.kz/v1/ledger-days/2026-10-14/proof.ots
tanba-verify ledger --day 2026-10-14 --ots ledger-2026-10-14.ots --inputs ledger-2026-10-14.json \
--btc-header-url https://blockstream.info/api
Exit 0 means the proof carries a Bitcoin block. Exit 2 means the inputs are inconsistent, 3 that the proof is for another digest, 6 that the proof is still pending, and 8 that the public block explorer disagrees. Without --btc-header-url the block header is not checked here; the official ots verify -d DIGEST FILE.ots checks it against your own node.
3. One approval in the ledger
curl -o ledger-proof.json https://verify.tanba-ooh.kz/v1/approval/TNB-2026-000123/ledger-proof
tanba-verify inclusion --proof ledger-proof.json --approval TNB-2026-000123
The proof says that the approval's leaf is in the tree of its day. It is available once the day is closed and recorded.
4. An approval, a revocation list and an anchor
tanba-verify spot.mp4 spot.mp4.p7s --roots root.pem
tanba-verify revocations list.p7s --ca root.pem
tanba-verify anchor anchor-2026-10-05.p7s --ca root.pem
The first command checks a media file against its approval envelope. Its exit codes are 0 OK, 2 BAD_SIGNATURE, 3 HASH_MISMATCH, 4 EXPIRED_APPROVAL, 5 NOT_YET_VALID and 64 for a wrong command or an unreadable file; 6 OUTER_NOT_VERIFIED and 7 OUTER_INVALID concern the state signature. The second prints a signed revocation list and the third checks a daily audit anchor, both with exit 0 or 2. The formats are described in Approval envelope and revocation list formats.
5. A stored batch
Every accepted proof-of-play batch is stored as the bytes received, with the signature and the SHA-256 of the body. Take the batch, hash it, verify its signature with the public key of the device or of the CMS installation, and follow prev_sha256 and seq. How this works is in Send proof of play.
What the evidence does not prove
The ledger shows that a record existed on a day and was not altered afterwards. It does not show that the decision behind a record was right. The seal covers what the platform received; a play that was never reported is not in it, and a missing stretch shows as a gap in the record numbers of the player.