Five-minute agent workflow
Build the checkout CLI and start the stack from the verified quickstart.
screenrig account create --email agent-owner@example.com --json # POST /api/v1/accounts
screenrig app upload ./built-webapp --json # POST /api/v1/applications
screenrig playlist create ./playlist.json --json # POST /api/v1/playlists
screenrig screen pair --code ABCDEF --label "Lobby" --json # POST /api/v1/screens/pair
screenrig screen assign scr_example --playlist-id pl_example --if-match 1 --json
screenrig events follow --json # GET /api/v1/events/streamExpected: mutations return revisioned resources or durable operations; event follow emits opaque cursors. Values are placeholders.
Base URLs and credential realms
https://screenrig.ai serves the live, HTTPS-verified public marketing and documentation site. https://api.screenrig.ai and https://play.screenrig.ai are architectural service origins only; the API, Player, release hosts, and protected content are not deployed or verified there. Verified local service equivalents are http://api.screenrig.localhost:8088 and http://play.screenrig.localhost:8088.
- accountBearer
- Account API only; never runtime/content/release authority.
- pairing, device, runtime cookies
- Trusted Player origin only, with distinct profiles.
- placementCapability
- Short-lived, placement-scoped K/V authority.
- launch ticket, release grant
- Single-use launch and exact release-host delivery.
- operatorBearer
- Separate operator realm.
Status: /.health, /.ready, /.version. Limits: /api/v1/capabilities.
Common request semantics
- Idempotency: retry only the same mutation with the same key; mismatch returns
409 idempotency_mismatch. - Revisions: changes require
If-Match; stale writes return412 revision_conflict. - Cursors: list and SSE cursors are opaque.
- Operations: uploads may begin in
receiving, then usequeued,running,succeeded,failed, orcancelled. - SSE: resume with the last cursor or
Last-Event-ID. Astream.resync_requiredframe means refetch authoritative state and resume at its supplied head cursor. - Limits: use capabilities; rate limiting returns
429 rate_limited.
Upload lifecycles
Applications
Submit an already-built deterministic archive and wait for validation, extraction, and immutable publication. The service does not build or execute uploaded source.
Media
Declare exact type, size, and hash; follow the signed raw PUT method and headers verbatim; commit and wait. Never log or reconstruct signed URLs or headers.
Runtime and protected content
Pairing, device/runtime sessions, manifests, reports, events, launch tickets, and runtime K/V live on the trusted Player origin. Manifest media supports contract-defined ranges; release assets use exact isolated hosts.
RFC 9457 problems
Errors use application/problem+json. Branch on status and stable code, never detail. Generated from problems.yaml.
internal_error500 · Internal server error
type: https://screenrig.ai/problems/internal-errorinvalid_request400 · Request is invalid
type: https://screenrig.ai/problems/invalid-requestunauthorized401 · Authentication is required
type: https://screenrig.ai/problems/unauthorizedforbidden403 · Request is not allowed
type: https://screenrig.ai/problems/forbiddennot_found404 · Resource was not found
type: https://screenrig.ai/problems/not-foundmethod_not_allowed405 · Method is not allowed
type: https://screenrig.ai/problems/method-not-allowedidempotency_mismatch409 · Idempotency key does not match the original request
type: https://screenrig.ai/problems/idempotency-mismatchaccount_exists409 · Account already exists
type: https://screenrig.ai/problems/account-existsresource_conflict409 · Resource state conflicts with the request
type: https://screenrig.ai/problems/resource-conflictrevision_conflict412 · Resource revision does not match
type: https://screenrig.ai/problems/revision-conflictinvalid_range416 · Requested byte range is not satisfiable
type: https://screenrig.ai/problems/invalid-rangequota_exceeded413 · Account content quota is exceeded
type: https://screenrig.ai/problems/quota-exceededrate_limited429 · Request rate is too high
type: https://screenrig.ai/problems/rate-limiteddependency_unavailable503 · Required dependency is unavailable
type: https://screenrig.ai/problems/dependency-unavailableschema_incompatible503 · Database schema is incompatible
type: https://screenrig.ai/problems/schema-incompatiblenot_ready503 · Service is not ready
type: https://screenrig.ai/problems/not-readyVersioning and troubleshooting
OpenAPI contract: 0.2.0. Run screenrig doctor --json; use doctor --repair-config for config permissions and curl --noproxy '*' if a proxy intercepts .localhost. Redact secrets, cookies, signed URLs, object keys, and customer content.
Complete endpoint inventory
50 operations generated from api/openapi.yaml. Examples are contract-generated localhost templates, not a browser console.
Service status and capabilities
Get health
curl --noproxy '*' --request GET 'http://api.screenrig.localhost:8088/.health'Get readiness
curl --noproxy '*' --request GET 'http://api.screenrig.localhost:8088/.ready'Get version
curl --noproxy '*' --request GET 'http://api.screenrig.localhost:8088/.version'Get capabilities
curl --noproxy '*' --request GET 'http://api.screenrig.localhost:8088/api/v1/capabilities'Accounts and credentials
Create account
curl --noproxy '*' --request POST --header 'Idempotency-Key: REQUEST_ID' --header 'Content-Type: application/json' --data '@request.json' 'http://api.screenrig.localhost:8088/api/v1/accounts'{
"email": "string"
}Get account
curl --noproxy '*' --request GET --header 'Authorization: Bearer SCREENRIG_TOKEN' 'http://api.screenrig.localhost:8088/api/v1/account'Acknowledge credential issuance
curl --noproxy '*' --request POST --header 'Authorization: Bearer SCREENRIG_TOKEN' 'http://api.screenrig.localhost:8088/api/v1/account/credential-issuances/RESOURCE_ID/ack'Applications and operations
List applications
curl --noproxy '*' --request GET --header 'Authorization: Bearer SCREENRIG_TOKEN' 'http://api.screenrig.localhost:8088/api/v1/applications'Upload application
Streams one CLI-produced tar.gz directly into bounded durable staging. Metadata is carried in headers so the archive is never base64-wrapped or materialized as JSON by the server.
curl --noproxy '*' --request POST --header 'Authorization: Bearer SCREENRIG_TOKEN' --header 'Idempotency-Key: REQUEST_ID' --header 'ScreenRig-Archive-SHA256: VALUE' --header 'ScreenRig-Expanded-Bytes: VALUE' --header 'ScreenRig-File-Count: VALUE' --header 'Content-Type: application/json' --data '@request.json' 'http://api.screenrig.localhost:8088/api/v1/applications'"string"Get application
curl --noproxy '*' --request GET --header 'Authorization: Bearer SCREENRIG_TOKEN' 'http://api.screenrig.localhost:8088/api/v1/applications/RESOURCE_ID'Get operation
curl --noproxy '*' --request GET --header 'Authorization: Bearer SCREENRIG_TOKEN' 'http://api.screenrig.localhost:8088/api/v1/operations/RESOURCE_ID'Cancel operation
curl --noproxy '*' --request POST --header 'Authorization: Bearer SCREENRIG_TOKEN' --header 'Idempotency-Key: REQUEST_ID' 'http://api.screenrig.localhost:8088/api/v1/operations/RESOURCE_ID/cancel'Media uploads
List media
curl --noproxy '*' --request GET --header 'Authorization: Bearer SCREENRIG_TOKEN' 'http://api.screenrig.localhost:8088/api/v1/media'Create media upload
curl --noproxy '*' --request POST --header 'Authorization: Bearer SCREENRIG_TOKEN' --header 'Idempotency-Key: REQUEST_ID' --header 'Content-Type: application/json' --data '@request.json' 'http://api.screenrig.localhost:8088/api/v1/media/uploads'{
"filename": "string",
"content_type": "image/png",
"bytes": 1,
"sha256": "string"
}Commit media upload
curl --noproxy '*' --request POST --header 'Authorization: Bearer SCREENRIG_TOKEN' --header 'Idempotency-Key: REQUEST_ID' --header 'Content-Type: application/json' --data '@request.json' 'http://api.screenrig.localhost:8088/api/v1/media/uploads/RESOURCE_ID/commit'{
"content_type": "image/png",
"bytes": 1,
"sha256": "string"
}Get media
curl --noproxy '*' --request GET --header 'Authorization: Bearer SCREENRIG_TOKEN' 'http://api.screenrig.localhost:8088/api/v1/media/RESOURCE_ID'Delete media
curl --noproxy '*' --request DELETE --header 'Authorization: Bearer SCREENRIG_TOKEN' --header 'If-Match: "1"' --header 'Idempotency-Key: REQUEST_ID' 'http://api.screenrig.localhost:8088/api/v1/media/RESOURCE_ID'Playlists
List playlists
curl --noproxy '*' --request GET --header 'Authorization: Bearer SCREENRIG_TOKEN' 'http://api.screenrig.localhost:8088/api/v1/playlists'Create playlist
curl --noproxy '*' --request POST --header 'Authorization: Bearer SCREENRIG_TOKEN' --header 'Idempotency-Key: REQUEST_ID' --header 'Content-Type: application/json' --data '@request.json' 'http://api.screenrig.localhost:8088/api/v1/playlists'{
"name": "string",
"pages": [
{}
]
}Get playlist
curl --noproxy '*' --request GET --header 'Authorization: Bearer SCREENRIG_TOKEN' 'http://api.screenrig.localhost:8088/api/v1/playlists/RESOURCE_ID'Update playlist
curl --noproxy '*' --request PUT --header 'Authorization: Bearer SCREENRIG_TOKEN' --header 'If-Match: "1"' --header 'Idempotency-Key: REQUEST_ID' --header 'Content-Type: application/json' --data '@request.json' 'http://api.screenrig.localhost:8088/api/v1/playlists/RESOURCE_ID'{
"name": "string",
"pages": [
{}
]
}Delete playlist
curl --noproxy '*' --request DELETE --header 'Authorization: Bearer SCREENRIG_TOKEN' --header 'If-Match: "1"' --header 'Idempotency-Key: REQUEST_ID' 'http://api.screenrig.localhost:8088/api/v1/playlists/RESOURCE_ID'Screens and control-plane pairing
List screens
curl --noproxy '*' --request GET --header 'Authorization: Bearer SCREENRIG_TOKEN' 'http://api.screenrig.localhost:8088/api/v1/screens'Pair screen
curl --noproxy '*' --request POST --header 'Authorization: Bearer SCREENRIG_TOKEN' --header 'Idempotency-Key: REQUEST_ID' --header 'Content-Type: application/json' --data '@request.json' 'http://api.screenrig.localhost:8088/api/v1/screens/pair'{
"code": "string",
"label": "string"
}Get screen
curl --noproxy '*' --request GET --header 'Authorization: Bearer SCREENRIG_TOKEN' 'http://api.screenrig.localhost:8088/api/v1/screens/RESOURCE_ID'Update screen
curl --noproxy '*' --request PATCH --header 'Authorization: Bearer SCREENRIG_TOKEN' --header 'If-Match: "1"' --header 'Idempotency-Key: REQUEST_ID' --header 'Content-Type: application/json' --data '@request.json' 'http://api.screenrig.localhost:8088/api/v1/screens/RESOURCE_ID'{
"name": "string",
"playlist_id": "string"
}Delete screen
curl --noproxy '*' --request DELETE --header 'Authorization: Bearer SCREENRIG_TOKEN' --header 'If-Match: "1"' --header 'Idempotency-Key: REQUEST_ID' 'http://api.screenrig.localhost:8088/api/v1/screens/RESOURCE_ID'Rotate screen public id
curl --noproxy '*' --request POST --header 'Authorization: Bearer SCREENRIG_TOKEN' --header 'If-Match: "1"' --header 'Idempotency-Key: REQUEST_ID' 'http://api.screenrig.localhost:8088/api/v1/screens/RESOURCE_ID/public-id/rotate'Revoke screen credential
curl --noproxy '*' --request POST --header 'Authorization: Bearer SCREENRIG_TOKEN' --header 'If-Match: "1"' --header 'Idempotency-Key: REQUEST_ID' 'http://api.screenrig.localhost:8088/api/v1/screens/RESOURCE_ID/credential/revoke'Application K/V for owners
List k v
curl --noproxy '*' --request GET --header 'Authorization: Bearer SCREENRIG_TOKEN' 'http://api.screenrig.localhost:8088/api/v1/applications/APPLICATION_ID/kv'Get k v
curl --noproxy '*' --request GET --header 'Authorization: Bearer SCREENRIG_TOKEN' 'http://api.screenrig.localhost:8088/api/v1/applications/APPLICATION_ID/kv/KEY'Put k v
curl --noproxy '*' --request PUT --header 'Authorization: Bearer SCREENRIG_TOKEN' --header 'Idempotency-Key: REQUEST_ID' --header 'Content-Type: application/json' --data '@request.json' 'http://api.screenrig.localhost:8088/api/v1/applications/APPLICATION_ID/kv/KEY'{
"value_base64": "string",
"content_type": "string"
}Delete k v
curl --noproxy '*' --request DELETE --header 'Authorization: Bearer SCREENRIG_TOKEN' --header 'If-Match: "1"' --header 'Idempotency-Key: REQUEST_ID' 'http://api.screenrig.localhost:8088/api/v1/applications/APPLICATION_ID/kv/KEY'Durable account events
List events
curl --noproxy '*' --request GET --header 'Authorization: Bearer SCREENRIG_TOKEN' 'http://api.screenrig.localhost:8088/api/v1/events'Stream events
curl --noproxy '*' --request GET --header 'Authorization: Bearer SCREENRIG_TOKEN' 'http://api.screenrig.localhost:8088/api/v1/events/stream'Player pairing and sessions
Start pairing session
curl --noproxy '*' --request POST 'http://play.screenrig.localhost:8088/runtime/v1/pairing-sessions'Stream pairing events
curl --noproxy '*' --request GET --cookie 'SCREENRIG_COOKIE=SESSION' 'http://play.screenrig.localhost:8088/runtime/v1/pairing-events'Complete pairing session
curl --noproxy '*' --request POST --cookie 'SCREENRIG_COOKIE=SESSION' --header 'Content-Type: application/json' --data '@request.json' 'http://play.screenrig.localhost:8088/runtime/v1/pairing-sessions/complete'{
"completion_nonce": "string"
}Create anonymous runtime session
curl --noproxy '*' --request POST --header 'Content-Type: application/json' --data '@request.json' 'http://play.screenrig.localhost:8088/runtime/v1/sessions'{
"public_id": "string"
}Create device runtime session
curl --noproxy '*' --request POST --cookie 'SCREENRIG_COOKIE=SESSION' 'http://play.screenrig.localhost:8088/runtime/v1/device-sessions'Runtime manifest, reports, and events
Get runtime manifest
curl --noproxy '*' --request GET --cookie 'SCREENRIG_COOKIE=SESSION' 'http://play.screenrig.localhost:8088/runtime/v1/manifest'Stream runtime events
curl --noproxy '*' --request GET --cookie 'SCREENRIG_COOKIE=SESSION' 'http://play.screenrig.localhost:8088/runtime/v1/events'Create runtime report
curl --noproxy '*' --request POST --cookie 'SCREENRIG_COOKIE=SESSION' --header 'Content-Type: application/json' --data '@request.json' 'http://play.screenrig.localhost:8088/runtime/v1/reports'{
"severity": "info",
"code": "manifest.activated",
"context": null
}Launch application release
curl --noproxy '*' --request POST --cookie 'SCREENRIG_COOKIE=SESSION' 'http://play.screenrig.localhost:8088/runtime/v1/manifests/MANIFEST_REVISION/releases/RELEASE_ID/launch'Runtime application K/V
List runtime k v
Lists metadata for the application placement named by the current manifest. Requires the HttpOnly runtime session and the parent-only ScreenRig-Placement-Capability handle issued on the application placement. Handles expire after five minutes and are refreshed by fetching the current runtime manifest; uploaded frames never receive the handle and must use the validated parent SDK bridge.
curl --noproxy '*' --request GET --header 'ScreenRig-Placement-Capability: PLACEMENT_CAPABILITY' --cookie 'SCREENRIG_COOKIE=SESSION' 'http://play.screenrig.localhost:8088/runtime/v1/apps/APPLICATION_ID/kv'Get runtime k v
curl --noproxy '*' --request GET --header 'ScreenRig-Placement-Capability: PLACEMENT_CAPABILITY' --cookie 'SCREENRIG_COOKIE=SESSION' 'http://play.screenrig.localhost:8088/runtime/v1/apps/APPLICATION_ID/kv/KEY'Put runtime k v
curl --noproxy '*' --request PUT --header 'ScreenRig-Placement-Capability: PLACEMENT_CAPABILITY' --cookie 'SCREENRIG_COOKIE=SESSION' --header 'Idempotency-Key: REQUEST_ID' --header 'Content-Type: application/json' --data '@request.json' 'http://play.screenrig.localhost:8088/runtime/v1/apps/APPLICATION_ID/kv/KEY'{
"value_base64": "string",
"content_type": "string"
}Delete runtime k v
curl --noproxy '*' --request DELETE --header 'ScreenRig-Placement-Capability: PLACEMENT_CAPABILITY' --cookie 'SCREENRIG_COOKIE=SESSION' --header 'If-Match: "1"' --header 'Idempotency-Key: REQUEST_ID' 'http://play.screenrig.localhost:8088/runtime/v1/apps/APPLICATION_ID/kv/KEY'Protected content and release assets
Get protected media
curl --noproxy '*' --request GET --cookie 'SCREENRIG_COOKIE=SESSION' 'http://play.screenrig.localhost:8088/content/v1/manifests/MANIFEST_REVISION/media/MEDIA_ID'Consume launch ticket or get release asset
Exact-release-host operation. With a ticket query, atomically consumes the single-use 30-second ticket, binds Host/release/screen/content-generation/manifest/grant, sets only the exact-host release-grant cookie, and redirects to the same path without the ticket. Without a ticket, validates that cookie on every GET/HEAD. The asset_path parameter is greedy (x-screenrig-greedy-path) and is resolved only beneath the ready release root. Runtime/account/device cookies and account bearer tokens never authorize this operation.
curl --noproxy '*' --request GET --cookie 'SCREENRIG_COOKIE=SESSION' 'https://r-RELEASE_HOST.apps.screenrig.ai/index.html'Schema index
Generated names and required fields; use raw OpenAPI for complete JSON Schema.
Account— required: id, email, revision, status, used_bytes, reserved_bytes, screen_count, content_limit_bytes, screen_limitAccountCreate— required: emailAccountCreated— required: account, token, issuance_idApplication— required: id, name, revision, stateApplicationList— required: itemsCapabilities— required: api_version, protocol_version, application_compressed_bytes, application_expanded_bytes, application_file_count, application_file_bytes, application_path_depth, application_path_bytes, playlist_max_pages, playlist_max_items_per_page, transition_max_duration_ms, screens_per_account, account_content_bytes, featuresEvent— required: cursor, sequence, type, severity, message, atEventList— required: items, next_cursorHealthResponse— required: statusKVEntry— required: application_id, key, value_base64, content_type, bytes, sha256, revisionKVList— required: itemsKVSummary— required: application_id, key, content_type, bytes, sha256, revisionKVWrite— required: value_base64, content_typeManifestActivatedContext— required: manifest_revisionManifestActivatedReport— required: severity, code, contextMedia— required: id, filename, kind, content_type, operation_id, sha256, bytes, revision, state, created_at, updated_atMediaCommit— required: content_type, bytes, sha256MediaList— required: itemsMediaUploadDeclaration— required: filename, content_type, bytes, sha256MediaUploadSession— required: id, operation, upload_url, method, headers, expires_atNextAction— required: command, reasonOperation— required: id, kind, state, created_at, updated_atOperationAccepted— required: id, operation_idPairScreen— required: codePairingClaim— required: screen, public_urlPairingClaimedEvent— required: type, completion_noncePairingComplete— required: completion_noncePairingCompletion— required: screen, public_urlPairingSession— required: code, expires_atPlaylist— required: id, name, revision, pagesPlaylistList— required: itemsPlaylistWrite— required: name, pagesProblem— required: type, title, status, detail, instance, code, request_id, errorsProblemField— required: field, code, detailReadyResponse— required: status, degradedReleaseLaunch— required: launch_url, expires_atRuntimeAdvance— required: modeRuntimeApplicationContent— required: type, applicationId, releaseId, launchUrl, origin, protocol, grantIdRuntimeApplicationPlacement— required: id, content, gridStyle, layer, capabilityHandle, capabilityExpiresAtRuntimeConditionReport— required: severity, code, contextRuntimeContent— required: noneRuntimeGrid— required: styleRuntimeIframeContent— required: type, src, titleRuntimeImageContent— required: type, mediaId, src, fit, allowUpscale, grantId, sha256, bytes, contentTypeRuntimeManifest— required: schemaVersion, manifestRevision, grantId, contentGeneration, screenId, screenLabel, playlistRevision, generatedAt, pagesRuntimePage— required: id, grid, transition, advance, itemsRuntimePassivePlacement— required: id, content, gridStyle, layerRuntimePlacement— required: noneRuntimeReport— required: noneRuntimeSession— required: paired, capabilities, event_cursor, public_urlRuntimeSessionRequest— required: public_idRuntimeTransition— required: type, durationMsRuntimeVideoContent— required: type, mediaId, src, fit, muted, loop, grantId, sha256, bytes, contentTypeScreen— required: id, public_id, label, revision, manifest_revision, content_access_generation, state, created_at, updated_atScreenList— required: itemsScreenPatch— required: noneVersionResponse— required: version, commit, api_version, protocol_version