Documentation contents

VCP 1 Documentation›API Reference

Playlists

User-owned playlists stored on your service — distinct from your own collections — with create, edit, and a conflict-safe reorder.

Advertise the playlists keyword in your manifest'scapabilities to mount all eight routes below. Playlists are user-owned state: every route requires an identity, writes require the playlists.write scope, and the two reads require onlylibrary.read. Everything here followsthe write model — ownership checks on every call, idempotent verbs, optimistic concurrency.

The playlist object

{
  "id": "pl_o2214",
  "title": "Rewatch queue",
  "description": "",
  "item_count": 3,
  "cover_url": "https://cdn.example.com/thumbs/88213.jpg",
  "version": "v41",
  "updated_at": "2026-07-16T09:30:00Z"
}

version is an opaque string (also served as the ETag) that changes on every mutation, including item changes. You may cap playlist size via limits.max_playlist_items in your manifest (default 1000).

Routes

RouteSemantics
GET /playlistsThe requesting user's playlists. Paginated.
POST /playlistsCreate: { "title", "description" } + Idempotency-Key → 201 playlist object.
PATCH /playlists/{id}Update metadata (any subset of title, description), If-Match recommended → 200 updated object.
DELETE /playlists/{id}Delete → 204, idempotent.
GET /playlists/{id}/itemsItems in order. Paginated.
POST /playlists/{id}/itemsAppend { "video_id" }, optional "position" (0-based insert) → 201 item.
DELETE /playlists/{id}/items/{item_id}Remove one item → 204, idempotent.
PUT /playlists/{id}/orderReorder — see below.

Playlist items

Items get their own item_id because the same video can appear twice in one playlist:

GET /playlists/{id}/items — 200 OK
{
  "items": [
    { "item_id": "pli_1", "video_id": "vid_88213", "added_at": "2026-07-10T11:00:00Z" },
    { "item_id": "pli_2", "video_id": "vid_11482", "added_at": "2026-07-11T18:20:00Z" }
  ],
  "next_cursor": null
}

Working with playlists

# Create (Idempotency-Key makes retries safe)
curl -X POST "https://api.example.com/vcp/v1/playlists" \
  -H "VCP-Service-Token: vcps_a81f42..." \
  -H "Authorization: Bearer vcpa_71be02..." \
  -H "Idempotency-Key: 9c4a7ee2-51b0-4de1-8a3f-2f4c01a4b9d7" \
  -H "Content-Type: application/json" \
  -d '{ "title": "Rewatch queue", "description": "" }'

# Append a video
curl -X POST "https://api.example.com/vcp/v1/playlists/pl_o2214/items" \
  -H "VCP-Service-Token: vcps_a81f42..." \
  -H "Authorization: Bearer vcpa_71be02..." \
  -H "Idempotency-Key: 3f7d9a10-6c2e-4b5f-9e81-b04d7c22e6aa" \
  -H "Content-Type: application/json" \
  -d '{ "video_id": "vid_88213" }'

# Reorder (full order replacement, guarded by If-Match)
curl -X PUT "https://api.example.com/vcp/v1/playlists/pl_o2214/order" \
  -H "VCP-Service-Token: vcps_a81f42..." \
  -H "Authorization: Bearer vcpa_71be02..." \
  -H "If-Match: v41" \
  -H "Content-Type: application/json" \
  -d '{ "item_ids": ["pli_2", "pli_1"] }'

Reordering

Reordering is a full-order replacement — one idempotent request, no move-operation grammar to get wrong. Send the complete list of current item ids in the new order, guarded by If-Match:

  • Success → 200 with the updated playlist object (new version).
  • The item_ids array must contain exactly the playlist's current item ids — a mismatch is 409 conflict.
  • A stale If-Match is 412 precondition_failed — the client refetches items and reapplies the user's intended order.

Coming soon!

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