Programmatic EngineAPI All connections

Bid protocol

Live · Version 1.0.0

Base URL

https://bidder.example.com · Your server. The real addresses of your bid endpoint and win notice endpoint are agreed at onboarding.

Authentication

API key, sent in the header X-Auth-Token

A secret that we agree with you at onboarding. We send it on every call to your server. Check it and reject calls without it.

Spec file
bid-protocol.yaml

Import into Postman: File → Import → paste the URL.

Overview

When a screen is about to play an ad slot, the network asks every partner assigned to that screen whether it wants to fill the slot. You answer with the creative you want to play and the price you pay. The highest price wins. After the creative has played, the network tells you, and that call is what you are billed for.

This page describes the calls the network makes to your server. You host three endpoints, or two if you skip the optional win notice. The calls you make to us (inventory, creative upload, status, reconciliation) are on the Partner API page, and you need them before you can bid. A creative must be uploaded and approved there before it can be used in a bid.

Player            Network (SSP)                         Your server
  |  slot request     |                                       |
  |------------------>|                                       |
  |                   |  1. bidRequest  (POST, all partners   |
  |                   |     assigned to the screen, in        |
  |                   |     parallel)                         |
  |                   |-------------------------------------->|
  |                   |  200 bid  /  204 no bid               |
  |                   |<--------------------------------------|
  |                   |  choose the highest valid price       |
  |                   |  2. winNotice  (GET, winner only)     |
  |                   |-------------------------------------->|
  |  creative + nurl  |                                       |
  |<------------------|                                       |
  |  plays the creative                                       |
  |  reports the play |                                       |
  |------------------>|                                       |
  |                   |  3. confirmation  (GET nurl,          |
  |                   |     only after a verified play)       |
  |                   |-------------------------------------->|

Timing

The network sends the bid request to all partners of the screen at the same moment and waits until every one has answered or timed out. Then it chooses. A slow answer delays the slot for everybody, so answer as fast as you can.

Limit Value
Bid request, total time 5 seconds
Bid request, time to connect 2 seconds
Retries None. A request that fails or times out is a no-bid for that slot.

The win notice and the confirmation have no limit of their own and use a default of 30 seconds. They are sent while the player is waiting for its answer, so answer them in well under a second. Neither call is repeated.

What you must implement

  1. A bid endpoint. It accepts POST with a JSON body (bidRequest) and answers 200 with a bid or 204 without a body. Its address is agreed at onboarding.
  2. A confirmation endpoint. It accepts GET on the nurl you returned in the bid (confirmation). It must be on the same host as your bid endpoint.
  3. Optionally, a win notice endpoint (winNotice). Tell us its address as a URI template. If you do not give one, no win notice is sent.

Requests from us carry the header X-Auth-Token with a secret that we agree with you at onboarding. Check it on all three endpoints. Without it, anybody who knows an address could create billable events. Use HTTPS.

Auction rules

  • Every partner assigned to the screen is asked. The auction is first price: the partner with the highest price wins and is billed exactly that price.
  • A bid is valid only if the creative named in video_id is confirmed, belongs to you and is assigned to this screen. Otherwise the bid is dropped as if you had not bid. The creative is matched by the external_id you chose at upload, not by our numeric id.
  • If two valid bids have the same price, the winner is chosen by our internal partner order. Do not rely on it.
  • min_price is the floor for the slot. Send a price at or above min_price. Bids below the floor or without a price may be dropped.
  • There is no currency field. All prices, including min_price, are in the currency of your contract and are amounts for one play, not CPM.
  • The winning price is recorded with two decimal places. Prices of 1,000,000 or more cannot be recorded.
  • Only the winner receives the win notice. Only a verified play produces a confirmation. A win that is never played is not billed.

Billing

The confirmation (nurl) is the billable event. It is sent once for each play after the player has reported the playback and the report has been verified. If your confirmation endpoint is down at that moment, the call is not repeated, the play is not marked as confirmed, and it does not appear in GET /{partner}/reconciliation/impressions. A win notice that fails does not cancel the win.

Reconciliation lists the plays whose confirmation call succeeded. In a search by date a play is listed only after it has been matched with the playback log of the player, which usually takes a few hours. Search again later, or search by unique_id. Compare reconciliation with the confirmations you received. The key of a play is the request_id.

Test checklist

Before you go live, check that your bidder:

  • rejects a request without the right X-Auth-Token with 401 or 403;
  • answers 204 with an empty body when it does not want the slot;
  • answers 200 with Content-Type: application/json and a JSON object (not an array) when it bids;
  • echoes request_id exactly as received;
  • returns a video_id that is the external_id of a confirmed creative that is assigned to the screen;
  • returns price as a number at or above min_price, with at most two decimals;
  • returns a nurl on the same host as the bid endpoint, and serves it with GET and 2xx without any extra parameters;
  • handles duration_ms and min_price being null;
  • handles screen.gid and screen.operator_id as strings;
  • answers within a second under normal load, and never needs more than the 5-second limit;
  • treats a repeated confirmation of the same request_id as one play.

Versioning

