Skip to content
POST/forecast We call you

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

RequiredBuild this. It is part of the contract.

POST /forecast: Availability and forecast ​

When an advertiser assembles a booking, DataFlair shows how many impressions each slot can realistically deliver over the chosen flight. The advertiser then books a sensible amount and does not over-commit or under-commit. DataFlair does this with ForecastService.getAvailabilityForecast on Google Ad Manager. This endpoint is your equivalent.

The call is read-only and creates nothing. It asks "what if I booked this?"

What we send ​

http
POST /forecast HTTP/1.1
Host: ads.example.com
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 body, saved as request.json:

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

The JSON on this page is read from the fixture files, so it cannot drift from the test suite.

FieldTypeRequiredMeaning
inventory_idstringyesThe slot being forecast. See Inventory identity.
flight.start_date, flight.end_datestringyesInclusive date range, YYYY-MM-DD, read in your account timezone from /health.
targeting.geoarray of stringsnoISO-3166-1 alpha-2 country codes. Absent or empty means no geo restriction (worldwide).
sizesarray of stringsnoCreative sizes under consideration. They improve accuracy. Google Ad Manager's own forecast is more precise when the creative placeholder size is supplied.

What you return ​

Status 200 with a JSON body:

json
{
  "inventory_id": "slot_728x90_home",
  "available_impressions": 1420000,
  "forecasted_impressions": 2100000,
  "unit_type": "IMPRESSIONS"
}
FieldTypeRequiredMeaning
inventory_idstringyesEchoes the slot, so DataFlair can match the response to the request.
available_impressionsintegeryesImpressions still reservable for this slot over the flight, after existing commitments. An advertiser can book against this number.
forecasted_impressionsintegeryesTotal impressions the slot is predicted to deliver over the flight, before existing commitments. It is always greater than or equal to available_impressions.
unit_typestringnoDefaults to IMPRESSIONS. It is there so the contract can extend to other units later. Only IMPRESSIONS is used today.

How this maps to Google Ad Manager ​

GAM's forecast returns four counts: availableUnits, matchedUnits, possibleUnits and reservedUnits. DataFlair needs two of them, and this endpoint asks for those two directly.

  • available_impressions is GAM availableUnits: what is left to sell.
  • forecasted_impressions is GAM matchedUnits: the total the targeting predicts.

You do not need GAM's other counts. If your platform models availability differently, map your closest concepts onto these two and describe the mapping in your handoff notes.

If you cannot forecast ​

Pick one of two options. Do not invent a number.

  1. Preferred. Declare "forecast": false in GET /health. DataFlair then does not call POST /forecast and shows the availability the publisher listed. The booking still works. It is not checked against a live prediction. DataFlair takes the same position with Revive today.
  2. If forecast is true but one slot cannot be forecast, return 501 Not Implemented with { "code": "forecast_unsupported", "message": "…" }. DataFlair treats that slot as "no forecast available" and degrades gracefully. It does not block the booking.

Errors ​

StatusWhat caused itWhat DataFlair doesWhat to do
400Malformed request.Treats it as a bug, logs it and shows it.Check the body against the fields above.
401Missing, invalid or expired key.Marks the connection as error.Check the key.
403The key lacks a required scope.Marks the connection as error.Widen the key's scope.
404Unknown inventory_id.Skips the item and reports it.Return 404 only for a slot that does not exist.
422Valid shape, invalid values, such as a bad date range or an incompatible size.Shows your message, so the operator can fix the booking.Return a clear message.
429Rate limit exceeded.Backs off and retries per Retry-After.Send Retry-After in seconds.
501This slot cannot be forecast.Degrades gracefully.See "If you cannot forecast".
5xxServer error.Retries with backoff.Check your server's logs.

Every error body has the shape described in Conventions.

Accuracy and performance ​

  • Caching is welcome. DataFlair caches forecast results briefly on its side. Its GAM path caches per slot, geo and month for a few minutes. A forecast that is a few minutes old is fine. A slow forecast that blocks the booking screen is not. Aim to answer in well under a second.
  • Rounding is fine. DataFlair rounds forecast numbers before it shows them to advertisers. You do not need an exact-to-the-impression figure.
  • Batching is optional. DataFlair may forecast several slots while an advertiser browses. A single-slot endpoint is enough, because DataFlair runs the calls in parallel. If you can offer a batch variant that accepts an array of inventory_id values, tell DataFlair, and it can use it to cut round trips.

Timeouts and retries ​

DataFlair does not call this endpoint yet. The platform's configured timeouts for calls to your server are 10 seconds to connect and 30 seconds in total.

Verify ​

Run the conformance check with --only forecast to check this endpoint against the fixtures.

Verify this endpoint

node tools/adserver-check/bin/adserver-check.mjs http://localhost:3000/api/v1 --key sk_test_local --only forecast

No playground here: the request would go to your own server. Run the checker.

The checker is not published to npm yet. See how to run it.

Docs version 1.0.1