Skip to main content
The PunchPlay Platform API supports two app-bound auth patterns:
  • Authorization code + PKCE for browser apps and websites
  • Device code for TV, desktop, and native-style clients
Both flows issue scoped bearer tokens for /api/platform/v1.

Register your app first

Create a developer app at Get API key. Each app receives a stable client_id.
  • Confidential clients also receive a client_secret
  • Public clients use client_id only
  • Every app defines its maximum allowed_scopes
  • The approval screen shows the app name and requested scopes before the user approves access

Client types

Client typeBest forCredentialsGuidance
PublicBrowser apps, native apps, desktop apps, TV appsclient_idDo not embed a secret you cannot protect
ConfidentialServer-backed apps and websitesclient_id + client_secretKeep the secret server-side only

Current scopes

Apps can currently request these scopes:
  • profile:read
  • playback:read
  • playback:write
  • events:read
If a request omits scope, PunchPlay grants the app’s configured allowed_scopes. If a request asks for a scope outside the app’s allowed_scopes, the request fails with invalid_scope.

Flow selection

Use this rule:
  • Use authorization code + PKCE for browser apps and websites that can redirect a user
  • Use device code for TV, desktop, CLI, and native-style clients that cannot handle a normal browser callback cleanly

Authorization code + PKCE

1. Redirect the user to PunchPlay

GET https://punchplay.tv/api/platform/v1/oauth/authorize
Required query parameters:
  • response_type=code
  • client_id=YOUR_CLIENT_ID
  • redirect_uri=YOUR_REGISTERED_REDIRECT_URI
  • code_challenge=BASE64URL_SHA256_OF_CODE_VERIFIER
  • code_challenge_method=S256
Optional:
  • scope=profile:read playback:read playback:write events:read
  • state=YOUR_OPAQUE_STATE
Example:
https://punchplay.tv/api/platform/v1/oauth/authorize?response_type=code&client_id=YOUR_CLIENT_ID&redirect_uri=https%3A%2F%2Fexample.com%2Fauth%2Fpunchplay%2Fcallback&code_challenge=YOUR_PKCE_CHALLENGE&code_challenge_method=S256&scope=profile%3Aread%20playback%3Aread%20playback%3Awrite&state=YOUR_STATE
PunchPlay authenticates the user if needed, shows the consent screen, then redirects back to your redirect_uri with:
  • code
  • state if you sent one
  • scope
If the request cannot be completed, PunchPlay redirects back with an error. Redirect-based failures may also include request_id so the developer has something concrete to report. Users can review and revoke approved apps later from https://punchplay.tv/settings/connected-apps.

2. Exchange the code for tokens

curl -X POST https://punchplay.tv/api/platform/v1/oauth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=authorization_code" \
  -d "client_id=YOUR_CLIENT_ID" \
  -d "client_secret=YOUR_CLIENT_SECRET" \
  -d "code=AUTHORIZATION_CODE" \
  -d "redirect_uri=https://example.com/auth/punchplay/callback" \
  -d "code_verifier=YOUR_ORIGINAL_PKCE_VERIFIER"
Public apps send client_id only. Confidential apps send both client_id and client_secret. Successful response:
{
  "access_token": "access_token",
  "refresh_token": "refresh_token",
  "token_type": "bearer",
  "expires_in": 2592000,
  "refresh_expires_in": 31536000,
  "scope": "profile:read playback:read playback:write"
}

3. Refresh the access token

curl -X POST https://punchplay.tv/api/platform/v1/oauth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=refresh_token" \
  -d "client_id=YOUR_CLIENT_ID" \
  -d "client_secret=YOUR_CLIENT_SECRET" \
  -d "refresh_token=REFRESH_TOKEN"

Device code

1. Request a device code

curl -X POST https://punchplay.tv/api/platform/v1/auth/device/code \
  -H "Content-Type: application/json" \
  -d '{
    "client_id": "YOUR_CLIENT_ID",
    "client_secret": "YOUR_CLIENT_SECRET",
    "scope": "profile:read playback:read playback:write events:read"
  }'
Public clients omit client_secret. Response fields:
FieldMeaning
user_codeShort code shown to the user
device_codeOpaque code your app uses to poll
verification_uriApproval page
verification_uri_completeApproval page with code prefilled
verification_uri_qrQR code image data
expires_inDevice-code lifetime in seconds
scopeThe scope set that will be attached to issued tokens

2. Poll the token endpoint

curl -X POST https://punchplay.tv/api/platform/v1/auth/device/token \
  -H "Content-Type: application/json" \
  -d '{
    "client_id": "YOUR_CLIENT_ID",
    "client_secret": "YOUR_CLIENT_SECRET",
    "device_code": "raw_device_code",
    "device_name": "PunchPlay Companion",
    "device_id": "living-room-mac"
  }'
Pending approval returns:
{ "error": "authorization_pending", "message": "Device code has not been approved yet.", "request_id": "ppreq_..." }
Success returns:
{
  "access_token": "access_token",
  "refresh_token": "refresh_token",
  "token_type": "bearer",
  "expires_in": 2592000,
  "refresh_expires_in": 31536000,
  "username": "scott",
  "scope": "profile:read playback:read playback:write events:read"
}

3. Refresh the access token

curl -X POST https://punchplay.tv/api/platform/v1/auth/refresh \
  -H "Content-Type: application/json" \
  -d '{
    "client_id":"YOUR_CLIENT_ID",
    "client_secret":"YOUR_CLIENT_SECRET",
    "refresh_token":"REFRESH_TOKEN"
  }'
Successful response:
{
  "access_token": "new_access_token",
  "token_type": "bearer",
  "expires_in": 2592000,
  "scope": "profile:read playback:read playback:write"
}

Authenticated requests

Use the access token in the Authorization header:
Authorization: Bearer ACCESS_TOKEN
Platform tokens are scoped to the platform namespace and intended for endpoints under /api/platform/v1.

Debugging auth failures

Platform auth errors include:
  • request_id in the JSON body
  • X-PunchPlay-Request-Id in the response headers
When reporting a failure, capture:
  • request_id
  • UTC timestamp
  • endpoint path
  • client_id
  • status code
  • raw error body

Security guidance

  • Treat client_secret, refresh tokens, and access tokens as sensitive credentials.
  • Do not embed client_secret in native apps, browser apps, or sample code intended for public distribution.
  • Use public clients when your app cannot safely hold a secret.
  • Keep allowed_scopes as narrow as possible for each app.
  • Rotate secrets immediately if you suspect they were exposed.
  • Deactivate an app if you need to revoke its issued tokens quickly.
  • If your app runs entirely in the browser, keep in mind that standard EventSource clients cannot attach custom authorization headers.
Poll every few seconds until the user approves the request or the device code expires. Back off if your app has multiple concurrent authorization attempts.

Check the authenticated identity

After obtaining a token, verify who you are acting as:
curl https://punchplay.tv/api/platform/v1/me \
  -H "Authorization: Bearer ACCESS_TOKEN"