> ## 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.

# Goal progress

> Read the latest stored assessment of a campaign's delivery and optimisation goals.

Goal progress shows whether a campaign is meeting the goals it booked. It is an
assessment from the latest seller delivery data and campaign facts Apostra has
processed. It does not calculate a new answer while you read it.

For a compact delivery snapshot, see [Campaign pulse](https://docs.apostra.com/v3/campaign-pulse.md).

Ask for the `progress` include on a campaign or media buy:

```json theme={null}
{ "kind": "campaign", "id": "cmp_123", "include": ["progress"] }
```

```json theme={null}
{ "kind": "media_buy", "id": "mb_123", "include": ["progress"] }
```

On a campaign, `goalProgress` contains the campaign's own goals, its media-buy
goals, and each package's delivery goal. On a media buy, it contains that buy's
goals and its packages' delivery goals. The entries keep the exact scope in
`scope`.

## Read a goal

Each `goalProgress` entry describes one stored goal assessment.

| Field | Meaning |
| - | - |
| `scope` | Whether the entry belongs to the campaign, a media buy, or a package. It also carries the applicable identifiers. |
| `goalKind` | `optimization` or `delivery`. |
| `goalPriority` | The priority of an optimisation goal. It is `null` for a delivery goal. |
| `goal`, `askedTarget`, `answeredTarget`, `actual`, `basis` | The recorded goal and evidence used for its assessment. Their shape depends on the goal. |
| `verdict` | The published assessment when it can be made. |
| `verdictWithheld` | Why no verdict is available, for example because the metric is not yet supported or the latest data is not enough to confirm an outcome. |
| `judgedAgainst` | Whether the assessment uses the asked or answered target. |
| `delivery` | Delivery-specific evidence: `constraint` (`kind` and `amount`), `expected`, `pacingIndex`, `deliveryProjection`, `projectionRange`, `sellerPacingIndex`, and `sellerDeliveryProjection`. It is `null` for optimisation goals. |
| `dataThrough` | The latest delivery time used for this assessment. |
| `nextCheckAt` | The next time this entry can change without new seller data. |

For an `optimization` entry, `goal` is the campaign or media buy's native
AdCP `optimization_goal`, including its snake\_case field names such as
`event_sources`, `event_source_id`, and `metric_id`. `askedTarget` and
`answeredTarget` are the target values the assessment compares; `actual` and
`basis` are Apostra's calculated evidence for that comparison.

Within a delivery entry, values are `null` when the seller has not supplied
enough compatible data for that measure. For example, Apostra does not combine
spend that sellers reported in different currencies.

An on-pace result means the projected finish is within 2% of the binding
constraint, or within the projection's measured uncertainty range, whichever
is larger.

In `get_delivery`, each campaign and media buy on the page has a `deliveryGoal`
block, even before a stored delivery assessment exists. Its `expected` and
`pacingIndex` cover the dates you asked for. The projected finish and end state
come from the latest stored evaluation, so they match the goal progress returned
by campaign and media-buy reads.

When the sweep has not yet stored a delivery assessment, `deliveryGoal.verdict`
is `null` and `deliveryGoal.verdictWithheld` is `awaiting_confirmation`. That is
a normal pending state, not zero delivery. The goal-progress sweep starts a
bounded refresh pass every 15 seconds. A candidate verdict must agree across two
consecutive evaluations before Apostra publishes it. Use `verdictWithheld` to
understand what it means and what to do next:

* `no_budget_or_booked_impressions`: the delivery goal has neither a spend
  budget nor booked impressions. Add a spend budget or booked-impression goal.
* `no_flight`: the delivery goal has no usable start or end date. Correct the
  flight dates.
* `data_through_before_flight`: available delivery data ends before the flight
  begins. Wait for in-flight delivery reporting, or correct the reporting dates.
* `delivery_not_reported`: no delivery has been reported yet. Retry after
  delivery is reported and check the seller reporting feed if it remains absent.
* `too_early_to_judge`: the available data is too early for a reliable projected
  finish. Wait for more delivery data.
* `awaiting_confirmation`: the sweep has a candidate state that has not yet
  matched across two consecutive evaluations. This is normal just after a
  change; a verdict normally follows after the next 15-second pass once the two
  evaluations agree. Synthetic demo entries always show this value because demos
  never have a stored assessment.
* `fx_rate_unavailable`: a campaign needs a daily currency rate that is
  unavailable for the requested range. Retry once a rate is available or correct
  the currency setup.
* `unavailable`: a delivery-fact, currency-rate, or stored-assessment read
  failed. Retry later; this is never a judgement on the campaign.

`progress` can be `null` while `deliveryGoal` is populated. That means there
is no optimisation-goal progress to show, but Apostra still has delivery-goal
evidence for the campaign or media buy.

If a legacy report does not provide both dates for the reporting interval,
`get_delivery` omits `goalProgress`. Apostra cannot calculate interval
`expected` or `pacingIndex` without those dates.

`sellerPacingIndex` and `sellerDeliveryProjection` are seller-published values
that Apostra passes through unchanged. The delivery verdict is Apostra's
assessment against the buyer's goal: it does not edit, score, or certify the
seller, and it creates no seller-facing change or notification.

## Show goal progress in a list

Use the same include with `search`:

```json theme={null}
{ "kind": "campaign", "include": ["progress"] }
```

```json theme={null}
{ "kind": "media_buy", "include": ["progress"] }
```

Each row then carries `progressSummary`:

| Field | Meaning |
| - | - |
| `worstVerdict` | The most serious published assessment across the row's goals. It is `null` when every verdict is withheld. |
| `deliveryEndState` | The published projected end state for that campaign or media buy. Package assessments remain available in `get`. |
| `dataThrough` | The latest data-through time across the row's stored goals. |
| `nextCheckAt` | The earliest next-check time across the row's stored goals. |

`worstVerdict` uses this order, from most to least serious:

1. `underdelivery`, `behind`, and other missed goals
2. `early_exhaustion`
3. `on_pace` and `on_track`
4. `complete` and `beat`

Goals whose verdict is withheld do not affect the summary. If every goal is
withheld, `worstVerdict` is `null`.

The summary is deliberately small so a page of campaigns or media buys can be
read in one request. Use `get` when you need every goal and its evidence.

## Keep a view current

Read again at `nextCheckAt` when it is present. A new seller delivery,
conversion event, goal, or budget change can also produce a new assessment.
The Apostra web app updates a changed goal assessment within about a minute.


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