M Motionworks Population Intelligence

Minting an Anytime tile grant

Tile access runs through grants: a minted record that authorizes your organization to fetch Popcast Anytime vector tiles. A grant returns a tile_json_url capability URL you drop into MapLibre or Mapbox GL JS.

All grant management endpoints are free (0 credits): grant CRUD and the TileJSON fetch are control-plane operations. Only the tile bytes (GET .../anytime/{layer}/{z}/{x}/{y}.mvt) are metered, at 1 credit per 1000 tiles.

Prerequisites

  • Your organization must be licensed for the popcast.anytime.segment_occ_tiles feature. This feature is manual-grant-only: an explicit grant row is required. Unlicensed orgs get 403 FEATURE_NOT_LICENSED. Contact sales for an explicit grant.
  • Credentials: a signed-in session token (Authorization: Bearer <token>) or an org-scoped X-API-Key. Anonymous callers cannot mint grants. Grants are attributed to the user who created them, so an API key must have been created by a user (see API_KEY_NO_AUDIT_USER below).

Create a grant

POST /v2/popcast/tiles/anytime/grants

Request body:

Field Type Meaning
name string (max 120) Human-readable label, shown in the developer dashboard
tilesets string[] Tileset slugs (the catalog's slug field) from the discovery catalog. An empty array means every tileset currently published; the grant is stored with the expanded concrete list, so tilesets published later need a new grant. A slug that is not published is rejected with 403 TILE_LAYER_NOT_LICENSED.
allowed_origins string[] Browser Origin allowlist for tilejson and tile fetches. Wildcards are not supported; list each origin literally. Use the explicit string "null" to allow requests that omit Origin (server-side rendering, curl).
expires_at ISO 8601 datetime Grant expiry. Note the tile-token inside the TileJSON independently expires 24h after each mint; re-fetch TileJSON before then.

Example:

curl -X POST "https://api2.mworks.com/v2/popcast/tiles/anytime/grants" \
  -H "X-API-Key: <your-org-api-key>" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Q3 campaign map",
    "tilesets": [],
    "allowed_origins": ["https://maps.example.com"],
    "expires_at": "2026-12-31T00:00:00Z"
  }'

Response (201):

{
  "data": {
    "grant_id": "01J5XH9K3W2Q5M0N8P7R4T6VYC",
    "tile_json_url": "https://api2.mworks.com/v2/popcast/tiles/anytime/grants/01J5XH9K3W2Q5M0N8P7R4T6VYC/tilejson",
    "tilesets": ["tiles_anytime_v2_3_21d529097c81af04_202501_202512_bg_v1", "tiles_anytime_v2_3_21d529097c81af04_202501_202512_zcta_v1", "..."],
    "allowed_origins": ["https://maps.example.com"],
    "expires_at": "2026-12-31T00:00:00Z",
    "created_at": "2026-08-08T20:05:11Z"
  }
}

The tile_json_url is a capability URL: treat it like an AWS S3 presigned URL. The opaque grant_id segment IS the credential; anyone holding the URL can render tiles from an allowed origin until the grant expires or is revoked. Two safety nets are built in: allowed_origins pins which sites can fetch tiles (Origin-enforced), and revoke kills the grant.

The entitlement is one-feature-all-tilesets: a license for Popcast Anytime Maptiles covers every published tileset. There is no per-segment scoping.

List, read, revoke

Operation Endpoint Notes
List grants GET /v2/popcast/tiles/anytime/grants Your organization's grants, most recent first. Each grant carries usage_30d, reported as 0 today until usage reporting ships.
Read one GET /v2/popcast/tiles/anytime/grants/{id} Scoped to the caller's org; expired or foreign grants read as 404.
Revoke POST /v2/popcast/tiles/anytime/grants/{id}/revoke Revokes the grant immediately. New TileJSON requests for it fail with 404, and tile requests that use tokens already minted from it are refused as well (401 UNAUTHORIZED with error.context.reason: grant_revoked), so revoking is the instant cutoff for a leaked URL. Revoking an already-revoked grant returns 200 with the unchanged record.

Error cases

  • 403 FEATURE_NOT_LICENSED: org has no explicit grant for popcast.anytime.segment_occ_tiles. Contact sales.
  • 403 TILE_LAYER_NOT_LICENSED: a tilesets[] entry names a slug Popcast Anytime does not publish. Fires on unpublished slugs only, never as a licensed-subset rejection (the entitlement is all-tilesets). The error's context.missing lists the offending slugs.
  • 403 API_KEY_NO_AUDIT_USER: the API key is not tied to a user, so the grant cannot be attributed. Mint with a signed-in session, or with an API key created by a user.
  • 403 TILE_GRANTS_REQUIRE_METERED: your organization has no pay-as-you-go (metered) billing. Contact sales to enable metered tile delivery.
  • 403 ORIGIN_NOT_ALLOWED: the fetch's Origin is not in allowed_origins.
  • 400: invalid request body. 401: missing or invalid credentials.

Deny envelope: every error response on this surface uses the standard envelope shape. Example for an unlicensed org:

{
  "error": {
    "code": "FEATURE_NOT_LICENSED",
    "message": "Your organization is not licensed for popcast.anytime.segment_occ_tiles.",
    "status": 403,
    "request_id": "req_e8281bd0f5a1",
    "product": "popcast",
    "context": {}
  }
}

Expired grants read as 404 NOT_FOUND (Grant expired.), not 403 or 410: a foreign, nonexistent, or expired grant id is indistinguishable from the outside. A revoked grant stays readable through the grant endpoints with revoked_at set, but its TileJSON returns 404 and every tile request made with a token minted from it is refused with 401 UNAUTHORIZED (grant_revoked), even if that token has not yet expired.

Token lifecycle

Each GET /tilejson mints a fresh tile token valid for 24 hours, embedded in tiles[]. A Popcast Anytime token never authorizes another product's tiles. The manifest's x-mw.refresh_after (82,800 seconds, 23h) tells clients when to re-fetch the TileJSON for a fresh token. Standard TileJSON consumers append the ?token= query to every tile request automatically; you do not call the .mvt endpoint by hand. Revoking the grant invalidates outstanding tokens immediately (see above).