Skip to content

We call youDataFlair calls YOUR server. You implement this endpoint. You do not call DataFlair.

End-to-end example ​

One booking, from first connection to final reconciliation, with real request and response bodies. The ids are consistent in every step, so you can trace them.

  • Account timezone: Europe/Berlin. Currency: EUR.
  • Ad slot: slot_728x90_home ("Homepage Leaderboard").
  • Advertiser: Acme Corp.
  • DataFlair campaign reference: CMP-VDWZQ4IT.

Step 1: Connect (once) ​

An operator enters your base_url and the credential you issued. DataFlair probes with GET /health.

http
GET /health
Authorization: Bearer sk_live_9f2c…
bash
curl "$BASE_URL/health" -H "Authorization: Bearer $API_KEY"

Your response:

json
{
  "account_id": "acct_1029",
  "account_name": "Example Media Network",
  "timezone": "Europe/Berlin",
  "currency": "EUR",
  "capabilities": {
    "forecast": true,
    "reporting": true,
    "draft_booking": true
  }
}

DataFlair records the account, the timezone and the currency, and marks the connection connected.

Step 2: Discover and map inventory ​

DataFlair calls GET /inventory.

http
GET /inventory?limit=100
Authorization: Bearer sk_live_9f2c…
bash
curl "$BASE_URL/inventory?limit=100" -H "Authorization: Bearer $API_KEY"

Your response:

json
{
  "data": [
    { "inventory_id": "slot_728x90_home", "name": "Homepage Leaderboard", "sizes": ["728x90"], "format": "display", "status": "active" }
  ],
  "next_cursor": null
}

The operator maps the DataFlair placement "Homepage Leaderboard" to slot_728x90_home. DataFlair stores that mapping once and reuses it for every future booking of this slot.

Step 3: An advertiser forecasts before booking ​

Acme Corp is considering all of August, targeting Germany and Austria. DataFlair calls POST /forecast.

http
POST /forecast
Authorization: Bearer sk_live_9f2c…
Content-Type: application/json
bash
curl -X POST "$BASE_URL/forecast" -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" -d @request.json

The request body:

json
{
  "inventory_id": "slot_728x90_home",
  "flight": {
    "start_date": "2026-08-01",
    "end_date": "2026-08-31"
  },
  "targeting": {
    "geo": [
      "DE",
      "AT"
    ]
  },
  "sizes": [
    "728x90"
  ]
}

Your response:

json
{
  "inventory_id": "slot_728x90_home",
  "available_impressions": 1420000,
  "forecasted_impressions": 2100000,
  "unit_type": "IMPRESSIONS"
}

DataFlair shows Acme that about 1.42M impressions are bookable. Acme books 100,000, pays into their DataFlair wallet and submits the reservation.

Step 4: You approve the reservation (inside DataFlair) ​

Your team reviews the reservation in DataFlair and approves it. This is the trigger. Nothing has reached your ad server yet. The approval causes the next call.

Step 5: DataFlair pushes the booking as a draft ​

DataFlair calls POST /orders.

http
POST /orders
Authorization: Bearer sk_live_9f2c…
Content-Type: application/json
Idempotency-Key: DF-CMP-VDWZQ4IT
bash
curl -X POST "$BASE_URL/orders" -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" -H "Idempotency-Key: DF-CMP-VDWZQ4IT" \
  -d @request.json

The request body:

json
{
  "idempotency_key": "DF-CMP-VDWZQ4IT",
  "advertiser": {
    "name": "Acme Corp",
    "external_ref": "brand_5501"
  },
  "order": {
    "name": "Summer Launch (DF-CMP-VDWZQ4IT)",
    "external_ref": "CMP-VDWZQ4IT"
  },
  "line_items": [
    {
      "external_ref": "DF-CMP-VDWZQ4IT-329",
      "inventory_id": "slot_728x90_home",
      "flight": {
        "start_date": "2026-08-01",
        "end_date": "2026-08-31"
      },
      "goal_impressions": 100000,
      "targeting": {
        "geo": [
          "DE",
          "AT"
        ]
      },
      "sizes": [
        "728x90"
      ],
      "creatives": [
        {
          "type": "third_party_tag",
          "width": 728,
          "height": 90,
          "tag": "<iframe src='https://t.dataflair.ai/ad/ABC123?df_source=custom&df_ad_server=custom_platform' width='728' height='90' frameborder='0' scrolling='no' referrerpolicy='no-referrer-when-downgrade' sandbox='allow-scripts allow-popups allow-popups-to-escape-sandbox allow-top-navigation-by-user-activation allow-same-origin' style='border:0;display:block' title='Advertisement'></iframe>"
        }
      ]
    }
  ]
}

Your platform resolves or creates the advertiser "Acme Corp". It creates a draft order and one draft line item. The line item targets slot_728x90_home for August in DE and AT, with a goal of 100,000 impressions. It attaches the DataFlair tag and returns your ids:

json
{
  "order_id": "ord_55021",
  "status": "DRAFT",
  "line_items": [
    {
      "external_ref": "DF-CMP-VDWZQ4IT-329",
      "line_item_id": "li_88012",
      "status": "DRAFT"
    }
  ]
}

DataFlair stores DF-CMP-VDWZQ4IT-329 → li_88012. Nothing is serving yet.

Step 6: A person takes it live (on your side) ​

Your ad-ops open the draft order ord_55021 in your own console, review it and activate it. DataFlair takes no part in this step. The line starts serving on 1 August.

Step 7: DataFlair pulls delivery to reconcile ​

Part way through the flight, and after it, DataFlair calls POST /reports.

http
POST /reports
Authorization: Bearer sk_live_9f2c…
Content-Type: application/json
bash
curl -X POST "$BASE_URL/reports" -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" -d @request.json

The request body:

json
{
  "line_item_ids": ["li_88012"],
  "date_range": { "start_date": "2026-08-01", "end_date": "2026-08-31" },
  "granularity": "total"
}

Your response:

json
{
  "rows": [
    { "line_item_id": "li_88012", "impressions": 98240, "clicks": 173 }
  ]
}

DataFlair matches li_88012 to the booked line DF-CMP-VDWZQ4IT-329. It records 98,240 delivered impressions against the goal of 100,000. It cross-checks its own tracking counts: clicks from the /go link and impressions from the in-frame pixel. Then it settles the campaign and pays the publisher net of commission. Reconciliation is done.

Idempotency in action ​

Now take a different run of the same booking. Acme's creative was still in review when you approved the reservation. The first POST /orders carried no creatives array, and the creative followed once it was approved. That is an update, not a retry. The second push uses a new idempotency_key with the same order and line external_ref values:

json
{ "idempotency_key": "DF-CMP-VDWZQ4IT-2", "order": { "external_ref": "CMP-VDWZQ4IT" }, "...": "same line external_refs, now with the creative" }

Your platform matches on external_ref and does not create a second order or line. It updates the existing line li_88012 with the creative and returns the same ids with 200. DataFlair's stored mapping does not change.

Posting the original idempotency_key again with a changed body is a different case. That is a 409, and it is not an update path. See POST /orders and Conventions.

Docs version 1.0.1