Appearance
Conformance check
The conformance check replays the fixtures against your ad server. It prints one line for each case. A failing line says what is wrong and links to the section that explains it.
It runs on your own machine, against localhost or a staging server. It does not need a DataFlair account. It checks each answer against the schemas in the OpenAPI file, the same file the API reference is built from, so the check and the reference cannot disagree.
The checker is not published to npm yet
npx cannot fetch it yet. It is in the DataFlair docs repository, in docs-site/tools/adserver-check. Run it from the docs-site folder, after npm ci. The fixtures work without it: send each request.json with curl and compare the answer with expected-response.json.
Run it
bash
node tools/adserver-check/bin/adserver-check.mjs http://localhost:3000/api/v1 --key sk_test_localUse the base URL you give DataFlair, and a test key. A command line stays in your shell history, so you can set ADSERVER_CHECK_KEY instead of --key.
| Option | Meaning |
|---|---|
--key <key> | The key to send as a Bearer token. Or set ADSERVER_CHECK_KEY. |
--only <endpoint> | Run one endpoint: health, inventory, forecast, orders or reports. |
--slot <inventory_id> | Book against this slot, instead of the first slot that GET /inventory lists. |
--docs <url> | Where the failure links point. The default is https://docs.dataflair.ai. |
--fixtures <folder> | Replay a folder of fixtures instead of the bundled ones. |
The exit code is 0 when your server is ready to connect, 1 when a case failed, and 2 when the command was used wrongly.
A passing run
Every case passes against a server that follows the contract:
text
✓ GET /health 200 Returns the account and its capabilities
✓ GET /health 401 A wrong key is a 401 with an error body
✓ GET /inventory 200 Lists the bookable slots
✓ POST /forecast 200 Returns available and forecasted impressions
✓ POST /forecast 404 An unknown inventory_id is a 404 with an error body
✓ POST /orders 201 Creates a draft order
✓ POST /orders 409 The same idempotency_key with a different body is a 409
✓ POST /orders 201 A booking with no creative still returns draft line items that do not serve
✓ POST /orders 200 A repeat of the same idempotency_key and body returns the same ids
✓ POST /orders 404 An unknown inventory_id is a 404 with an error body
✓ POST /orders 200 A new idempotency_key with the same external_ref updates the existing order
✓ POST /reports 200 Returns impressions and clicks per line
✓ POST /reports 200 granularity daily returns a date on every row
13 passed · 0 failed. Ready to connect.A failing run
Here a server returns its orders as ACTIVE. The check was run with --only orders. Each failing line names the value and links to the draft-only rule:
text
✗ POST /orders 201 Creates a draft order
Order "ord_55021" returned as "ACTIVE". It must come back as DRAFT and must not serve.
Line item "li_88012" returned as "ACTIVE". Every line item must come back as DRAFT and must not serve.
→ See https://docs.dataflair.ai/marketplace/ad-server-api/operations/orders#draft-only
✓ POST /orders 409 The same idempotency_key with a different body is a 409
✗ POST /orders 201 A booking with no creative still returns draft line items that do not serve
Order "ord_55022" returned as "ACTIVE". It must come back as DRAFT and must not serve.
Line item "li_88013" returned as "ACTIVE". Every line item must come back as DRAFT and must not serve.
→ See https://docs.dataflair.ai/marketplace/ad-server-api/operations/orders#draft-only
✗ POST /orders 200 A repeat of the same idempotency_key and body returns the same ids
Order "ord_55021" returned as "ACTIVE". It must come back as DRAFT and must not serve.
Line item "li_88012" returned as "ACTIVE". Every line item must come back as DRAFT and must not serve.
→ See https://docs.dataflair.ai/marketplace/ad-server-api/operations/orders#draft-only
✓ POST /orders 404 An unknown inventory_id is a 404 with an error body
✗ POST /orders 200 A new idempotency_key with the same external_ref updates the existing order
Order "ord_55021" returned as "ACTIVE". It must come back as DRAFT and must not serve.
Line item "li_88012" returned as "ACTIVE". Every line item must come back as DRAFT and must not serve.
→ See https://docs.dataflair.ai/marketplace/ad-server-api/operations/orders#draft-only
2 passed · 4 failed. Not ready to connect.What it sends and changes
The requests are the fixtures. The check changes three things and nothing else:
- The campaign token. The examples use the token
VDWZQ4ITin every key, order name andexternal_ref. Each run swaps it for a fresh one, so you can run the check again without replaying the last run's keys. - The slot. The examples book
slot_728x90_home. The check readsGET /inventoryand books the first slot that is not archived, and it prefers a slot that takes728x90. Pass--slotto choose one. The unknown-slot cases keepslot_x. - The line item ids in the reports request. The check sends the ids your server returned from
POST /orders, not the example ids.
The wrong-key case sends a generated key. Nothing else in a request is changed.
The booking cases create draft orders on your server, named Summer Launch (DF-CMP-...) and similar. Delete them when you are done.
With --only, the check first reads what the endpoint needs, without printing it. --only forecast, --only orders and --only reports read GET /inventory for a slot. --only forecast also reads GET /health. --only reports then books one draft order, because reports asks about a line item.
What it checks
Every case checks that your server answered, that it did not redirect, that the status is the expected one, and that the body fits the schema. DataFlair does not follow redirects, so a redirect fails the case. If your server does not answer the first request at all, the check stops there and marks the rest as not run.
If GET /health says forecast is false, the forecast cases are skipped. DataFlair does not call POST /forecast then. A skipped case is not a pass. A run where every case was skipped is not ready to connect.
These rules apply on top of the schema:
| Rule | What it checks | Explained in |
|---|---|---|
health.requiredCapabilities | reporting and draft_booking are not false. | Fields |
forecast.echoesSlot | The answer names the slot that was asked about. | What you return |
forecast.ordering | available_impressions is not higher than forecasted_impressions. | What you return |
orders.draftOnly | The order and every line item come back as DRAFT. | Draft only |
orders.echoesExternalRefs | Every external_ref that was sent comes back, and no other. | What you return |
orders.sameIdsAsCreate | A repeat or an update returns the same order_id and line_item_id values as the first call. | Idempotency and recovery |
reports.rowsForRequestedLines | Every row is for a line that was asked about, with one row per line, or one per line per day. | What you return |
reports.dailyHasDate | With granularity set to daily, every row has a date. | What you return |
What it does not check
- It reads only the first page of
GET /inventory. - It waits up to 30 seconds for each answer. It does not measure speed.
- It reads the state your server says it returned. It cannot tell whether a draft really stays out of serving. Look at the drafts in your console.
- It does not test how DataFlair behaves. It tests your server.
If a case fails, follow its link. Errors and Troubleshooting cover the rest.