Documentation contents

VCP 1 Documentation

Request Conventions

The headers, pagination, caching, and data rules shared by every VCP endpoint — learn them once, they apply everywhere.

All request and response bodies are application/json, UTF-8, over HTTPS (TLS 1.2+). There is no request-signing layer: TLS provides integrity and confidentiality, and the service token authenticates the gateway.

Headers

Every API request from the gateway to your server looks like this:

GET {api_base}/collections HTTP/1.1
VCP-Service-Token: vcps_a81f42...
Authorization: Bearer vcpa_71be02...
VCP-User-Token: vcpu_5f19ab...
VCP-Client: vctv-ios/2.4.1
VCP-Client-IP: 203.0.113.40
Accept: application/json
HeaderPresenceMeaning
VCP-Service-TokenAlwaysGateway identification — see the service token.
AuthorizationWith a sessionEnd-user session credential: a pasted API key or a paired access token.
VCP-User-TokenWhen suppliedPrivileged-access user token.
VCP-ClientAlwaysApp name/version, for your analytics and debugging. Never key behavior on it.
VCP-Client-IPAlwaysThe end-user device's public IP as seen by the gateway. If you geo-restrict or sign media URLs against an IP, use this — never the connecting (gateway) IP, because media is fetched by the device.

Pagination

Every list endpoint is cursor-based:

  • Request — ?limit=50&cursor=…, with limit capped at your manifest's limits.max_page_size (default 100).
  • Response — "next_cursor": "…", an opaque string that is absent or null on the last page.

Cursors must remain valid for at least 10 minutes and must be treated as opaque — consumers never parse them. Draining a full list looks like this:

# First page
curl "https://api.example.com/vcp/v1/collections?limit=100" \
  -H "VCP-Service-Token: vcps_a81f42..."

# Follow next_cursor from each response until it comes back null
curl "https://api.example.com/vcp/v1/collections?limit=100&cursor=eyJvIjoxMDB9" \
  -H "VCP-Service-Token: vcps_a81f42..."

Caching

List and detail responses should include an ETag; the gateway sendsIf-None-Match and handles 304 Not Modified:

# First fetch: note the ETag response header
curl -i "https://api.example.com/vcp/v1/collections" \
  -H "VCP-Service-Token: vcps_a81f42..."
# HTTP/1.1 200 OK
# ETag: "col-list-v18"

# Later fetch: send it back — an unchanged list costs almost nothing
curl -i "https://api.example.com/vcp/v1/collections" \
  -H "VCP-Service-Token: vcps_a81f42..." \
  -H 'If-None-Match: "col-list-v18"'
# HTTP/1.1 304 Not Modified

Every object also carries updated_at (RFC 3339 UTC) — the basis fordelta sync, and the fallback comparison for providers without it.

Common data rules

RuleValue
IDsOpaque strings, stable forever, ≤ 128 chars, [A-Za-z0-9_-].
TimestampsRFC 3339 UTC — 2026-07-16T09:30:00Z.
Durations / positionsSeconds, as a JSON number.
Language tagsBCP 47 — en, pt-BR.
Unknown JSON fieldsIgnored by consumers; allowed for provider extensions (prefix custom fields x_).

Rate limiting

You may rate-limit per end-user token and overall per publisher integration. If you do, respond 429 with a Retry-After header when exceeded — the gateway backs off with exponential delay plus jitter. SeeError Handling for the full retry rules.

Coming soon!

We're putting the finishing touches on VClarity. It'll be on the App Store and Google Play very soon.