Appearance
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/jsonbash
curl -X POST "$BASE_URL/forecast" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d @request.jsonThe 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.
| Field | Type | Required | Meaning |
|---|---|---|---|
inventory_id | string | yes | The slot being forecast. See Inventory identity. |
flight.start_date, flight.end_date | string | yes | Inclusive date range, YYYY-MM-DD, read in your account timezone from /health. |
targeting.geo | array of strings | no | ISO-3166-1 alpha-2 country codes. Absent or empty means no geo restriction (worldwide). |
sizes | array of strings | no | Creative 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"
}| Field | Type | Required | Meaning |
|---|---|---|---|
inventory_id | string | yes | Echoes the slot, so DataFlair can match the response to the request. |
available_impressions | integer | yes | Impressions still reservable for this slot over the flight, after existing commitments. An advertiser can book against this number. |
forecasted_impressions | integer | yes | Total impressions the slot is predicted to deliver over the flight, before existing commitments. It is always greater than or equal to available_impressions. |
unit_type | string | no | Defaults 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_impressionsis GAMavailableUnits: what is left to sell.forecasted_impressionsis GAMmatchedUnits: 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.
- Preferred. Declare
"forecast": falseinGET /health. DataFlair then does not callPOST /forecastand 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. - If
forecastistruebut one slot cannot be forecast, return501 Not Implementedwith{ "code": "forecast_unsupported", "message": "…" }. DataFlair treats that slot as "no forecast available" and degrades gracefully. It does not block the booking.
Errors
| Status | What caused it | What DataFlair does | What to do |
|---|---|---|---|
400 | Malformed request. | Treats it as a bug, logs it and shows it. | Check the body against the fields above. |
401 | Missing, invalid or expired key. | Marks the connection as error. | Check the key. |
403 | The key lacks a required scope. | Marks the connection as error. | Widen the key's scope. |
404 | Unknown inventory_id. | Skips the item and reports it. | Return 404 only for a slot that does not exist. |
422 | Valid 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. |
429 | Rate limit exceeded. | Backs off and retries per Retry-After. | Send Retry-After in seconds. |
501 | This slot cannot be forecast. | Degrades gracefully. | See "If you cannot forecast". |
5xx | Server 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_idvalues, 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 forecastNo 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.