Viewcast direct measurement purchase

Buy a measurement directly from a display_id with POST /v2/viewcast/measurements/purchase/direct: the synchronous 200 contract, the locked final_measured asset, the 12-month subscription window, pricing, idempotency and replay, and the display_id reserve rule.

The direct measurement purchase endpoint lets you buy a measurement for a display without first creating a draft asset. It is the search-driven path: you found a display_id through the public display inventory (or a Displays inventory search), and you want to own the measurement for that display right away. Instead of the three-step lifecycle (create a draft asset, purchase a draft measurement, purchase a final measurement), one synchronous call mints a completed, final-measured asset owned by your organization.

POST /v2/viewcast/measurements/purchase/direct

The endpoint is on the v2 base https://api2.mworks.com. For the endpoint-by-endpoint reference, see the Viewcast API reference. For how the normal draft-to-final lifecycle works, see Displays On Demand measurements.

This page covers the direct purchase type only. The same /v2/viewcast/measurements/purchase/{type} route also serves the draft and final types for assets you already created; those are documented on the Displays On Demand pages.

When to use it

Use the direct purchase when:

  • you hold a display_id from inventory search or the public display inventory and want to acquire the measurement for it, and
  • you do not need the intermediate draft result; you want the final, measured asset in one step.

The result is a final_measured asset, owned by your organization, with both display_id and source_display_id set to the display_id you submitted. The purchase also starts a 12-month subscription window from the purchase date (see below).

Request

The request body is strict: unknown keys return 400. The field set matches the create-asset body of POST /v2/displays/assets (see Asset lifecycle), plus the display_id you are purchasing and the measurement_request_id idempotency key.

FieldTypeRequiredMeaning
display_idStringYesThe display identifier to purchase. Must be a non-empty string. Locked onto the minted asset: both display_id and source_display_id are set to this value. See the validation caveat below.
classificationStringYesRoadside or Place-Based. Immutable after mint: it cannot be changed later.
anchorObjectYes{ "lat": number, "lon": number } reference point for the face, used for viewshed construction.
related_partiesArrayNoCaller-side identifiers. At most 16 entries, each a flat object with role, party_name, party_display_id, and spots[] (same shape as asset creation).
displayObjectNoDisplay descriptor (for example height_in, width_in, digital, orientation). Sparse; sub-fields optional.
user_referenceString or nullNoFree-text caller reference.
measurement_request_idUUIDYesCaller-minted idempotency key (see below).

Classification is immutable: the value you submit at purchase time is final for the life of the asset. Choose it carefully: there is no PATCH path to correct it later (the minted asset rejects refine requests entirely, see below).

display_id is not yet validated against inventory: any non-empty string is accepted today. Existence validation ships in a later story. Until then, the display_id you submit is taken at face value, and a fabricated display_id still reserves that value globally (see the reserve rule below). Submit the exact identifier you found through search.

curl -X POST https://api2.mworks.com/v2/viewcast/measurements/purchase/direct \
  -H "Authorization: Bearer ***" \
  -H "Content-Type: application/json" \
  -d '{
    "display_id": "dsp_4471MYFACE",
    "classification": "Roadside",
    "anchor": { "lat": 34.0901, "lon": -118.3839 },
    "related_parties": [
      {
        "role": "owner",
        "party_name": "Console caller",
        "party_display_id": "my-face-4471",
        "spots": [ { "spot_id": "my-spot-9902" } ]
      }
    ],
    "user_reference": "sunset-billboard-campaign",
    "measurement_request_id": "550e8400-e29b-41d4-a716-446655440000"
  }'

Response

The purchase is synchronous: a successful call returns 200 OK with the freshly minted asset in the standard measurement result envelope.

{
  "data": {
    "asset_id": "vcaJDVDYWSSMHAXVEFYW1DVD2PPFD",
    "kind": "direct",
    "status": "completed"
  },
  "meta": {
    "request_id": "req_...",
    "credits_used": 300,
    "product": "viewcast"
  }
}

The data.kind is direct and data.status is completed: there is nothing to poll. The minted asset is in the final_measured state immediately.

What the purchase mints

The call creates a final_measured asset that is:

  • Owned by your organization.
  • Private (not published to the shared inventory surface).
  • Locked: the asset is in a terminal state. PATCH refine requests and DELETE archive requests both return 409. There is no way to modify or archive a direct-purchased asset through the API.
  • Identified: display_id and source_display_id are both set to the submitted value, so the asset joins to the broader Displays inventory surface by that identifier.

Pricing

The direct purchase costs 300 credits total: 1 cr base endpoint cost plus the 299 cr purchase charge (viewcast_viewshed_purchase_direct). If your wallet cannot fund the charge, the call returns 402 before any write: nothing is minted and no credit moves.

Idempotency and replay

measurement_request_id (any RFC 4122 UUID, minted client-side) is the idempotency key:

  • Same measurement_request_id + same body: returns the original 200 response at 0 credits, with the header X-MW-Idempotent-Replay: 1. No second asset is minted and no second charge occurs.
  • Same id + different body: returns 409 idempotency_mismatch, with any charge difference refunded.

Mint a fresh UUID for each genuinely new purchase.

The display_id reserve rule

One display_id maps to at most one live final_measured asset (a global unique index backs this):

  • If the display_id is already claimed by an existing final_measured asset, the call returns 409 before any charge.
  • A duplicate purchase by the same organization for the same display_id (with a different measurement_request_id) also returns 409, in that case after the charge, with the duplicate charge refunded.

Because display_id existence is not yet validated (see the caveat above), the reserve rule applies to whatever value you submit: a fabricated display_id reserves that value globally until the 12-month subscription window expires. Check your identifier carefully before submitting.

The 12-month subscription window

The purchase stamps a 12-month subscription window starting on the purchase date. The subscription governs licensed access to the display's profile through Viewcast Profiles: while the window is open, GET /v2/viewcast/profiles/{display_id} serves your organization as an owned read. At expiry the profile route fails closed until repurchase.

For the full subscription and renewal mechanics, see Purchase flow and credits.

How this relates to Viewcast Profiles

The Viewcast Profiles read endpoint (GET /v2/viewcast/profiles/{display_id}) is the consumption side: it serves the profile of a display your organization already owns a measurement for. The direct purchase is the acquisition side: it is how you acquire that ownership. An unowned caller reading the profile route receives 403 FEATURE_NOT_LICENSED pointing at this purchase surface; after a successful direct purchase, the same read serves your organization.

What to read next


Did this page help you?