> ## Documentation Index
> Fetch the complete documentation index at: https://docs.apostra.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Does your buy still match the booking?

> What within the booking, outside the booking and not comparable mean on a media buy you booked through a media partner, and why a missing answer is not a pass.

After you book a media buy through a media partner, the media partner's ad
server can drift from what you agreed: a budget raised, a flight date moved,
targeting widened, or a rate changed. Apostra keeps checking, and the buy now
carries one answer to the question "does this buy still match the booking?" in a
field called `booking`.

The answer comes from the media partner's storefront. Apostra shows you the
storefront's answer and nothing about the ad server behind it: you never see an
ad server, a source, or a value read back from one. You already hold the booked
values, so the answer names the fields that moved and leaves the values out.

> [!NOTE]
>
> The booking answer is in beta and is switched on per organization. Ask your
> Apostra contact to turn it on for your organization. Until it is on, your buys
> carry no `booking` field.

## If you read `contract_out_of_line`

The V3 live status (`get` with `kind: "media_buy"` and `include: ["liveStatus"]`)
no longer returns the `contract_out_of_line` blocker. `booking` replaces it and
says more: it covers every booked field and names the ones that are outside.
Until the booking answer is on for your organization, a buy that has drifted
shows no signal on the V3 live status. The v2 buyer status read still returns
`contract_out_of_line`.

## The three answers

| `status` | Say it as | Meaning |
| - | - | - |
| `"within"` | Within the booking | The storefront compared every booked field and every one is within the booking. |
| `"outside"` | Outside the booking | At least one booked field is outside the booking. |
| `null` | Not comparable | The storefront cannot say either way. |

**Not comparable is not a pass.** It does not mean something is wrong, and it
never means the buy is within the booking. It means the storefront has not
verified the buy, so do not show "no differences" for it. Check for `"within"`
by name, and treat a `null` status, and a buy with no `booking` field at all, as
"not checked".

A buy reads **not comparable** when:

* nothing has been compared since the booking was accepted;
* at least one booked field could not be compared;
* the storefront has not heard from the media partner's ad server recently
  enough, so it records the answer as not comparable until the next read (the
  bound is 15 minutes by default).

You are not given a reason for a buy that is not comparable.

> [!NOTE]
>
> While the beta runs, a sandbox buy is not yet kept out of the check. Treat the
> answer on a sandbox buy as not verified, whatever its `status`. A sandbox buy
> carries a no-charge line in the media partner's ad server, so its rate can differ
> from the booking and read outside. The rule that records a sandbox buy as not
> comparable is still to come.

A buy is outside the booking as soon as the storefront records it. There is no
grace period, because billing follows the booking and a late answer is an
inaccurate one. If the buy has several sources, it is outside when any of them
is, within only when every one is, and otherwise not comparable.

## What "within the booking" means

Within the booking does not mean equal to it. The media partner's state is within
the booking when each field is inside what you booked:

| Field | Within the booking when |
| - | - |
| Targeting | The partner's targeting reaches no one the booking did not. A narrower audience or area is within. |
| Flight | The partner's start and end lie inside the booked window: no earlier start and no later end. |
| Budget | The partner's amount is at or below the booked amount, in the booked currency. A lower amount is within; under-delivery is a delivery question, not a booking question. |
| Pricing | The partner's rate and pricing model equal the booked terms. |
| Creatives | The buy carries only creatives you assigned. |

A field that cannot be compared is not outside the booking. It keeps the buy from
reading within.

## What the answer carries

```json theme={null}
{
  "booking": {
    "status": "outside",
    "asOf": "2026-10-26T09:30:00.000Z",
    "since": "2026-10-25T14:00:00.000Z",
    "fieldPaths": ["packages[sf_pkg_1].budget", "end_time"],
    "financial": true,
    "narrowerPaths": ["packages[sf_pkg_2].targeting_overlay.geography"]
  }
}
```

| Field | Meaning |
| - | - |
| `status` | `"within"`, `"outside"`, or `null` for not comparable. |
| `asOf` | The time of the oldest read the answer rests on, so it is never shown as fresher than its stalest part. `null` when nothing has been compared yet. |
| `since` | When the oldest outside field was first seen. Present only when `status` is `"outside"`. |
| `fieldPaths` | The AdCP paths of the booked fields that are outside the booking, each once, money first. The paths use your buy's own package ids (`sf_pkg_...`). A difference on a package that cannot be matched is named `packages`. Present only when `status` is `"outside"`. |
| `fieldPathsTruncated` | `true` when more fields are outside the booking than `fieldPaths` lists. The list holds at most 50 paths, money first, so treat the remaining fields as still outside. Absent otherwise. |
| `financial` | `true` when any outside field is a budget, rate or flight. Present only when `status` is `"outside"`. |
| `narrowerPaths` | Paths where the partner's state is within the booking but narrower than asked: you booked the US or Canada and the partner delivers in the US only, a later start, an earlier end, a lower budget. Never a breach, and it never changes `status`. Absent when there are none, and when `status` is `null`. |

The answer never carries a booked value, a value the partner reports, or why a
field could not be compared. The only read time it states is `asOf`, the time of
the oldest read the answer rests on.

The text a tool returns for the buy states the answer in the same words: "within
the booking", "outside the booking" or "not comparable", never "none" or "no
differences".

## Where you read it

`get` with `kind: "media_buy"` returns `booking` for a buy routed through a
storefront. List rows from `search` do not carry it. A buy that is not routed
through a storefront, or has not been sent to a source yet, has no agreed terms
to check and carries no `booking` field.

## What to do about an outside buy

1. **Read `fieldPaths`.** Money first: a budget, rate or flight outside the
   booking can change what delivers.
2. **Ask the media partner.** The change may be intentional on their side. They
   see the booked and reported values; you do not.
3. **If you agree the change,** update the buy. When the update is accepted it
   becomes the booking and the difference closes.

Billing follows the booking, not the media partner's ad server. A rate raised
there does not raise what you pay.

## Related

* [Agreed terms check](https://docs.apostra.com/v3/agreed-terms-check.md) is the media partner's view of the
  same recorded result, with the booked and reported values.
* [Media buy lifecycle](https://docs.apostra.com/v2/concepts/media-buy-lifecycle.md) explains the statuses a
  buy moves through, which are separate from whether it matches the booking.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.