Changes to this protocol are additive: new optional request fields and new optional response fields. Read request fields by name and ignore the ones you do not know. Unknown fields in your response are ignored by us.

Calls we make to your server

These are requests our platform sends to a URL you provide. Your server answers them as described.

POSTbidRequestWe send

Slot request#

Sent to your bid address when a screen assigned to you is about to play a slot. One request per slot and partner. Answer 200 with a bid or 204 with no body for no bid.

Anything other than 200 or 204 (a 4xx, a 5xx, a timeout, an invalid body) is treated as no bid. A 200 whose body is not a JSON object is also no bid.

Fields of the answer:

  • request_id: echo the value from the request. We store it as the key of the play. If you leave it out we invent one, and you will not be able to match your records with reconciliation.
  • video_id: the external_id you gave the creative at upload. creative_id is accepted as another name for the same field. Our numeric creative id is not accepted here.
  • price: what you pay for this play. bid is accepted as another name.
  • nurl: the address we call after a verified play. See the confirmation call.

If video_id is missing, or names a creative that is not usable on this screen, the bid is dropped.

min_price is the floor for this slot. It can be null when the screen has no floor. duration_ms is null when the screen owner has not set the slot length. timestamp_ms is the moment the slot is scheduled to be shown.

Body we send · application/json

FieldTypeDescriptionExample
request_idrequired string

Identifier of this request. Unique for each request. Treat it as an opaque string and echo it in your answer.

req_8f3a1c92e7
timestamp_msrequired integer | null

The moment the slot is scheduled to be shown, in Unix milliseconds, UTC.

1791454530000
duration_msrequired integer | null

Length of the slot in milliseconds. Null when the screen owner has not set it.

10000
min_pricerequired number | null

Floor price for one play, in the currency of your contract. Null when the screen has no floor. Send a price at or above it.

120
screenrequired object

The screen that offers the slot.

screen.gidrequired string

Screen id, the same number as gid in the inventory list of the Partner API, written as a string.

173
screen.operator_idrequired string

Id of the network that owns the screen, written as a string.

7
{
    "request_id": "req_8f3a1c92e7",
    "timestamp_ms": 1791454530000,
    "duration_ms": 10000,
    "min_price": 120,
    "screen": {
        "gid": "173",
        "operator_id": "7"
    }
}

Expected responses

200

A bid. The body must be a JSON object.

Response fields
FieldTypeDescriptionExample
request_idrequired string

The request_id of the request, unchanged.

req_8f3a1c92e7
video_idrequired string

The external_id of a confirmed creative of yours that is assigned to the screen. A number is accepted and read as a string. creative_id is accepted as another name.

spring_2026_001
pricerequired numbermin 0

The price you pay for this play, in the currency of your contract, at or above min_price, at most two decimals. bid is accepted as another name.

150
nurlrequired string (uri)

The address we call after a verified play. It must be on the same host as your bid address. It is called without changes.

https://bidder.example.com/confirm?rid=req_8f3a1c92e7
{
    "request_id": "req_8f3a1c92e7",
    "video_id": "spring_2026_001",
    "price": 150,
    "nurl": "https://bidder.example.com/confirm?rid=req_8f3a1c92e7"
}
204

No bid. The body must be empty.

GETwinNoticeWe send

Win notice#

Sent right after the auction, only to the winner, and only if you gave us an acceptance URL. It uses GET and the same X-Auth-Token header as the bid request. A 2xx answer is expected, and the body is not read.

You give us the address as a URI template (RFC 6570), for example:

https://bidder.example.com/win{?uniqueId,playerId,price,videoExternalId}

Use {name} to insert a value, {+name} to insert a value without escaping, and {?a,b} to add a query string. Variables with no value are left out.

Variable Value
uniqueId The request_id of your bid.
playerId Screen id (gid).
operatorId Network id (screen.operator_id).
price The price of your bid.
timestampMs Scheduled show time, Unix milliseconds.
durationMs Slot length in milliseconds.
videoExternalId Your external_id of the creative that won.
videoId Our numeric id of the creative.
nurl The nurl from your bid.

If this call fails, the error is only logged. The win stands and the creative is still sent to the screen. Do not use the win notice for billing, use the confirmation.

Expected responses

200

The notice was received. Any 2xx status is accepted.

GETconfirmationWe send

Confirmation of a verified play#

Sent when the player has reported that your creative was played and the report has been verified. This is the billable event.

The call is a GET to the nurl exactly as you returned it in the bid. We do not substitute macros, we do not add parameters and we do not change the path. Put into the nurl everything you need to recognise the play, for example the request_id.

The call is made only if the host of the nurl equals the host of your bid address. A nurl on any other host is never called, and the play is not confirmed. The call uses the same X-Auth-Token header. A 2xx status means you accepted it. Any other status, or a timeout, counts as a failure.

The call is not repeated. A play whose confirmation failed is not confirmed and does not appear in reconciliation. The confirmation can arrive minutes after the win, or not at all when the player is offline.

Expected responses

200

The confirmation was received. Any 2xx status is accepted.