Viewcast batch measurement purchase
Buy up to 100 measurements in one call with POST /v2/viewcast/measurements/purchase/{draft,final,direct}/batch: the batch body with its whole-batch idempotency key, per-item outcomes in submission order, pricing where only queued items bill, and the per-type rules for draft, final, and direct items.
The batch measurement purchase endpoints buy measurements for 1 to 100 targets in one synchronous call. Instead of looping the single-purchase endpoint client-side, you submit the whole list in one request and get back one outcome per item, in your submission order. One call buys one purchase type: the type (draft, final, or direct) sits in the path, and every item runs exactly the single-purchase flow for that type. One item's failure never blocks another.
POST /v2/viewcast/measurements/purchase/{draft,final,direct}/batch
The endpoints are on the v2 base https://api2.mworks.com. For the endpoint-by-endpoint reference, see the Viewcast API reference. For the draft and final single purchases on the same route family, see Displays On Demand measurements. For the single-item direct path, see Viewcast direct measurement purchase.
When to use it
Use the batch surface when you are buying for many targets at once:
- a list of
asset_ids you own, buyingdraftorfinalmeasurements for all of them, or - a list of
display_ids from inventory search, buying them all directly.
For a single target, use the single-purchase endpoints: same flow, less ceremony.
Request
The body has two fields: a whole-batch idempotency key and the item list.
| Field | Type | Required | Meaning |
|---|---|---|---|
purchase_request_id | UUID | Yes | Your idempotency identifier for the whole batch (see below). |
items | Array of 1 to 100 items | Yes | The items to purchase, processed in submission order. |
Each item carries the target plus a per-item idempotency id. draft and final items take owned assets:
| Field | Type | Required | Meaning |
|---|---|---|---|
asset_id | String | Yes | An asset owned by your organization. |
measurement_request_id | UUID | Yes | Per-item idempotency identifier. |
direct items take display identifiers:
| Field | Type | Required | Meaning |
|---|---|---|---|
display_id | String | Yes | The display to purchase, as issued by the Motionworks display catalog. |
measurement_request_id | UUID | Yes | Per-item idempotency identifier. |
The body is strict: unknown keys return 400 naming the rejected field, and so do an empty item list, more than 100 items, non-UUID identifiers, the retired kind body field, and the Idempotency-Key header (batch idempotency lives in purchase_request_id).
curl -X POST https://api2.mworks.com/v2/viewcast/measurements/purchase/draft/batch \
-H "Authorization: Bearer ***" \
-H "Content-Type: application/json" \
-d '{
"purchase_request_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"items": [
{
"asset_id": "vcaJDVDYWSSMHAXVEFYW1DVD2PPFD",
"measurement_request_id": "550e8400-e29b-41d4-a716-446655440000"
},
{
"asset_id": "vcaQTWJBXSKGHFL4Z1MV9DPWRX",
"measurement_request_id": "6ba7b810-9dad-11d1-80b4-00c04fd430c8"
}
]
}'Response
The call is synchronous: every item is processed before the response returns. A successful call returns 202 Accepted with one outcome per item in your submission order. Queued draft items then complete through the normal measurement pipeline; poll them as usual (see Displays On Demand measurements).
{
"data": {
"purchase_request_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"type": "draft",
"submitted_at": "2026-09-13T14:02:11Z",
"completed_at": "2026-09-13T14:02:14Z",
"items": [
{
"target": "vcaJDVDYWSSMHAXVEFYW1DVD2PPFD",
"outcome": "queued",
"measurement_id": "9c8b7a6b-5d4e-4f3a-8b2c-1d0e9f8a7b6c",
"processed_at": "2026-09-13T14:02:12Z"
},
{
"target": "vcaQTWJBXSKGHFL4Z1MV9DPWRX",
"outcome": "skipped:not_owned",
"processed_at": "2026-09-13T14:02:13Z"
}
],
"queued_count": 1
},
"meta": {
"request_id": "req_...",
"credits_used": 150,
"product": "viewcast"
}
}Each item echoes its target (asset_id for draft and final, display_id for direct) and carries a processed_at terminal timestamp. Queued items carry the minted measurement_id; queued direct items also carry the minted asset_id. The full outcome set:
| Outcome | Billed | Meaning |
|---|---|---|
queued | Yes | The item charged and queued exactly as the single-purchase flow. |
skipped:not_owned | No | The asset_id is not owned by your organization. |
skipped:bad_state | No | The asset's current state does not allow this purchase type. |
skipped:already_measured | No | The asset already holds the measurement this purchase would queue. |
skipped:idempotent_replay | No | The item's per-item replay key was already recorded; the recorded outcome returns at no charge. |
skipped:not_in_catalog | No | Direct only: the catalog has no entry for the display_id. |
skipped:already_licensed | No | Direct only: your organization already licenses the display_id. |
skipped:duplicate_in_batch | No | The same target appears twice in this batch; only the first occurrence is processed. |
failed:insufficient_credits | No | The wallet could not fund this item's charge (the per-item 402); the batch continued past it. |
failed:not_available | No | The purchase could not run; see the final-type posture below. |
failed:upstream | No | An upstream dependency failed while processing the item. |
Pricing
The call costs a 1 credit base (once per call) plus the per-item purchase delta for every item that queues: 149 credits per queued draft item, 299 credits per queued final or direct item. A queued item therefore costs exactly the single-purchase total: 150 credits for a draft item, 300 credits for a final or direct item. Total charge = 1 + (rate - 1) x queued_count.
Skipped and failed items bill nothing. There is no whole-call wallet pre-check: each item charges on its own, and an item your wallet cannot fund surfaces as failed:insufficient_credits while the rest of the batch continues. The example response above charged 150 credits: one queued draft item plus the 1 credit base.
Idempotency and replay
purchase_request_id (any RFC 4122 UUID, minted client-side) is the idempotency key for the whole batch, and each item carries its own measurement_request_id:
- Same
purchase_request_id+ same item list in the same order: returns the recorded outcomes at 0 credits, with the headerX-MW-Idempotent-Replay: 1. Nothing is queued or charged a second time. - Same id + a different item list (or the same items reordered): returns 409
idempotency_mismatch. The mismatch is rejected before anything is charged. - Same id while a batch with that id is still processing: returns 409; retry shortly.
Per-item replay keys are derived server-side as <purchase_request_id>:<measurement_request_id>, so a batch retried under the same purchase_request_id never double-bills an item that already queued: on reprocessing, such an item reports skipped:idempotent_replay at no charge.
Mint a fresh purchase_request_id for each genuinely new batch, and a fresh measurement_request_id for each item in it.
Type-specific behavior
- draft: every item runs the single draft-purchase flow: ownership and state guards, then charge and queue. Queued items complete through the normal production pipeline; poll
GET /v2/viewcast/measurements/{asset_id}for completion. - final: the final measurement provider is stubbed upstream, so today every item reports
failed:not_availableand nothing is charged beyond the 1 credit base. When the provider is wired, each item will run the single final-purchase flow at the 300 credit rate. - direct: every item runs the single direct-purchase flow against the display catalog, with lookups fanned out to at most 10 concurrent requests. A
display_idthe catalog does not return reportsskipped:not_in_catalog, and adisplay_idyour organization already licenses reportsskipped:already_licensed; both are decided before any charge. Queued items mintfinal_measuredassets synchronously, and each starts its own 12-month subscription window.
What to read next
- Displays On Demand measurements - the single draft and final purchase and poll contract.
- Viewcast direct measurement purchase - the single-item direct path.
- Purchase flow and credits - the credit model, refunds, and the subscription window.
- Viewcast Profiles - the licensed profile read.
- Viewcast API reference - auto-built endpoint documentation.
Updated about 2 hours ago
