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

# Get campaign seller scorecard

> Score each seller in a campaign on delivery, price, performance and quality

`GET /api/v2/buyer/campaigns/{campaignId}/seller-scorecard`

Answers "how did each seller do in this campaign?" Every seller you bought
from in the campaign gets four scores, each judged on its own: delivery,
price, performance and quality. Each score carries its value, the seller's
rank among the campaign's sellers on that score alone, and who counted it.
There is no blended score. A seller that costs more but performs better should
read as exactly that, two different answers, and a single number would hide
the trade-off.

The scorecard uses only your own media buys in the campaign. It never uses
other buyers' results, so it needs no minimum number of buyers behind a
figure. For how sellers are judged on the goal itself, see
[Goal-seeking campaigns](/v2/concepts/goal-seeking-campaigns#scoring-the-sellers-in-a-campaign).

<Note>
  **V3 beta.** The scorecard is open to buyers enrolled in the V3 beta. Any other account
  is refused with `403 FEATURE_NOT_ENABLED`.
</Note>

## Request

```bash theme={null}
curl "https://api.apostra.com/api/v2/buyer/campaigns/cmp_123/seller-scorecard" \
  -H "Authorization: Bearer $SCOPE3_API_KEY"
```

## Parameters

| Param | Type | Required | Notes |
| - | - | - | - |
| `campaignId` | string | Yes | Path. A live campaign on your account |
| `startDate` | string | No | `YYYY-MM-DD`. Defaults to the campaign's first reported day |
| `endDate` | string | No | `YYYY-MM-DD`. Defaults to today |

Without dates, the scorecard covers the campaign's whole reported life.

## Response

| Field | Type | Meaning |
| - | - | - |
| `campaignId` | string | The campaign scored. |
| `periodStart`, `periodEnd` | string | The first and last day scored. |
| `currency` | string or null | The advertiser currency every amount is in. `null` when nothing was reported. |
| `priceUnit` | string | The unit every seller's price is in (see [Price](#price)). |
| `pricePerUnits` | number | `1000` when `priceUnit` is `impressions` (a price per thousand), otherwise `1`. |
| `sellers` | array | One row per seller, most spend first. |
| `moneyCoverage` | object | Whether the reporting store holds every day the period covers: `status` is `complete`, `partial` or `unavailable`. When it is not `complete`, spend is understated, so every seller's delivery and price read as not reported. |
| `unattributedMediaBuyIds` | array | Media buys whose products span more than one Storefront. They belong to no single seller, so they are not scored. |

Each entry in `sellers`:

| Field | Type | Meaning |
| - | - | - |
| `sellers[].storefrontId` | string | The Storefront the media buys were booked with. |
| `sellers[].sellerName` | string or null | The Storefront's name. |
| `sellers[].mediaBuyIds` | array | The seller's media buys in the campaign that were scored. |
| `sellers[].delivery` | object | The delivery score. `price`, `performance` and `quality` sit beside it, each in the same shape. |

Every score has the same shape. Here it is under `delivery`; `price`,
`performance` and `quality` carry the same fields:

| Field | Type | Meaning |
| - | - | - |
| `sellers[].delivery.value` | object or null | The score itself, described per score below. `null` when the score is not reported for this seller. |
| `sellers[].delivery.rank` | integer or null | The seller's rank among the campaign's sellers on this score alone. `1` is best, and tied values share a rank. `null` when the rank is withheld. |
| `sellers[].delivery.rankedAmong` | integer | How many of the campaign's sellers were ranked on this score. |
| `sellers[].delivery.rankWithheld` | string or null | Why there is no rank. `not_reported`: there is no value. `too_few_observations`: there is a value, but over too little delivery to compare. `not_comparable`: there is no common yardstick, such as no budget and flight to pace against, no target, or sellers judged in different units. |
| `sellers[].delivery.countedBy` | object or null | Who counted the value: `{ "kind": "seller" }` for the seller's own delivery report, `{ "kind": "vendor", "vendor": … }` for a measurement vendor's values, or `{ "kind": "buyer_event_source", "vendor": … }` for your own measurement records. |

**A score with no data is not reported. It is never zero.** It has no value
and no rank, and the seller is not counted in `rankedAmong`, so a missing
score never drags a seller down or pushes another seller up.

### Delivery

Did the seller deliver what you booked, on time?

| Field | Meaning |
| - | - |
| `sellers[].delivery.value.spend` | Delivered spend, including the platform fee. |
| `sellers[].delivery.value.budget` | Booked budget across the seller's media buys, including the fee. `null` when any of them has no budget. |
| `sellers[].delivery.value.impressions` | Delivered impressions. |
| `sellers[].delivery.value.budgetDelivered` | `spend` divided by `budget`. |
| `sellers[].delivery.value.pace` | Spend against an even pace across each buy's flight: `expectedSpend`, `actualSpend`, their `ratio` (`1` is exactly on pace) and a `verdict` of `on_pace`, `behind` or `ahead`. Each buy is paced over its own flight and the results are summed. A buy too early in its flight to judge is left out, rather than counted as on pace. `null` when no buy can be paced. |

Delivery ranks on how far `ratio` is from `1`, so under-delivery and
over-delivery both rank lower than delivery on pace.

### Price

What you paid per unit of the campaign's primary goal: per click for a click
goal, per completed view for a completed-view goal, and so on. When the goal
names something delivery cannot price, such as a purchase event, a viewable
rate or a vendor's metric, or when the campaign has no goal, the price is per
thousand impressions (eCPM). Every seller in one scorecard is priced in the
same unit.

| Field | Meaning |
| - | - |
| `sellers[].price.value.value` | Spend, including the platform fee, divided by the delivered units, times `perUnits`. |
| `sellers[].price.value.unit` | The unit priced. |
| `sellers[].price.value.perUnits` | How many of the unit the value prices: `1000` for impressions, otherwise `1`. |
| `sellers[].price.value.units` | The delivered units the spend was divided by. |
| `sellers[].price.value.currency` | The currency of the price. |

Price ranks cheapest first. A seller that delivered fewer units than goal
progress needs to give a verdict (for example 100 clicks or 20 leads)
shows its price but is not ranked on it. A seller that did not report the unit
has no price.

### Performance

Did the seller's media buys meet your goal? The value is the seller's
[goal progress](/v2/buyer/reporting/tasks/get-reporting-metrics#goal-progress),
judged over all its media buys in the campaign together, with the same rules as
the campaign's own goal progress. When your measurement records count a
vendor-measured goal, only records that name one of the seller's media buys
count toward it. A record for the whole campaign cannot be split between
sellers.

Performance ranks only sellers whose goal was judged: a lower cost ranks
higher for a cost target, and a higher rate ranks higher for a rate target.
When the goal's metric was not reported, the goal progress is still returned so
that `verdictWithheld` and `freshness.missingMetrics` say why, and the rank is
withheld as `not_reported`.

### Quality

Was the delivery viewable, valid and brand safe? Quality is not judged yet, so
it always reads as not reported.

## Errors

* `400 VALIDATION_ERROR`: a malformed or impossible `startDate` or `endDate` (such as `2026-02-31`), or a `startDate` after `endDate`.
* `403 FEATURE_NOT_ENABLED`: the account is not enrolled in the V3 beta.
* `404 NOT_FOUND`: no live campaign with this id on your account.
* `422 SPEND_DENOMINATION_UNRESOLVED` and `503 FX_RATE_UNAVAILABLE`: as for
  [Get reporting metrics](/v2/buyer/reporting/tasks/get-reporting-metrics#errors),
  which reads the same delivery.

See [Errors](/v2/reference/errors) for the full error contract.

## Related

<CardGroup cols={2}>
  <Card title="Get reporting metrics" href="/v2/buyer/reporting/tasks/get-reporting-metrics" icon="chart-line">
    The same delivery and goal progress, per media buy and campaign
  </Card>

  <Card title="Goal-seeking campaigns" href="/v2/concepts/goal-seeking-campaigns" icon="bullseye">
    How goals are stated, answered and judged
  </Card>
</CardGroup>


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