API reference

Projects API

Projects, invitations, and sign-in

HTTP reference. Generated from the backend contract. Browse endpoints below or download OpenAPI.

This group has 147 operations, generated from api/openapi.yaml. Filter by path, action, or authentication. Each endpoint lists its inputs; expand it for a request template and response codes. Templates need your own values and a schema-valid body.

Replace uppercase placeholders with your values. For a JSON request, save a body matching the schema in request.json. Cookie examples use a local cookie jar from an authenticated session.

Projects, invitations, and sign-in

GET/api/project/deletion-preview

Preview Project Deletion Agent

Returns current confirmation details, deletion blockers and archived devices that will be disconnected. allowed is false, with a reason, when the caller may not delete the project (only its owner or an administrator of its organization may; for an agent, its responsible person) or a blocker remains.

Authentication
projectBearer OR dashboardSession
Request body
none
Operation ID
previewProjectDeletionAgent

Parameters

NameSend inRequired?Description
ScreenRig-ProjectheaderoptionalDeprecated for one release. Must be consistent with the JWT projects grants; adds Deprecation and Warning headers. No token exchange.
project_idqueryoptionalExpected project ID; a changed selection is refused.
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --cookie cookies.txt --cookie-jar cookies.txt 'https://screenrig.ai/api/project/deletion-preview'

Responses

StatusMeaningBody and headers
200Project lifecycle resultProjectDeletionPreview (application/json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
PUT/api/project/owner

Transfer Project Owner Agent

The owner transfers ownership to a verified existing project member; this grants no new membership. The new owner's membership leaves any screen_scope and upload_scope, so the new owner reaches the whole project.

A dashboard session of an admin of the project's organization who is a member transfers ownership the same way, from whoever owns the project; an organization admin who is not a member uses PUT /api/organizations/{org_id}/projects/{project_id}/owner.

Authentication
projectBearer OR dashboardSession
Request body
ProjectOwnerTransfer
Operation ID
transferProjectOwnerAgent

Parameters

NameSend inRequired?Description
ScreenRig-ProjectheaderoptionalDeprecated for one release. Must be consistent with the JWT projects grants; adds Deprecation and Warning headers. No token exchange.

Request body fields

FieldDescription
project_id (optional, string)Expected project ID. The server refuses the action if the current credential or cookie session targets another project; browser clients send the page's project ID. minLength: 1 maxLength: 200
user_id (required, string)minLength: 1 maxLength: 200
Request template and responses
shell · request template
curl --request PUT --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --cookie cookies.txt --cookie-jar cookies.txt --header 'Content-Type: application/json' --data '@request.json' 'https://screenrig.ai/api/project/owner'

Responses

StatusMeaningBody and headers
200Project lifecycle resultProjectContext (application/json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
POST/api/project/move

Move Project Agent

Owner-authorized move transfers screen occupancy and new usage to the destination payer atomically; historical charges keep their payer. A destination already holding as many live projects as its plan allows is project_limit_reached, whose required_plan names the plan with room, absent at Enterprise.

Authentication
projectBearer OR dashboardSession
Request body
ProjectMove
Operation ID
moveProjectAgent

Parameters

NameSend inRequired?Description
ScreenRig-ProjectheaderoptionalDeprecated for one release. Must be consistent with the JWT projects grants; adds Deprecation and Warning headers. No token exchange.

Request body fields

FieldDescription
project_id (optional, string)Expected project ID. The server refuses the action if the current credential or cookie session targets another project; browser clients send the page's project ID. minLength: 1 maxLength: 200
organization_id (required, string)minLength: 1 maxLength: 200
Request template and responses
shell · request template
curl --request POST --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --cookie cookies.txt --cookie-jar cookies.txt --header 'Content-Type: application/json' --data '@request.json' 'https://screenrig.ai/api/project/move'

Responses

StatusMeaningBody and headers
200Project lifecycle resultProjectContext (application/json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/project/moves

Allowed Project Moves Agent

Lists destinations the owner administers or whose verified domain matches their verified email.

Authentication
projectBearer OR dashboardSession
Request body
none
Operation ID
allowedProjectMovesAgent

Parameters

NameSend inRequired?Description
ScreenRig-ProjectheaderoptionalDeprecated for one release. Must be consistent with the JWT projects grants; adds Deprecation and Warning headers. No token exchange.
project_idqueryoptionalExpected project ID; a changed selection is refused.
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --cookie cookies.txt --cookie-jar cookies.txt 'https://screenrig.ai/api/project/moves'

Responses

StatusMeaningBody and headers
200Project lifecycle resultProjectMoveDestinations (application/json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/projects

List Agent Projects

Lists every active membership of the identity, with organization and owner context, including memberships omitted from this token or its grant's consent. Each entry marks in_token; discovery adds no authority and has no 64-project cap.

Authentication
agentIdentityBearer OR dashboardSession
Request body
none
Operation ID
listAgentProjects

Parameters

NameSend inRequired?Description
ScreenRig-ProjectheaderoptionalDeprecated for one release. Must be consistent with the JWT projects grants; adds Deprecation and Warning headers. No token exchange.
Request template and responses
shell · request template
curl --request GET --cookie cookies.txt --cookie-jar cookies.txt 'https://screenrig.ai/api/projects'

Responses

StatusMeaningBody and headers
200Project lifecycle resultProjectContextList (application/json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
POST/api/projects

Create Agent Project

Creates a named project owned by the verified responsible person. With no organization named, it goes to the person's verified-domain organization, else the current project's organization, else the organization the person used most recently among those they administer or hold as their free one, else a new organization.

An organization name selects exactly one visible match, otherwise creates a new organization. A person holds one free Standard organization; a new organization beyond it is free_organization_limit, naming the one they hold.

An organization holds at most as many live projects as its plan allows (Standard 1, Plus 3, Premium 10, Education 50, Enterprise 100, widened by its featuresets); one more is project_limit_reached, whose required_plan names the plan with room, absent at Enterprise (contact support).

An exact idempotent retry redelivers its sealed membership credential for ten minutes. Enrollment is exempt from the limit.

Under an agent access JWT (identity scope, access:manage, a grant with identity access Manage) no project token is delivered; the project joins the grant with Manage and every capability, and a refresh with its project_id returns a token for it.

Authentication
agentIdentityBearer OR dashboardSession
Request body
ProjectCreate
Operation ID
createAgentProject

Parameters

NameSend inRequired?Description
ScreenRig-ProjectheaderoptionalDeprecated for one release. Must be consistent with the JWT projects grants; adds Deprecation and Warning headers. No token exchange.
Idempotency-Keyheaderrequired

Request body fields

FieldDescription
name (required, ProjectName)Trimmed printable project name. Rejects controls, URL-looking text, @, www., and ://. minLength: 1 maxLength: 60
organization_id (optional, string)minLength: 1 maxLength: 200
organization_name (optional, ProjectName)Trimmed printable project name. Rejects controls, URL-looking text, @, www., and ://. minLength: 1 maxLength: 60
Request template and responses
shell · request template
curl --request POST --cookie cookies.txt --cookie-jar cookies.txt --header 'Idempotency-Key: REQUEST_ID' --header 'Content-Type: application/json' --data '@request.json' 'https://screenrig.ai/api/projects'

Responses

StatusMeaningBody and headers
201Project lifecycle resultCreatedProject (application/json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/invitations

List Invitations

Lists invitation lifecycle records for the current project, excluding sign-in resets. Recipient addresses are visible to the owning project, which supplied them. Tokens and credential URLs are never listed.

Authentication
projectBearer OR dashboardSession
Request body
none
Operation ID
listInvitations

Parameters

NameSend inRequired?Description
ScreenRig-ProjectheaderoptionalDeprecated for one release. Must be consistent with the JWT projects grants; adds Deprecation and Warning headers. No token exchange.
kindqueryoptional
statusqueryoptional
cursorqueryoptional
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --cookie cookies.txt --cookie-jar cookies.txt 'https://screenrig.ai/api/invitations'

Responses

StatusMeaningBody and headers
200Lists invitation lifecycle records for the current project, excluding sign-in resets.InvitationList (application/json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
POST/api/invitations

Create Invitations

Creates member or ad-buyer invitations. Email delivery never returns a credential. Link delivery is member-only and returns one URL, including on exact idempotent replay within 24 hours. Email invitations expire after seven days; links expire after 24 hours. Outstanding email invitations of the same kind, address, and project are reused.

A member limited to screens does not invite people (outside_screen_scope).

A project_member email invitation to a person who would be an external guest of the project's organization (it is not their home organization) is subject to that organization's guest policy, and guest_not_allowed (403) answers when the policy (allow, domains or none) does not admit the address. Accepting the invitation checks again.

Staff and the organization's own admins are exempt. A screen_scope on the invitation is screen scope, which the Enterprise plan includes; a project whose plan lacks it is refused with feature_not_in_plan (402).

Authentication
projectBearer OR dashboardSession
Request body
InvitationCreate
Operation ID
createInvitations

Parameters

NameSend inRequired?Description
ScreenRig-ProjectheaderoptionalDeprecated for one release. Must be consistent with the JWT projects grants; adds Deprecation and Warning headers. No token exchange.
Idempotency-Keyheaderrequired

Request body fields

FieldDescription
kind (required, string)Allowed: "project_member", "ad_buyer"
delivery (optional, string)Allowed: "email", "link" default: "email"
emails (optional, array)
advertising (optional, InvitationAdvertising)Seller-owned scope: at least one screen or slot. Screens only, slots only, or both are accepted.
upload_scope (optional, UploadScope)

What an uploader may use (docs/uploaders.md): the playlists it changes pages of and the media folders it uploads into. Folders are exactly the listed ones, never their subfolders. An id that names no live object of the project when written is invalid_request at its position; a later deletion leaves a dead id, which grants nothing.

The scope is read on each request, so a change applies to the next one.

screen_scope (optional, ScreenScope)

What a scoped member or agent may act on (docs/screen-scope.md): the screens in the listed screen folders and in every folder inside them, and the listed screens. At least one id in all. An id that names no live folder or screen of the project when written is invalid_request at its position; a later deletion leaves a dead id, which grants nothing.

The scope is read on each request, so a change applies to the next one. Tags are never scope.

Request template and responses
shell · request template
curl --request POST --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --cookie cookies.txt --cookie-jar cookies.txt --header 'Idempotency-Key: REQUEST_ID' --header 'Content-Type: application/json' --data '@request.json' 'https://screenrig.ai/api/invitations'

Responses

StatusMeaningBody and headers
201Creates member or ad-buyer invitations.InvitationCreated (application/json); headers: RateLimit-Policy, RateLimit
402

feature_not_in_plan — a screen scope needs Enterprise, and an upload scope (an uploader) needs Plus; the problem names the feature, the plan the account is on and required_plan. Narrowing an upload scope and removing either scope are always allowed.

Problem (application/problem+json)
403

outside_screen_scope - the caller is limited to screens and the screen, screen folder, selector or audience the request names or reaches is outside them (docs/screen-scope.md). An id outside the scope and an id that does not exist get the same answer; errors[0].screen_scope carries the caller's scope, and the write is refused whole, never narrowed.

Problem (application/problem+json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
429

Stable rate_limited problem. Retry only after the authoritative Retry-After interval. Fixed-window denials also include the applicable RateLimit-Policy and RateLimit members; concurrency and byte-budget denials omit those optional disclosures.

Problem (application/problem+json); headers: Retry-After, RateLimit-Policy, RateLimit
POST/api/invitations/{id}/revoke

Revoke Invitation

Revokes an outstanding invitation. An accepted invitation returns invitation_consumed. A member limited to screens does not revoke invitations (outside_screen_scope).

Authentication
projectBearer OR dashboardSession
Request body
none
Operation ID
revokeInvitation

Parameters

NameSend inRequired?Description
ScreenRig-ProjectheaderoptionalDeprecated for one release. Must be consistent with the JWT projects grants; adds Deprecation and Warning headers. No token exchange.
idpathrequired
Request template and responses
shell · request template
curl --request POST --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --cookie cookies.txt --cookie-jar cookies.txt 'https://screenrig.ai/api/invitations/RESOURCE_ID/revoke'

Responses

StatusMeaningBody and headers
204Revokes an outstanding invitation.no body
403

outside_screen_scope - the caller is limited to screens and the screen, screen folder, selector or audience the request names or reaches is outside them (docs/screen-scope.md). An id outside the scope and an id that does not exist get the same answer; errors[0].screen_scope carries the caller's scope, and the write is refused whole, never narrowed.

Problem (application/problem+json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
POST/api/sign-in-resets

Request Sign In Reset

Accepts a sign-in reset request without revealing whether a person holds the address.

A person whose address is unverified, such as a self-serve signup, is found too, and completing that reset, which its owner must confirm with replace_unverified_account, gives the inbox's owner a new account (a new person with the reset's credential, a new organization and project) and deletes the unverified person, whom nobody had shown the address belonged to.

A reset link expires one hour after it was last requested. While a person's link is live and less than a day old, another request sends that same link again (at most once every ten minutes) and moves its expiry to one hour from the request, so a request never stops the link already in the inbox; otherwise a new link replaces it. There is no limit per address.

Completing a reset removes the person's other passkeys (every passkey for a password reset), removes the password when the new credential is a passkey, discards a pending email change and ends every session. With or without a person, the request also re-sends at most ten invitations addressed to the email, and any one invitation at most once an hour.

Of the ten most recent non-deleted projects whose contact address matches, each active project with a catalog plan and ownership still pending from enrollment gets its enrollment invitation back, even when it expired or its recipient already joined as an ordinary member.

Accepting that enrollment invitation with the existing sign-in completes the ownership claim; requesting recovery alone changes no ownership or credentials. Pending emailed member and ad-buyer invitations to active projects with a catalog plan, and pending organization admin invitations to live organizations, fill the rest, newest first.

A re-sent invitation keeps its ID and gets a new link and expiry; the old link stops working and the project's outstanding invitation count is unchanged. An expired enrollment returns as a new invitation that takes an invitation slot again, so the count rises by one, and it is skipped when the project is full.

Other expired invitations, and revoked, accepted and link invitations, are not re-sent.

Authentication
none
Request body
SignInResetRequest
Operation ID
requestSignInReset

Parameters

NameSend inRequired?Description
Idempotency-Keyheaderrequired

Request body fields

FieldDescription
email (required, string)minLength: 3 maxLength: 254 format: "email"
Request template and responses
shell · request template
curl --request POST --header 'Idempotency-Key: REQUEST_ID' --header 'Content-Type: application/json' --data '@request.json' 'https://screenrig.ai/api/sign-in-resets'

Responses

StatusMeaningBody and headers
202Accepts a sign-in reset request without revealing whether a person holds the address.SignInResetAccepted (application/json); headers: RateLimit-Policy, RateLimit
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
429

Stable rate_limited problem. Retry only after the authoritative Retry-After interval. Fixed-window denials also include the applicable RateLimit-Policy and RateLimit members; concurrency and byte-budget denials omit those optional disclosures.

Problem (application/problem+json); headers: Retry-After, RateLimit-Policy, RateLimit
POST/api/enrollments

Enroll CLI

Creates a new project and its first agent through explicit bundled-CLI enrollment, even when the contact address already belongs to a person or project. The contact email stays unverified and grants no authority; malformed addresses return invalid_request.

Queues an enrollment invitation in the same transaction. project_name is optional; omission uses a readable two-word name. Exact idempotent replay precedes rate limits. Persist the permanent credential before reporting success; its replay envelope expires at issuance_expires_at and later retries return credential_issuance_expired.

The idempotency record lasts 24 hours.

Authentication
none
Request body
CLIEnrollmentRequest
Operation ID
enrollCLI

Parameters

NameSend inRequired?Description
Idempotency-Keyheaderrequired

Request body fields

FieldDescription
credential_format (optional, string)

Must be oauth, which answers the agent JWT pair (CLIEnrollmentOAuth). legacy, or omitting it, answers 410 client_update_required, because the legacy permanent bearers are retired. A server that is not issuing agent JWTs answers not_ready. Allowed: "oauth", "legacy"

intent (optional, string)

Optional enrollment purpose. Omit or signage keeps screens=true, advertiser=false. advertising sets advertiser=true, screens=false, and never changes the billing-plan assignment. Allowed: "signage", "advertising"

client_id (required, string)Stable anonymous installation identity generated from 32 CSPRNG bytes and persisted before the first request. It is rate-limit material, not a project credential. pattern: "^cli_[A-Za-z0-9_-]{43}$"
email (optional, string)

Unverified project contact address. Exactly one of email or agentid_claim is required. Enrollment always creates a new project and queues its invitation; an address alone grants no authority. minLength: 3 maxLength: 254 format: "email"

agentid_claim (optional, string)

Single-use AgentID claim code from the AgentID sign-in page. Exactly one of email or agentid_claim is required. The verified AgentID owner address becomes the project contact and invitation recipient. pattern: "^agid_[A-Za-z0-9_-]{43}$"

beta_key (optional, string)Required when the server has a configured enrollment beta key. Omit when the server does not gate enrollment.
name (optional, string)default: "Agent" minLength: 1 maxLength: 80
agent_type (optional, string)default: "cli" pattern: "^[A-Za-z0-9][A-Za-z0-9._-]{0,31}$"
platform (optional, string)maxLength: 80
version (optional, string)maxLength: 40
install_source (optional, string)

Optional. Where the integration was installed from, the host and, after a slash, the marketplace (claude/screenrig, codex/screenrig, grok/screenrig), or a bare host such as npm. Software reports it, not a person, so a missing or wrongly shaped value is ignored and never fails enrollment.

It only counts where installs came from and grants nothing. pattern: "^[a-z][a-z0-9-]{0,31}(/[a-z0-9][a-z0-9._-]{0,63})?$"

project_name (optional, ProjectName)Trimmed printable project name. Rejects controls, URL-looking text, @, www., and ://. minLength: 1 maxLength: 60
setup_code (optional, string)

Optional setup code the person copied from the website with the setup prompt (two groups of four letters and digits, case and hyphen ignored). It links the new project to that website visit; an unknown or expired code is ignored and never fails enrollment. It grants nothing. pattern: "^[0-9A-Za-z]{4}-?[0-9A-Za-z]{4}$"

organization (optional, ProjectName)Trimmed printable project name. Rejects controls, URL-looking text, @, www., and ://. minLength: 1 maxLength: 60
Request template and responses
shell · request template
curl --request POST --header 'Idempotency-Key: REQUEST_ID' --header 'Content-Type: application/json' --data '@request.json' 'https://api.screenrig.ai/api/enrollments'

Responses

StatusMeaningBody and headers
201

New project and permanent bearer credential. The project carries the unverified contact address in its trimmed supplied form. Persist and verify the token before reporting enrollment success. The credential has no scheduled expiry but its encrypted exact-retry delivery envelope exists only until issuance_expires_at.

CLIEnrollmentOAuth (application/json); headers: Cache-Control, RateLimit-Policy, RateLimit
400

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
409

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
410

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
429

Stable rate_limited problem. Retry only after the authoritative Retry-After interval. Fixed-window denials also include the applicable RateLimit-Policy and RateLimit members; concurrency and byte-budget denials omit those optional disclosures.

Problem (application/problem+json); headers: Retry-After, RateLimit-Policy, RateLimit
500

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/agentid/start

Start Agent IDSign In

Starts an AgentID (OIDC) browser sign-in on the API host derived from the runtime public origin (https://play.<domain> -> https://api.<domain>). Sets a single-use binding cookie and redirects to the AgentID authorization endpoint with PKCE S256. Answers only on the API host.

While the relying party has no client id and secret the route renders a plain unavailable page with 503.

Authentication
none
Request body
none
Operation ID
startAgentIDSignIn
Request template and responses
shell · request template
curl --request GET 'https://api.screenrig.ai/agentid/start'

Responses

StatusMeaningBody and headers
302Redirect to the AgentID authorization endpoint.no body
503AgentID sign-in is unavailable.string (text/html)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/agentid/callback

Complete Agent IDSign In

Completes an AgentID browser sign-in on the API host. Requires iss equal to the configured issuer, the binding cookie, and an unexpired single-use transaction.

Exchanges the code with client_secret_basic and PKCE, verifies the ES256 id_token (iss, aud, exp with 60 s skew, nonce) against the cached JWKS, calls userinfo and enforces the owner rules, then renders a single-use claim-code page. A subject already bound to an agent renders the already-enrolled page.

This route never creates a project, identity, or invitation.

Authentication
none
Request body
none
Operation ID
completeAgentIDSignIn

Parameters

NameSend inRequired?Description
codequeryoptional
statequeryoptional
issqueryoptional
errorqueryoptional
Request template and responses
shell · request template
curl --request GET 'https://api.screenrig.ai/agentid/callback'

Responses

StatusMeaningBody and headers
200Single-use AgentID claim-code page with plugin install steps.string (text/html)
409The AgentID subject is already enrolled.string (text/html)
503AgentID sign-in is unavailable.string (text/html)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/project

Get Project

The calling project. Does not debit the 1-credit API meter, so a zero-remaining project can still read remaining and recover. After a successful project principal, authenticated /api JSON and problem responses include ScreenRig-Credits-Remaining, ScreenRig-Credits-Reset, and ScreenRig-Credits-Included as whole credits.

SSE, runtime, content, and unauthenticated responses omit them.

Authentication
projectBearer OR dashboardSession
Request body
none
Operation ID
getProject

Parameters

NameSend inRequired?Description
ScreenRig-ProjectheaderoptionalDeprecated for one release. Must be consistent with the JWT projects grants; adds Deprecation and Warning headers. No token exchange.
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --cookie cookies.txt --cookie-jar cookies.txt 'https://screenrig.ai/api/project'

Responses

StatusMeaningBody and headers
200ProjectProject (application/json); headers: ScreenRig-Credits-Remaining, ScreenRig-Credits-Reset, ScreenRig-Credits-Included, ScreenRig-Credits-Low
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
PATCH/api/project

Update Project

Renames the current project. Names contain 1–60 printable characters and no URL-looking text.

Authentication
projectBearer OR dashboardSession
Request body
ProjectPatch
Operation ID
updateProject

Parameters

NameSend inRequired?Description
ScreenRig-ProjectheaderoptionalDeprecated for one release. Must be consistent with the JWT projects grants; adds Deprecation and Warning headers. No token exchange.

Request body fields

FieldDescription
project_id (optional, string)Expected project ID. The server refuses the action if the current credential or cookie session targets another project; browser clients send the page's project ID. minLength: 1 maxLength: 200
name (required, ProjectName)Trimmed printable project name. Rejects controls, URL-looking text, @, www., and ://. minLength: 1 maxLength: 60
Request template and responses
shell · request template
curl --request PATCH --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --cookie cookies.txt --cookie-jar cookies.txt --header 'Content-Type: application/json' --data '@request.json' 'https://screenrig.ai/api/project'

Responses

StatusMeaningBody and headers
200Renames the current project.Project (application/json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
DELETE/api/project

Delete Project Agent

Only the project's owner or an administrator of its organization may delete it; any other caller is refused with forbidden. A person must also be a member of the project.

An agent needs the target membership project capability and deletes for its responsible person, who must be the owner or an organization administrator; an agent without a responsible person cannot delete, except the agent that enrolled the project while no person has accepted its enrollment.

Also requires the current name and revision, zero non-archived screens, no credit, reservations or debt in its own wallet and no live advertising. A negative balance run up under free or launch terms does not block; deletion writes it off with a project_delete_writeoff ledger entry. Queues member notices and uses the irreversible tombstone.

Authentication
projectBearer OR dashboardSession
Request body
ProjectDeleteConfirmation
Operation ID
deleteProjectAgent

Parameters

NameSend inRequired?Description
ScreenRig-ProjectheaderoptionalDeprecated for one release. Must be consistent with the JWT projects grants; adds Deprecation and Warning headers. No token exchange.

Request body fields

FieldDescription
project_id (optional, string)Expected project ID. The server refuses the action if the current credential or cookie session targets another project; browser clients send the page's project ID. minLength: 1 maxLength: 200
empty_only (optional, boolean)

Require an empty Screens project in the deletion transaction, including content, other agents or members, work and correspondence. The CLI additionally requires its saved enrollment provenance before using this cleanup guard. Omission keeps explicit member deletion.

name (required, ProjectName)Trimmed printable project name. Rejects controls, URL-looking text, @, www., and ://. minLength: 1 maxLength: 60
revision (required, integer)minimum: 1
Request template and responses
shell · request template
curl --request DELETE --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --cookie cookies.txt --cookie-jar cookies.txt --header 'Content-Type: application/json' --data '@request.json' 'https://screenrig.ai/api/project'

Responses

StatusMeaningBody and headers
200Project lifecycle resultDeletedProject (application/json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/project/capabilities

Get Project Capabilities

The calling project's plan, independent advertiser/screens flags with their revision, the derived effective capability set, the plan features it has (plan_features) and its limits (limits). Never reflects a client claim; an unknown plan fails closed as forbidden.

Authentication
projectBearer OR dashboardSession
Request body
none
Operation ID
getProjectCapabilities

Parameters

NameSend inRequired?Description
ScreenRig-ProjectheaderoptionalDeprecated for one release. Must be consistent with the JWT projects grants; adds Deprecation and Warning headers. No token exchange.
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --cookie cookies.txt --cookie-jar cookies.txt 'https://screenrig.ai/api/project/capabilities'

Responses

StatusMeaningBody and headers
200Project capabilities.ProjectCapabilities (application/json); headers: Cache-Control
403forbidden - the project plan is not in the catalog.Problem (application/problem+json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/organizations/{org_id}/audit

List Organization Audit

The organization's own audit log: changes to its administrators, domains and billing settings, with the same entries, filters and formats as GET /api/audit. Requires an administrator of the organization. Part of the audit log, which the Enterprise plan includes; an organization whose plan lacks it is refused with feature_not_in_plan (402).

Every plan records its changes.

Authentication
dashboardSession
Request body
none
Operation ID
listOrganizationAudit

Parameters

NameSend inRequired?Description
org_idpathrequired
actorqueryoptional
actor_kindqueryoptional
sourcequeryoptional
actionqueryoptional
sincequeryoptional
untilqueryoptional
cursorqueryoptional
limitqueryoptional
formatqueryoptionaljson (default) returns the report as JSON. csv, xlsx and pdf return the same rows as a file attachment (every page of a paged report, up to 50000 rows).
Request template and responses
shell · request template
curl --request GET --cookie cookies.txt --cookie-jar cookies.txt 'https://screenrig.ai/api/organizations/ORG_ID/audit'

Responses

StatusMeaningBody and headers
200One page of entries, or the filtered log as a file.AuditList (application/json), string (text/csv), string (application/vnd.openxmlformats-officedocument.spreadsheetml.sheet), string (application/pdf)
400

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
402feature_not_in_plan — The audit log is part of the Enterprise plan; the problem names the feature, the plan the account is on and required_plan.Problem (application/problem+json)
404

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/organizations/{org_id}/notifications

List Organization Notifications

The organization's notifications, of every channel, oldest first (at most 50).

A notification belongs to the organization and covers every project of it, including projects added later (project_ids absent), or the chosen projects (project_ids); it acts on the screens, sources, campaigns and cards of those projects exactly as a project notification does. status is failing while any covered project's deliveries are, and failing_since, last_success_at and last_failure_at fold the covered projects' (the earliest failure start, the latest success and failure).

A webhook's signing secret is never returned here. Requires an administrator of the organization; anyone else is not_found.

Authentication
dashboardSession
Request body
none
Operation ID
listOrganizationNotifications

Parameters

NameSend inRequired?Description
org_idpathrequired
Request template and responses
shell · request template
curl --request GET --cookie cookies.txt --cookie-jar cookies.txt 'https://screenrig.ai/api/organizations/ORG_ID/notifications'

Responses

StatusMeaningBody and headers
200The organization's notifications.OrganizationNotificationList (application/json)
404

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
POST/api/organizations/{org_id}/notifications

Create Organization Notification

Creates a notification of the organization, with the members of POST /api/notifications and the projects it covers: project_ids absent or null covers every project of the organization (those it has and those it gets), a list covers exactly those, each a live project of this organization (invalid_request otherwise).

An email notification's recipients are owner (each covered project's owner), or user_ids of people of the organization (its admins and home members) or members of a covered project; each project still mails only the people who are members of it.

An organization has at most 50 notifications, not counting the defaults the system makes (notification_limit_reached). The same plan features gate the channels, rules and conditions as on the project routes, judged on the organization's plan. Each covered project gets notification.created, and the change is recorded in the organization's audit log.

A webhook's signing secret is returned only in this answer and in rotate-secret; one secret signs every covered project's deliveries. An exact retry with the same Idempotency-Key returns this same answer, secret included, for twenty-four hours.

Authentication
dashboardSession
Request body
OrganizationNotificationWrite
Operation ID
createOrganizationNotification

Parameters

NameSend inRequired?Description
org_idpathrequired
Idempotency-KeyheaderoptionalOmit for a fresh operation. Supply and reuse a key to deduplicate retries; the CLI manages keys automatically.

Request body fields

FieldDescription
channel (required, string)Allowed: "email", "webhook", "slack", "teams", "pagerduty", "telegram"
description (optional, string)A name for people. maxLength: 200
conditions (optional, NotificationConditions)
screen_tags (optional, ScreenTags)

Fleet selector tags, 0 to 16 unique exact tags, each matching the media tag grammar. On ScreenPatch the array replaces the whole set and an empty array clears it; a duplicate or malformed tag is invalid_request. Changing tags bumps the screen revision (If-Match guards it) and appends screen.updated with details.tags; it never changes the manifest revision.

Tags are never on the runtime manifest and never authorization.

audience (optional, CampaignAudience)

Which screens a campaign targets: exactly one of all (every rule matches), any (at least one matches), tag (the screen carries the tag), screen_id (that screen) or folder (the screens in that screen folder and every folder inside it, GET /api/screen-folders; the folder must exist).

Rules nest at most 3 deep and an audience has at most 500 rules. {"all": []} is every screen of the project; elsewhere all and any list at least one rule.

min_severity (optional, NotificationSeverity)

The severity of a notice, least severe first. An opened notice has its condition's severity: error for screen_offline and warning for every other condition, unless the notification's severity says otherwise. A resolved notice and a test are info. Allowed: "info", "warning", "error"

severity (optional, NotificationSeverityOverrides)

Condition to severity for this notification, such as {"not_playing": "error"}. It counts for min_severity and is the severity Teams and PagerDuty show for the condition. A condition not listed keeps its default. On a patch an empty object, like null, clears every override.

active_hours (optional, NotificationActiveHours)

When opened notices go out: the windows (screenrig.schedule/v1), read in timezone. A notice that falls due while they are closed waits for the next opening (outside hold, the default) and goes out then if its condition still holds, so a condition that clears first sends nothing, or is skipped (outside drop; last_error outside_hours).

A resolved notice for an opened notice that was sent always goes out, inside the hours or not, and a test ignores them. crashing is held or dropped like any other condition. The hours judge a notice when it first goes out; a failed one is retried on the usual schedule whatever the hours.

Adding, changing or removing the hours judges the notices held for the old ones again at once.

reach_drop (optional, NotificationReachDrop)

The smallest drop in a campaign's reach a reach_dropped notice is sent for: screens is the fewest screens lost (default 1) and percent, when set, the smallest share of the screens the campaign reached when it was published; a drop must meet both.

A smaller drop queues no notice, and a queued notice whose drop shrank below it by the time it is due is skipped (condition_cleared). Only with the reach_dropped condition; on a notification without it, invalid_request.

hold_minutes (optional, integer)How long a condition must last before it notifies. crashing is never held. default: 10 minimum: 0 maximum: 1440
recipients (optional, NotificationRecipients)

Email only. owner (whoever owns the project when a notice sends) or the user_id of a person who is a member of the project; a user_id that is not a member is invalid_request. Each is emailed at their verified address. One who has since left the project or has no verified address is skipped.

url (optional, string)Webhook only: https URL on a public Internet host, port 443 (the default) or 8443. No userinfo or fragment. maxLength: 2048 format: "uri"
event_types (optional, NotificationEventTypes)

Webhook only. Project events also POSTed as they happen, exactly as a webhook sends them: exact types such as screen.online, or prefixes ending in .* such as screen.*. notification.test is never fanned out.

destination (optional, NotificationDestination)

Slack, Teams, PagerDuty and Telegram only; required for them. The credential in the shape the service issues it: slack, the incoming webhook URL (hooks.slack.com); teams, the Workflows webhook URL (logic.azure.com or powerplatform.com; Office 365 connector URLs are retired); pagerduty, the 32-character Events API v2 routing key; telegram, the bot token.

Another shape is notification_destination_rejected. It is sealed, never returned, and appears on reads only as destination_hint. minLength: 1 maxLength: 2048

telegram_chat_id (optional, NotificationTelegramChat)Telegram only; required for it. The chat to post to: its numeric id (negative for a group or channel) or @channelname. Not a credential. pattern: "^(-?[0-9]{1,20}|@[A-Za-z][A-Za-z0-9_]{4,31})$"
enabled (optional, boolean)default: true
project_ids (optional, inline)The projects the notification covers; null or absent covers every project of the organization.
Request template and responses
shell · request template
curl --request POST --cookie cookies.txt --cookie-jar cookies.txt --header 'Content-Type: application/json' --data '@request.json' 'https://screenrig.ai/api/organizations/ORG_ID/notifications'

Responses

StatusMeaningBody and headers
201Created. A webhook's secret is shown only here and on rotate-secret.Notification (application/json); headers: Cache-Control
400invalid_request, webhook_url_rejected or notification_destination_rejected.Problem (application/problem+json)
402feature_not_in_plan — as on POST /api/notifications, for the organization's plan.Problem (application/problem+json)
404

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
409notification_limit_reached or idempotency_mismatch.Problem (application/problem+json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/organizations/{org_id}/notifications/{id}

Get Organization Notification

One notification of the organization, as GET /api/organizations/{org_id}/notifications shows it.

Authentication
dashboardSession
Request body
none
Operation ID
getOrganizationNotification

Parameters

NameSend inRequired?Description
org_idpathrequired
idpathrequired
Request template and responses
shell · request template
curl --request GET --cookie cookies.txt --cookie-jar cookies.txt 'https://screenrig.ai/api/organizations/ORG_ID/notifications/RESOURCE_ID'

Responses

StatusMeaningBody and headers
200One notification.Notification (application/json); headers: ETag
404

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
PATCH/api/organizations/{org_id}/notifications/{id}

Update Organization Notification

Changes any member PATCH /api/notifications/{id} changes, in the notification and in every covered project, and project_ids: absent leaves the projects, null covers every project, a list covers exactly those. A project that gains the notification starts at its current event (nothing earlier is sent); one that loses it has the notification deleted.

Each covered project gets notification.updated, and the change is recorded in the organization's audit log.

A change that makes the notification cover a project it does not cover now is gated like a create of the notification as it will be (its channel, rules and glass conditions, on the organization's plan); covering fewer projects is never gated, and switching a list to every project always covers more. If-Match guards the revision.

Authentication
dashboardSession
Request body
OrganizationNotificationPatch
Operation ID
updateOrganizationNotification

Parameters

NameSend inRequired?Description
org_idpathrequired
idpathrequired
If-MatchheaderoptionalOptional positive resource revision. Omit to write the current resource; a supplied stale revision is revision_conflict.
Idempotency-KeyheaderoptionalOmit for a fresh operation. Supply and reuse a key to deduplicate retries; the CLI manages keys automatically.

Request body fields

FieldDescription
description (optional, string)An empty string clears the description. maxLength: 200
conditions (optional, NotificationConditions)
screen_tags (optional, ScreenTags)

Fleet selector tags, 0 to 16 unique exact tags, each matching the media tag grammar. On ScreenPatch the array replaces the whole set and an empty array clears it; a duplicate or malformed tag is invalid_request. Changing tags bumps the screen revision (If-Match guards it) and appends screen.updated with details.tags; it never changes the manifest revision.

Tags are never on the runtime manifest and never authorization.

audience (optional, inline)As on NotificationPatch.
min_severity (optional, inline)As on NotificationPatch.
severity (optional, inline)Replaces every override; null or an empty object clears them.
active_hours (optional, inline)Replaces the hours; null clears them.
reach_drop (optional, inline)Replaces the threshold; null clears it.
hold_minutes (optional, integer)minimum: 0 maximum: 1440
recipients (optional, NotificationRecipients)

Email only. owner (whoever owns the project when a notice sends) or the user_id of a person who is a member of the project; a user_id that is not a member is invalid_request. Each is emailed at their verified address. One who has since left the project or has no verified address is skipped.

url (optional, string)maxLength: 2048 format: "uri"
event_types (optional, NotificationEventTypes)

Webhook only. Project events also POSTed as they happen, exactly as a webhook sends them: exact types such as screen.online, or prefixes ending in .* such as screen.*. notification.test is never fanned out.

destination (optional, NotificationDestination)

Slack, Teams, PagerDuty and Telegram only; required for them. The credential in the shape the service issues it: slack, the incoming webhook URL (hooks.slack.com); teams, the Workflows webhook URL (logic.azure.com or powerplatform.com; Office 365 connector URLs are retired); pagerduty, the 32-character Events API v2 routing key; telegram, the bot token.

Another shape is notification_destination_rejected. It is sealed, never returned, and appears on reads only as destination_hint. minLength: 1 maxLength: 2048

telegram_chat_id (optional, NotificationTelegramChat)Telegram only; required for it. The chat to post to: its numeric id (negative for a group or channel) or @channelname. Not a credential. pattern: "^(-?[0-9]{1,20}|@[A-Za-z][A-Za-z0-9_]{4,31})$"
enabled (optional, boolean)
snoozed_until (optional, inline)Send nothing until this instant, at most 30 days ahead; null ends the snooze.
project_ids (optional, inline)Absent leaves the projects the notification covers, null covers every project of the organization, a list covers exactly those projects.
Request template and responses
shell · request template
curl --request PATCH --cookie cookies.txt --cookie-jar cookies.txt --header 'Content-Type: application/json' --data '@request.json' 'https://screenrig.ai/api/organizations/ORG_ID/notifications/RESOURCE_ID'

Responses

StatusMeaningBody and headers
200Updated notification.Notification (application/json); headers: ETag
400invalid_request, webhook_url_rejected or notification_destination_rejected.Problem (application/problem+json)
402feature_not_in_plan — as on PATCH /api/notifications/{id}, for the organization's plan.Problem (application/problem+json)
404

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
412revision_conflict — If-Match is stale; the error's current_revision carries the current revision.Problem (application/problem+json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
DELETE/api/organizations/{org_id}/notifications/{id}

Delete Organization Notification

Deletes the notification from every project it covers, with notification.deleted in each, and records it in the organization's audit log. Pending notices are failed with webhook_deleted.

Authentication
dashboardSession
Request body
none
Operation ID
deleteOrganizationNotification

Parameters

NameSend inRequired?Description
org_idpathrequired
idpathrequired
If-MatchheaderoptionalOptional positive resource revision. Omit to write the current resource; a supplied stale revision is revision_conflict.
Idempotency-KeyheaderoptionalOmit for a fresh operation. Supply and reuse a key to deduplicate retries; the CLI manages keys automatically.
Request template and responses
shell · request template
curl --request DELETE --cookie cookies.txt --cookie-jar cookies.txt 'https://screenrig.ai/api/organizations/ORG_ID/notifications/RESOURCE_ID'

Responses

StatusMeaningBody and headers
204Deleted.no body; headers: Cache-Control
404

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
412revision_conflict — If-Match is stale; the error's current_revision carries the current revision.Problem (application/problem+json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
POST/api/organizations/{org_id}/notifications/{id}/rotate-secret

Rotate Organization Notification Secret

Webhook notifications only (any other channel is invalid_request). Replaces the signing secret in every covered project at once, so one receiver keeps verifying one secret, and returns the notification with the new one in secret.

As on POST /api/notifications/{id}/rotate-secret, at most one attempt per project already in flight may still arrive signed with the old secret. An exact retry with the same Idempotency-Key returns the same new secret for twenty-four hours.

Authentication
dashboardSession
Request body
none
Operation ID
rotateOrganizationNotificationSecret

Parameters

NameSend inRequired?Description
org_idpathrequired
idpathrequired
If-MatchheaderoptionalOptional positive resource revision. Omit to write the current resource; a supplied stale revision is revision_conflict.
Idempotency-KeyheaderoptionalOmit for a fresh operation. Supply and reuse a key to deduplicate retries; the CLI manages keys automatically.
Request template and responses
shell · request template
curl --request POST --cookie cookies.txt --cookie-jar cookies.txt 'https://screenrig.ai/api/organizations/ORG_ID/notifications/RESOURCE_ID/rotate-secret'

Responses

StatusMeaningBody and headers
200The notification and its new secret.Notification (application/json); headers: Cache-Control
400invalid_request — the notification is not a webhook.Problem (application/problem+json)
404

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
412revision_conflict — If-Match is stale; the error's current_revision carries the current revision.Problem (application/problem+json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
POST/api/organizations/{org_id}/notifications/{id}/test

Test Organization Notification

Sends one notification.test through the first project the notification covers (by project id), as POST /api/notifications/{id}/test sends one through its project: one delivery, whose outcome the deliveries list shows, attempted once.

Every covered project has the same receiver, destination and secret, so one test proves the channel; the email of a test goes to the recipients of that project. A notification that covers no project is invalid_request.

Authentication
dashboardSession
Request body
none
Operation ID
testOrganizationNotification

Parameters

NameSend inRequired?Description
org_idpathrequired
idpathrequired
Idempotency-KeyheaderoptionalOmit for a fresh operation. Supply and reuse a key to deduplicate retries; the CLI manages keys automatically.
Request template and responses
shell · request template
curl --request POST --cookie cookies.txt --cookie-jar cookies.txt 'https://screenrig.ai/api/organizations/ORG_ID/notifications/RESOURCE_ID/test'

Responses

StatusMeaningBody and headers
202The queued test delivery.NotificationDelivery (application/json); headers: RateLimit-Policy, RateLimit
404

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
429

Stable rate_limited problem. Retry only after the authoritative Retry-After interval. Fixed-window denials also include the applicable RateLimit-Policy and RateLimit members; concurrency and byte-budget denials omit those optional disclosures.

Problem (application/problem+json); headers: Retry-After, RateLimit-Policy, RateLimit
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/organizations/{org_id}/notifications/{id}/deliveries

List Organization Notification Deliveries

The delivery logs of every project the notification covers, as one list, newest first by when each row was queued. Each row names its project (project_id), and its id opens GET .../deliveries/{delivery_id}/attempts. Pass next_cursor back as before for the next page.

Authentication
dashboardSession
Request body
none
Operation ID
listOrganizationNotificationDeliveries

Parameters

NameSend inRequired?Description
org_idpathrequired
idpathrequired
beforequeryoptionalnext_cursor of the previous deliveries page.
limitqueryoptional
Request template and responses
shell · request template
curl --request GET --cookie cookies.txt --cookie-jar cookies.txt 'https://screenrig.ai/api/organizations/ORG_ID/notifications/RESOURCE_ID/deliveries'

Responses

StatusMeaningBody and headers
200One page of deliveries.NotificationDeliveryList (application/json)
404

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/organizations/{org_id}/notifications/{id}/deliveries/{delivery_id}/attempts

List Organization Notification Delivery Attempts

One delivery's attempts, newest first, the most recent 20. A delivery that is not one of this notification's is not_found.

Authentication
dashboardSession
Request body
none
Operation ID
listOrganizationNotificationDeliveryAttempts

Parameters

NameSend inRequired?Description
org_idpathrequired
idpathrequired
delivery_idpathrequiredThe id of one of the webhook's deliveries.
Request template and responses
shell · request template
curl --request GET --cookie cookies.txt --cookie-jar cookies.txt 'https://screenrig.ai/api/organizations/ORG_ID/notifications/RESOURCE_ID/deliveries/DELIVERY_ID/attempts'

Responses

StatusMeaningBody and headers
200The delivery's kept attempts.NotificationDeliveryAttemptList (application/json)
404

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
DELETE/api/organizations/{org_id}/notifications/{id}/unsubscribed/{user_id}

Resubscribe Organization Notification User

Mails an email notification's person again after they stopped it with the unsubscribe link in its mail, in every project the notification covers (the link stops them in all of them). Idempotent: a person who is not stopped changes nothing, and the answer is the notification as it is.

A change bumps the revision and appends notification.updated with details change resubscribed, user_id and via api to each covered project.

Authentication
dashboardSession
Request body
none
Operation ID
resubscribeOrganizationNotificationUser

Parameters

NameSend inRequired?Description
org_idpathrequired
idpathrequired
user_idpathrequiredThe user_id of a person in the notification's unsubscribed list.
Request template and responses
shell · request template
curl --request DELETE --cookie cookies.txt --cookie-jar cookies.txt 'https://screenrig.ai/api/organizations/ORG_ID/notifications/RESOURCE_ID/unsubscribed/USER_ID'

Responses

StatusMeaningBody and headers
200The notification, without the person in unsubscribed.Notification (application/json); headers: ETag
404

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/projects/{project_id}/reports

List Report Kinds In Project

Lists the report kinds GET /api/reports/{kind} builds, with the filters each takes, and the formats a report is written in. Needs the reports capability.

Authentication
projectBearer
Request body
none
Operation ID
listReportKindsInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' 'https://api.screenrig.ai/api/projects/PROJECT_ID/reports'

Responses

StatusMeaningBody and headers
200The report kinds.ReportCatalog (application/json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/projects/{project_id}/report-subscriptions

List Report Subscriptions In Project

Lists the project's scheduled reports, oldest first (at most 50), each with its next run and the outcome of its last. Requires the project capability.

Authentication
projectBearer
Request body
none
Operation ID
listReportSubscriptionsInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' 'https://api.screenrig.ai/api/projects/PROJECT_ID/report-subscriptions'

Responses

StatusMeaningBody and headers
200The project's report subscriptions.ReportSubscriptionList (application/json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
POST/api/projects/{project_id}/report-subscriptions

Create Report Subscription In Project

Schedules a report to be emailed, as a PDF, XLSX or CSV attachment, daily, weekly or monthly at an hour in a time zone.

Each run covers the period before it in UTC days: yesterday, the seven days before, or last month. recipients are members of the project, named by user_id or by the email address of the member; anyone else is refused, so a subscription is never a way to mail an outsider, and a member who leaves stops receiving it.

A failed run is retried and shows as last_status failed with last_error. At most 50 per organization across its projects (report_subscription_limit_reached).

Authentication
projectBearer
Request body
ReportSubscriptionWrite
Operation ID
createReportSubscriptionInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
Idempotency-KeyheaderoptionalOmit for a fresh operation. Supply and reuse a key to deduplicate retries; the CLI manages keys automatically.

Request body fields

FieldDescription
name (required, string)minLength: 1 maxLength: 100
kind (required, string)Allowed: "fleet_health", "uptime", "publishing", "alerts", "alert_log", "proof_of_play"
filters (optional, object)The report's filters other than the days (GET /api/reports lists them).
schedule (required, ReportSchedule)
format (required, string)Allowed: "pdf", "xlsx", "csv"
recipients (required, array)user_id or email address of project members.
enabled (optional, boolean)default: true
Request template and responses
shell · request template
curl --request POST --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --header 'Content-Type: application/json' --data '@request.json' 'https://api.screenrig.ai/api/projects/PROJECT_ID/report-subscriptions'

Responses

StatusMeaningBody and headers
201Created.ReportSubscription (application/json); headers: ETag
400

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
402feature_not_in_plan — Reports are part of Plus. The problem names the feature, the project's plan and required_plan.Problem (application/problem+json)
409report_subscription_limit_reached.Problem (application/problem+json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/projects/{project_id}/cards

List Cards In Project

Authentication
projectBearer
Request body
none
Operation ID
listCardsInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
projectqueryoptional
afterqueryoptional
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' 'https://api.screenrig.ai/api/projects/PROJECT_ID/cards'

Responses

StatusMeaningBody and headers
200Card resourceobject (application/json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
POST/api/projects/{project_id}/cards

Create Project Card

Authentication
projectBearer
Request body
CardCreate
Operation ID
createProjectCard

Parameters

NameSend inRequired?Description
project_idpathrequired

Request body fields

FieldDescription
type (required, string)
major (optional, integer)minimum: 1
params (required, object)
data (optional, object)
Request template and responses
shell · request template
curl --request POST --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --header 'Content-Type: application/json' --data '@request.json' 'https://api.screenrig.ai/api/projects/PROJECT_ID/cards'

Responses

StatusMeaningBody and headers
201Card resourceCardInstance (application/json)
429

Stable rate_limited problem. Retry only after the authoritative Retry-After interval. Fixed-window denials also include the applicable RateLimit-Policy and RateLimit members; concurrency and byte-budget denials omit those optional disclosures.

Problem (application/problem+json); headers: Retry-After, RateLimit-Policy, RateLimit
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
POST/api/organizations/{org_id}/billing/portal-sessions

Create Organization Portal

Requires a designated admin of a live organization, exact same-origin cookie authentication and JWT CSRF. Actor and return URL are server-owned. Response is private and no-store. Open to an organization delegated to a reseller too, for its card and past invoices.

Authentication
dashboardSession
Request body
EmptyPaymentRequest
Operation ID
createOrganizationPortal

Parameters

NameSend inRequired?Description
org_idpathrequired
Request template and responses
shell · request template
curl --request POST --cookie cookies.txt --cookie-jar cookies.txt --header 'Content-Type: application/json' --data '@request.json' 'https://screenrig.ai/api/organizations/ORG_ID/billing/portal-sessions'

Responses

StatusMeaningBody and headers
201Billing management result.BillingPortalSession (application/json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
PUT/api/organizations/{org_id}/billing/auto-top-up

Set Organization Auto Top Up

Requires a designated admin of a live organization, exact same-origin cookie authentication and JWT CSRF. The actor is server-owned. Disabling preserves saved amounts and monthly spend; amount fields are ignored when disabled. Response is private and no-store. Changing settings clears a recoverable pause only after any failed payable invoice is safely voided.

Enabling it for an organization delegated to a reseller answers 409 billed_by_reseller; disabling stays open.

Authentication
dashboardSession
Request body
AutoTopUpSettings
Operation ID
setOrganizationAutoTopUp

Parameters

NameSend inRequired?Description
org_idpathrequired
Request template and responses
shell · request template
curl --request PUT --cookie cookies.txt --cookie-jar cookies.txt --header 'Content-Type: application/json' --data '@request.json' 'https://screenrig.ai/api/organizations/ORG_ID/billing/auto-top-up'

Responses

StatusMeaningBody and headers
200Billing management result.AutoTopUpView (application/json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/organizations/{org_id}/billing/payments

Get Organization Payments

Payment projections for a live organization. Requires its designated admin cookie; staff visibility alone grants no purchase access. Unconfigured payments return available false. Never grants credit from a browser return.

Authentication
dashboardSession
Request body
none
Operation ID
getOrganizationPayments

Parameters

NameSend inRequired?Description
org_idpathrequired
Request template and responses
shell · request template
curl --request GET --cookie cookies.txt --cookie-jar cookies.txt 'https://screenrig.ai/api/organizations/ORG_ID/billing/payments'

Responses

StatusMeaningBody and headers
200Payment availability and recent purchases.OrganizationPayments (application/json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
POST/api/organizations/{org_id}/billing/credit-checkouts

Create Organization Checkout

Start a prepaid purchase for a live organization designated admin. Requires same-origin cookie authentication and, for JWT sessions, a matching CSRF header. Organization, customer, actor and return URLs are server-owned. Credit applies only after the billing service confirms payment. Retry ambiguous responses with the same Idempotency-Key and amount.

An organization delegated to a reseller answers 409 billed_by_reseller.

Authentication
dashboardSession
Request body
object
Operation ID
createOrganizationCheckout

Parameters

NameSend inRequired?Description
org_idpathrequired
Idempotency-Keyheaderrequired

Request body fields

FieldDescription
amount_cents (required, integer)minimum: 10000 maximum: 1000000 format: "int64"
Request template and responses
shell · request template
curl --request POST --cookie cookies.txt --cookie-jar cookies.txt --header 'Idempotency-Key: REQUEST_ID' --header 'Content-Type: application/json' --data '@request.json' 'https://screenrig.ai/api/organizations/ORG_ID/billing/credit-checkouts'

Responses

StatusMeaningBody and headers
201Purchase created or replayed. Checkout URL is absent after completion. Responses are private and no-store.CreditPurchase (application/json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/organizations/{org_id}/billing/balance

Get Organization Billing Balance

The organization wallet. Requires a designated organization admin, an admin of the reseller the organization is delegated to, or a staff session. Grants no project membership.

Authentication
dashboardSession
Request body
none
Operation ID
getOrganizationBillingBalance

Parameters

NameSend inRequired?Description
org_idpathrequired
Request template and responses
shell · request template
curl --request GET --cookie cookies.txt --cookie-jar cookies.txt 'https://screenrig.ai/api/organizations/ORG_ID/billing/balance'

Responses

StatusMeaningBody and headers
200Organization billing balance.BillingBalance (application/json); headers: Cache-Control
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/organizations/{org_id}/billing/statement

Get Organization Billing Statement

Journal entries attributed to this organization at charge time, with project and payer identities. Moves do not transfer historical access. Entries predating recorded organization context remain in their project statements. Read by the same people as the balance (getOrganizationBillingBalance).

Authentication
dashboardSession
Request body
none
Operation ID
getOrganizationBillingStatement

Parameters

NameSend inRequired?Description
org_idpathrequired
cursorqueryoptional
limitqueryoptional
Request template and responses
shell · request template
curl --request GET --cookie cookies.txt --cookie-jar cookies.txt 'https://screenrig.ai/api/organizations/ORG_ID/billing/statement'

Responses

StatusMeaningBody and headers
200Organization billing statement.BillingStatement (application/json); headers: Cache-Control
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/organizations/{org_id}/billing/usage

Get Organization Billing Usage

The organization's usage pool and each project's share for a UTC month. Covers usage paid by this organization; other payer costs are in the organization statement. Read by the same people as the balance (getOrganizationBillingBalance).

Authentication
dashboardSession
Request body
none
Operation ID
getOrganizationBillingUsage

Parameters

NameSend inRequired?Description
org_idpathrequired
cursorqueryoptional
limitqueryoptional
periodqueryoptionalUTC month in YYYY-MM form; defaults to the current month.
Request template and responses
shell · request template
curl --request GET --cookie cookies.txt --cookie-jar cookies.txt 'https://screenrig.ai/api/organizations/ORG_ID/billing/usage'

Responses

StatusMeaningBody and headers
200Organization billing usage.OrganizationBillingUsage (application/json); headers: Cache-Control
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/organizations

Agent Organizations List

Visible organizations, including empty organizations for their admins. Names are not unique.

Authentication
agentIdentityBearer OR dashboardSession
Request body
none
Operation ID
agentOrganizationsList
Request template and responses
shell · request template
curl --request GET --cookie cookies.txt --cookie-jar cookies.txt 'https://api.screenrig.ai/api/organizations'

Responses

StatusMeaningBody and headers
200Organization result.OrganizationList (application/json); headers: Cache-Control
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
PATCH/api/organizations/{org_id}

Agent Organizations Rename

Designated admins and agents whose verified responsible person is an admin may rename an organization. No project permission or membership is granted.

Authentication
agentIdentityBearer OR dashboardSession
Request body
OrganizationRename
Operation ID
agentOrganizationsRename

Parameters

NameSend inRequired?Description
org_idpathrequired

Request body fields

FieldDescription
name (required, ProjectName)Trimmed printable project name. Rejects controls, URL-looking text, @, www., and ://. minLength: 1 maxLength: 60
Request template and responses
shell · request template
curl --request PATCH --cookie cookies.txt --cookie-jar cookies.txt --header 'Content-Type: application/json' --data '@request.json' 'https://api.screenrig.ai/api/organizations/ORG_ID'

Responses

StatusMeaningBody and headers
200Organization result.OrganizationView (application/json); headers: Cache-Control
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
PUT/api/project/review-policy

Set Project Review Policy

Turns Require review for agent changes on or off. While on, every agent and service client on the project is held to Propose access on every request, whatever its credential carries. The project owner or an admin of the project's organization only (forbidden otherwise); staff shadow sessions cannot change it.

If-Match carries review_policy_revision (0 allowed) and is required; a stale value is revision_conflict. Turning it off requires proof, the fresh passkey or password proof agent connection approval uses; turning it on does not. Open reviews stay decidable either way. Appends project.review_policy_changed.

Authentication
dashboardSession
Request body
ReviewPolicyUpdate
Operation ID
setProjectReviewPolicy

Parameters

NameSend inRequired?Description
If-Matchheaderrequired

Request body fields

FieldDescription
agent_changes_require_review (required, boolean)
proof (optional, DashboardProof)
Request template and responses
shell · request template
curl --request PUT --cookie cookies.txt --cookie-jar cookies.txt --header 'If-Match: "REVISION"' --header 'Content-Type: application/json' --data '@request.json' 'https://screenrig.ai/api/project/review-policy'

Responses

StatusMeaningBody and headers
200The policy now in force.ReviewPolicy (application/json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/projects/{project_id}/project/deletion-preview

Preview Project Deletion Agent In Project

Returns current confirmation details, deletion blockers and archived devices that will be disconnected. allowed is false, with a reason, when the caller may not delete the project (only its owner or an administrator of its organization may; for an agent, its responsible person) or a blocker remains.

Authentication
projectBearer
Request body
none
Operation ID
previewProjectDeletionAgentInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
project_idqueryoptionalExpected project ID; a changed selection is refused.
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' 'https://api.screenrig.ai/api/projects/PROJECT_ID/project/deletion-preview'

Responses

StatusMeaningBody and headers
200Project lifecycle resultProjectDeletionPreview (application/json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
PUT/api/projects/{project_id}/project/owner

Transfer Project Owner Agent In Project

The owner transfers ownership to a verified existing project member; this grants no new membership. The new owner's membership leaves any screen_scope and upload_scope, so the new owner reaches the whole project.

Authentication
projectBearer
Request body
ProjectOwnerTransfer
Operation ID
transferProjectOwnerAgentInProject

Parameters

NameSend inRequired?Description
project_idpathrequired

Request body fields

FieldDescription
project_id (optional, string)Expected project ID. The server refuses the action if the current credential or cookie session targets another project; browser clients send the page's project ID. minLength: 1 maxLength: 200
user_id (required, string)minLength: 1 maxLength: 200
Request template and responses
shell · request template
curl --request PUT --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --header 'Content-Type: application/json' --data '@request.json' 'https://api.screenrig.ai/api/projects/PROJECT_ID/project/owner'

Responses

StatusMeaningBody and headers
200Project lifecycle resultProjectContext (application/json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
POST/api/projects/{project_id}/project/move

Move Project Agent In Project

Owner-authorized move transfers screen occupancy and new usage to the destination payer atomically; historical charges keep their payer.

Authentication
projectBearer
Request body
ProjectMove
Operation ID
moveProjectAgentInProject

Parameters

NameSend inRequired?Description
project_idpathrequired

Request body fields

FieldDescription
project_id (optional, string)Expected project ID. The server refuses the action if the current credential or cookie session targets another project; browser clients send the page's project ID. minLength: 1 maxLength: 200
organization_id (required, string)minLength: 1 maxLength: 200
Request template and responses
shell · request template
curl --request POST --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --header 'Content-Type: application/json' --data '@request.json' 'https://api.screenrig.ai/api/projects/PROJECT_ID/project/move'

Responses

StatusMeaningBody and headers
200Project lifecycle resultProjectContext (application/json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/projects/{project_id}/project/moves

Allowed Project Moves Agent In Project

Lists destinations the owner administers or whose verified domain matches their verified email.

Authentication
projectBearer
Request body
none
Operation ID
allowedProjectMovesAgentInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
project_idqueryoptionalExpected project ID; a changed selection is refused.
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' 'https://api.screenrig.ai/api/projects/PROJECT_ID/project/moves'

Responses

StatusMeaningBody and headers
200Project lifecycle resultProjectMoveDestinations (application/json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/projects/{project_id}/invitations

List Invitations In Project

Lists invitation lifecycle records for the current project, excluding sign-in resets. Recipient addresses are visible to the owning project, which supplied them. Tokens and credential URLs are never listed.

Authentication
projectBearer
Request body
none
Operation ID
listInvitationsInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
kindqueryoptional
statusqueryoptional
cursorqueryoptional
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' 'https://api.screenrig.ai/api/projects/PROJECT_ID/invitations'

Responses

StatusMeaningBody and headers
200Lists invitation lifecycle records for the current project, excluding sign-in resets.InvitationList (application/json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
POST/api/projects/{project_id}/invitations

Create Invitations In Project

Creates member or ad-buyer invitations. Email delivery never returns a credential. Link delivery is member-only and returns one URL, including on exact idempotent replay within 24 hours. Email invitations expire after seven days; links expire after 24 hours. Outstanding email invitations of the same kind, address, and project are reused.

A member limited to screens does not invite people (outside_screen_scope).

A project_member email invitation to a person who would be an external guest of the project's organization (it is not their home organization) is subject to that organization's guest policy, and guest_not_allowed (403) answers when the policy (allow, domains or none) does not admit the address. Accepting the invitation checks again.

Staff and the organization's own admins are exempt. A screen_scope on the invitation is screen scope, which the Enterprise plan includes; a project whose plan lacks it is refused with feature_not_in_plan (402).

Authentication
projectBearer
Request body
InvitationCreate
Operation ID
createInvitationsInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
Idempotency-Keyheaderrequired

Request body fields

FieldDescription
kind (required, string)Allowed: "project_member", "ad_buyer"
delivery (optional, string)Allowed: "email", "link" default: "email"
emails (optional, array)
advertising (optional, InvitationAdvertising)Seller-owned scope: at least one screen or slot. Screens only, slots only, or both are accepted.
upload_scope (optional, UploadScope)

What an uploader may use (docs/uploaders.md): the playlists it changes pages of and the media folders it uploads into. Folders are exactly the listed ones, never their subfolders. An id that names no live object of the project when written is invalid_request at its position; a later deletion leaves a dead id, which grants nothing.

The scope is read on each request, so a change applies to the next one.

screen_scope (optional, ScreenScope)

What a scoped member or agent may act on (docs/screen-scope.md): the screens in the listed screen folders and in every folder inside them, and the listed screens. At least one id in all. An id that names no live folder or screen of the project when written is invalid_request at its position; a later deletion leaves a dead id, which grants nothing.

The scope is read on each request, so a change applies to the next one. Tags are never scope.

Request template and responses
shell · request template
curl --request POST --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --header 'Idempotency-Key: REQUEST_ID' --header 'Content-Type: application/json' --data '@request.json' 'https://api.screenrig.ai/api/projects/PROJECT_ID/invitations'

Responses

StatusMeaningBody and headers
201Creates member or ad-buyer invitations.InvitationCreated (application/json); headers: RateLimit-Policy, RateLimit
402

feature_not_in_plan — a screen scope needs Enterprise, and an upload scope (an uploader) needs Plus; the problem names the feature, the plan the account is on and required_plan. Narrowing an upload scope and removing either scope are always allowed.

Problem (application/problem+json)
403

outside_screen_scope - the caller is limited to screens and the screen, screen folder, selector or audience the request names or reaches is outside them (docs/screen-scope.md). An id outside the scope and an id that does not exist get the same answer; errors[0].screen_scope carries the caller's scope, and the write is refused whole, never narrowed.

Problem (application/problem+json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
429

Stable rate_limited problem. Retry only after the authoritative Retry-After interval. Fixed-window denials also include the applicable RateLimit-Policy and RateLimit members; concurrency and byte-budget denials omit those optional disclosures.

Problem (application/problem+json); headers: Retry-After, RateLimit-Policy, RateLimit
GET/api/projects/{project_id}/project

Get Project In Project

The calling project. Does not debit the 1-credit API meter, so a zero-remaining project can still read remaining and recover. After a successful project principal, authenticated /api JSON and problem responses include ScreenRig-Credits-Remaining, ScreenRig-Credits-Reset, and ScreenRig-Credits-Included as whole credits.

SSE, runtime, content, and unauthenticated responses omit them.

Authentication
projectBearer
Request body
none
Operation ID
getProjectInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' 'https://api.screenrig.ai/api/projects/PROJECT_ID/project'

Responses

StatusMeaningBody and headers
200ProjectProject (application/json); headers: ScreenRig-Credits-Remaining, ScreenRig-Credits-Reset, ScreenRig-Credits-Included, ScreenRig-Credits-Low
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
PATCH/api/projects/{project_id}/project

Update Project In Project

Renames the current project. Names contain 1–60 printable characters and no URL-looking text.

Authentication
projectBearer
Request body
ProjectPatch
Operation ID
updateProjectInProject

Parameters

NameSend inRequired?Description
project_idpathrequired

Request body fields

FieldDescription
project_id (optional, string)Expected project ID. The server refuses the action if the current credential or cookie session targets another project; browser clients send the page's project ID. minLength: 1 maxLength: 200
name (required, ProjectName)Trimmed printable project name. Rejects controls, URL-looking text, @, www., and ://. minLength: 1 maxLength: 60
Request template and responses
shell · request template
curl --request PATCH --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --header 'Content-Type: application/json' --data '@request.json' 'https://api.screenrig.ai/api/projects/PROJECT_ID/project'

Responses

StatusMeaningBody and headers
200Renames the current project.Project (application/json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
DELETE/api/projects/{project_id}/project

Delete Project Agent In Project

Only the project's owner or an administrator of its organization may delete it; any other caller is refused with forbidden. A person must also be a member of the project.

An agent needs the target membership project capability and deletes for its responsible person, who must be the owner or an organization administrator; an agent without a responsible person cannot delete, except the agent that enrolled the project while no person has accepted its enrollment.

Also requires the current name and revision, zero non-archived screens, no credit, reservations or debt in its own wallet and no live advertising. A negative balance run up under free or launch terms does not block; deletion writes it off with a project_delete_writeoff ledger entry. Queues member notices and uses the irreversible tombstone.

Authentication
projectBearer
Request body
ProjectDeleteConfirmation
Operation ID
deleteProjectAgentInProject

Parameters

NameSend inRequired?Description
project_idpathrequired

Request body fields

FieldDescription
project_id (optional, string)Expected project ID. The server refuses the action if the current credential or cookie session targets another project; browser clients send the page's project ID. minLength: 1 maxLength: 200
empty_only (optional, boolean)

Require an empty Screens project in the deletion transaction, including content, other agents or members, work and correspondence. The CLI additionally requires its saved enrollment provenance before using this cleanup guard. Omission keeps explicit member deletion.

name (required, ProjectName)Trimmed printable project name. Rejects controls, URL-looking text, @, www., and ://. minLength: 1 maxLength: 60
revision (required, integer)minimum: 1
Request template and responses
shell · request template
curl --request DELETE --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --header 'Content-Type: application/json' --data '@request.json' 'https://api.screenrig.ai/api/projects/PROJECT_ID/project'

Responses

StatusMeaningBody and headers
200Project lifecycle resultDeletedProject (application/json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/projects/{project_id}/applications

List Applications In Project

Lists applications newest first, at most 500 per page. Names are labels and need not be unique; address an application by id. next_cursor is the position of the last returned row while more rows remain; pass it back as after, with the same filters, for the next page. next_cursor is null on the last page.

Authentication
projectBearer
Request body
none
Operation ID
listApplicationsInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
afterqueryoptionalnext_cursor of the previous page of the same list, with the same filters. Omitted starts at the newest row. A value that is not such a cursor is invalid_request.
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' 'https://api.screenrig.ai/api/projects/PROJECT_ID/applications'

Responses

StatusMeaningBody and headers
200ApplicationsApplicationList (application/json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
POST/api/projects/{project_id}/applications

Upload Application In Project

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.

The proxy in front of the API ends a request it has not answered within about 100 s, so a large archive on a slow uplink fails here; POST /api/applications/uploads sends the archive straight to the object store instead.

Authentication
projectBearer
Request body
string
Operation ID
uploadApplicationInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
Idempotency-Keyheaderrequired
ScreenRig-Archive-SHA256headerrequired
ScreenRig-Expanded-Bytesheaderrequired
ScreenRig-File-Countheaderrequired
ScreenRig-SDK-Versionheaderoptional
ScreenRig-Application-Nameheaderoptional

ASCII application name; mutually exclusive with ScreenRig-Application-Name*. Leading and trailing whitespace is trimmed. Controls and duplicate header values are rejected. The decoded name is limited to 120 Unicode scalar values.

ScreenRig-Application-Name*headeroptional

Unicode application name encoded as RFC 8187 UTF-8'' followed by percent-encoded UTF-8 bytes (empty language, exact UTF-8 charset). Mutually exclusive with ScreenRig-Application-Name. Invalid escapes, invalid UTF-8, controls, and duplicate header values are rejected.

Leading and trailing whitespace is trimmed; the decoded name is limited to 120 Unicode scalar values. Neither name header may rename a release update. This avoids raw Unicode in HTTP header values.

Request template and responses
shell · request template
curl --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/gzip' --data-binary '@request.bin' 'https://api.screenrig.ai/api/projects/PROJECT_ID/applications'

Responses

StatusMeaningBody and headers
202Upload acceptedOperationAccepted (application/json); headers: RateLimit-Policy, RateLimit
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
POST/api/projects/{project_id}/applications/uploads

Create Application Upload In Project

Declares a direct upload of one CLI-produced tar.gz that creates a new application. The answer is a signed authorization for exactly one object PUT of the archive, so the bytes go straight to the object store and never through the API, whose proxy ends a request it has not answered within about 100 s.

PUT the archive to upload_url, then commit with POST /api/applications/uploads/{id}/commit and wait on the operation. The application, its release and the receiving operation exist from this answer on, as after POST /api/applications. An upload not committed within 24 hours fails, and an application that never published a release is removed.

The same Idempotency-Key and body answer the same upload with a freshly signed URL. GET /api/capabilities sets features.application_direct_uploads where these routes are served.

Authentication
projectBearer
Request body
ApplicationUploadDeclaration
Operation ID
createApplicationUploadInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
Idempotency-Keyheaderrequired

Request body fields

FieldDescription
name (optional, string)

Name of a new application, trimmed; at most 120 Unicode characters and no controls. Omitted or empty selects a generated name. A release declaration (POST /api/applications/{id}/uploads) must not carry one. maxLength: 120

sha256 (required, string)SHA-256 of the archive bytes. pattern: "^[0-9a-f]{64}$"
compressed_bytes (required, integer)Size of the archive in bytes. minimum: 1 maximum: 104857600
expanded_bytes (required, integer)minimum: 1 maximum: 262144000
file_count (required, integer)minimum: 1 maximum: 5000
sdk_version (optional, string)maxLength: 64
Request template and responses
shell · request template
curl --request POST --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --header 'Idempotency-Key: REQUEST_ID' --header 'Content-Type: application/json' --data '@request.json' 'https://api.screenrig.ai/api/projects/PROJECT_ID/applications/uploads'

Responses

StatusMeaningBody and headers
201Signed authorization for exactly one object PUT of the archive. Send the returned method and every returned header verbatim; the PUT must start before expires_at, two hours after the declaration.ApplicationUploadSession (application/json); headers: Cache-Control, RateLimit-Policy, RateLimit
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/projects/{project_id}/playlists

List Playlists V2 In Project

Versioned playlist list that may expose adslot pages. The v1 list refuses a page holding an ad-bearing document with version_required instead of filtering it.

Pages like listPlaylists, newest first, at most 200 per page and fewer once a page holds 8 MiB of stored playlists. next_cursor is the position of the last returned row while more rows remain; pass it back as after, with the same filters, for the next page. next_cursor is null on the last page. library=true lists the organization Library's playlists instead (read-only; schedule them or create from their templates).

Authentication
projectBearer
Request body
none
Operation ID
listPlaylistsV2InProject

Parameters

NameSend inRequired?Description
project_idpathrequired
libraryqueryoptional

true lists the organization's Library project instead of this project: its items are read-only here and carry library true. An organization with no Library, or the Library project itself, lists nothing with true.

afterqueryoptionalnext_cursor of the previous page of the same list, with the same filters. Omitted starts at the newest row. A value that is not such a cursor is invalid_request.
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' 'https://api.screenrig.ai/api/projects/PROJECT_ID/playlists'

Responses

StatusMeaningBody and headers
200Playlists with the adslot page union.PlaylistV2List (application/json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
POST/api/projects/{project_id}/playlists

Create Playlist V2 In Project

Authoring entry for the adslot page union. At most 16 adslot pages, at least one ordinary page with no visibility, and the reuse of one slot definition on different pages remain server checks. Reference resolution and DNS stay server checks.

A write that carries an iframe page the Player web app cannot frame is stored all the same, and its answer carries warnings (PlaylistWarning) and the project's event log gets one playlist.iframe_framing_refused event per such page.

A write whose iframe src, fallback_src or application params read a screen token ({screen.field.NAME} and the others of the primitive schemas) that a screen showing the playlist lacks also answers with a screen_fact_missing warning naming the first 20 such screens; those screens' manifests leave that primitive out.

An iframe src or fallback_src that is a Google Slides, Docs or Sheets link (share, Publish to web or embed) or a Microsoft 365 OneDrive or SharePoint Embed link is stored rebuilt for the screen, where Slides loop and advance on the link's delayms held to the page's duration, Docs, Sheets, Word and Excel reload every 5 minutes.

A pasted <iframe> embed code in src or fallback_src is read for its src. A file that asks viewers to sign in is refused with document_not_shared (400), whose errors[0].field is that src or fallback_src and whose detail names the sharing setting to change.

Authentication
projectBearer
Request body
PlaylistCreateRequest
Operation ID
createPlaylistV2InProject

Parameters

NameSend inRequired?Description
project_idpathrequired
Screenrig-Review-Noteheaderoptional

Optional proposer note on a review-class write, sent as percent-encoded UTF-8 (what JavaScript's encodeURIComponent writes). The server percent-decodes it (an invalid escape is 400 invalid_request); the decoded note is plain text, at most 280 characters after trimming, no control characters (else 400 invalid_request).

Stored on the review when the write becomes one; ignored when it applies live.

Idempotency-KeyheaderoptionalOmit for a fresh operation. Supply and reuse a key to deduplicate retries; the CLI manages keys automatically.
Request template and responses
shell · request template
curl --request POST --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --header 'Content-Type: application/json' --data '@request.json' 'https://api.screenrig.ai/api/projects/PROJECT_ID/playlists'

Responses

StatusMeaningBody and headers
202

The write became a review and waits for a person's approval (docs/reviews.md), under Propose access, or at any access level when it reaches a screen in a protected screen folder, where a second approver decides it (docs/screen-scope.md). A person approves, rejects or requests changes in the dashboard at review.url.

An Idempotency-Key replay answers the same body.

ReviewPending (application/json)
201Playlist with its adslot pages.PlaylistV2 (application/json)
402

feature_not_in_plan — Declaring fields, locking a primitive or changing a playlist that declares fields is a playlist template, and the project's plan does not include them; required_plan names the plan that does. Creating a playlist from a template is always allowed.

A format of 2 or more displays (a video wall) is part of Plus; a region format and a playlist with no format are in every plan. The problem names the feature, the project's plan and required_plan.

Problem (application/problem+json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/projects/{project_id}/screens

List Screens In Project

Default list returns pairing_pending and active screens. Pass state=archived to list archived screens only. Pass tag to list only screens whose tags contain that exact tag; untagged screens are omitted when the filter is present.

Pass field, once per field, as NAME:VALUE to list only screens whose fields hold every value, and near as LAT,LON,KM to list only screens located within KM kilometres of the point; screens with no location are omitted, and every filter combines with state and tag.

Pass folder as a screen folder ID to list only the screens directly inside it (not those of its subfolders), or root for the screens outside every folder.

Screens are newest first, at most 500 per page. next_cursor is the position of the last returned row while more rows remain; pass it back as after, with the same filters, for the next page. next_cursor is null on the last page. A caller limited to screens (docs/screen-scope.md) lists only the screens in its scope.

A request that names no project leaves out each project where the caller is limited to screens; name the project to list it.

Authentication
projectBearer
Request body
none
Operation ID
listScreensInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
statequeryoptionalOmit for pairing_pending and active. Pass archived to list archived screens only.
tagqueryoptionalExact screen tag. Untagged screens are omitted when this filter is present.
fieldqueryoptional

NAME:VALUE, split at the first colon: only screens whose field NAME holds exactly VALUE. Repeat the parameter for several fields; every one must match, and a name may be given once. A malformed or repeated one is invalid_request naming field.

nearqueryoptional

LAT,LON,KM in decimal degrees and kilometres, for example 47.6062,-122.3321,25: only screens whose location lies within KM kilometres of the point. Latitude is -90 to 90, longitude -180 to 180 and KM above 0 and at most 20038. Screens with no location are omitted. A malformed value is invalid_request naming near.

folderqueryoptionalA screen folder ID keeps only the screens directly inside that folder, not those of its subfolders; root keeps only the screens outside every folder. Omitted lists every screen.
afterqueryoptionalnext_cursor of the previous page of the same list, with the same filters. Omitted starts at the newest row. A value that is not such a cursor is invalid_request.
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' 'https://api.screenrig.ai/api/projects/PROJECT_ID/screens'

Responses

StatusMeaningBody and headers
200ScreensScreenList (application/json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/projects/{project_id}/screen-folders

List Screen Folders In Project

Lists every screen folder in the project, at most 1000, ordered by name.

Folders organize screens and target them: a campaign audience leaf {"folder": ID} matches the screens in that folder and every folder inside it, a fleet action selector by:folder acts on the same screens, and a folder's default_playlist_id is what its screens without a playlist of their own show. parent_id is null at the project root; build the tree from parent_id. screens counts the live screens directly inside each folder.

A screen's folder is Screen.folder_id. A caller limited to screens (docs/screen-scope.md) lists the folders inside its scope and the folders above them, which are read-only so its tree has a root; folders above carry no screens count and sibling folders are hidden. A request that names no project leaves out each project where the caller is limited to screens.

Authentication
projectBearer
Request body
none
Operation ID
listScreenFoldersInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' 'https://api.screenrig.ai/api/projects/PROJECT_ID/screen-folders'

Responses

StatusMeaningBody and headers
200Screen foldersScreenFolderList (application/json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
POST/api/projects/{project_id}/screen-folders

Create Screen Folder In Project

Creates one screen folder at the project root (parent_id null or absent) or inside parent_id. Names are trimmed, hold 1 to 100 Unicode characters with no controls, are not "." or "..", and are unique among their siblings (resource_conflict).

An organization holds at most 1000 folders across its projects (quota_exceeded) nested at most 10 deep (invalid_request). default_playlist_id, when set, must name an approved playlist (playlist_not_approved). Emits screen.folder_created.

A caller limited to screens (docs/screen-scope.md) creates a folder only inside a folder of its scope; the project root or any other parent is outside_screen_scope. Creating a folder inside a protected folder is a protected_change review (202 pending_review) decided by a second approver.

Authentication
projectBearer
Request body
ScreenFolderCreate
Operation ID
createScreenFolderInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
Idempotency-KeyheaderoptionalOmit for a fresh operation. Supply and reuse a key to deduplicate retries; the CLI manages keys automatically.

Request body fields

FieldDescription
name (required, string)Trimmed; 1 to 100 Unicode characters, no controls, not . or .., unique among its siblings. minLength: 1 maxLength: 100
parent_id (optional, inline)The folder to create it in; null or absent for the project root.
default_playlist_id (optional, string)An approved playlist for the folder's screens without their own. minLength: 1
Request template and responses
shell · request template
curl --request POST --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --header 'Content-Type: application/json' --data '@request.json' 'https://api.screenrig.ai/api/projects/PROJECT_ID/screen-folders'

Responses

StatusMeaningBody and headers
201Created folder.ScreenFolder (application/json); headers: ETag
202

The write became a review and waits for a person's approval (docs/reviews.md), under Propose access, or at any access level when it reaches a screen in a protected screen folder, where a second approver decides it (docs/screen-scope.md). A person approves, rejects or requests changes in the dashboard at review.url.

An Idempotency-Key replay answers the same body.

ReviewPending (application/json)
403outside_screen_scope as on OutsideScreenScope, or approver_required - a member limited to screens who cannot approve reviews does not change what a screen plays or when (docs/screen-scope.md).Problem (application/problem+json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
POST/api/projects/{project_id}/screens/move

Move Screens In Project

Moves screens (screen_ids) and folders (folder_ids) into one folder (folder_id), or to the project root when folder_id is null, in one all-or-nothing request of at most 1000 ids. Every id must exist (not_found). A folder cannot move into itself or a folder inside it, and the move must keep every folder within 10 levels (invalid_request).

Items already in the destination are left as they are; each moved screen and folder advances its revision. Moved screens re-resolve their playlist within about 15 seconds: levels names the campaigns whose folder audience they enter or leave and the folder default playlists they gain or lose. Emits screen.moved.

A caller limited to screens (docs/screen-scope.md) moves screens and folders inside its scope into a folder of its scope; any id or destination outside it, and the project root, refuse the whole move (outside_screen_scope), also when a screen leaves the scope between the check and the write.

A move into or out of a protected folder is a protected_change review (202 pending_review) decided by a second approver.

Authentication
projectBearer
Request body
ScreenMove
Operation ID
moveScreensInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
Idempotency-KeyheaderoptionalOmit for a fresh operation. Supply and reuse a key to deduplicate retries; the CLI manages keys automatically.

Request body fields

FieldDescription
folder_id (required, inline)Destination folder; null for the project root.
screen_ids (optional, array)
folder_ids (optional, array)
Request template and responses
shell · request template
curl --request POST --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --header 'Content-Type: application/json' --data '@request.json' 'https://api.screenrig.ai/api/projects/PROJECT_ID/screens/move'

Responses

StatusMeaningBody and headers
200How many screens and folders moved, and the levels the moved screens gain or lose.ScreenMoveResult (application/json)
202

The write became a review and waits for a person's approval (docs/reviews.md), under Propose access, or at any access level when it reaches a screen in a protected screen folder, where a second approver decides it (docs/screen-scope.md). A person approves, rejects or requests changes in the dashboard at review.url.

An Idempotency-Key replay answers the same body.

ReviewPending (application/json)
403outside_screen_scope as on OutsideScreenScope, or approver_required - a member limited to screens who cannot approve reviews does not change what a screen plays or when (docs/screen-scope.md).Problem (application/problem+json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/projects/{project_id}/schedule/calendar

Get Schedule Calendar In Project

Answers what a subject's screens play over [from, to) and why, for the dashboard's Schedule calendar: exactly one of screen_id, folder_id (the screens in the folder and every folder inside it), tag, or campaign_id (the screens in its audience).

Screens whose stacks have identical inputs (the same levels, default, timezone and display count) share one group with one timeline, so a large subject costs tens of timelines; a group lists up to 500 of its screens and an answer at most 200 groups (truncated).

Each group carries its stack, highest first (takeover, campaigns that reach the screens, their own schedule entries, then the default playlist or the nearest folder's), each level's spans (plays on every display it targets, partial with the displays it plays on, outranked, or conditional while it waits on interaction or a data condition only a Player observes), what each display shows (on_screen; the main region of a full page), and conflicts (two campaigns of one priority holding at once; a level that holds yet never plays). from and to are RFC 3339 instants, to after from, at most 93 days apart; they are truncated to the minute.

Rules are read in each group's timezone as the sweep and every Player read them; every level is judged playable. A caller limited to screens (docs/screen-scope.md) must send a screen_id or a folder_id inside its scope; a tag, a campaign_id or no subject is outside_screen_scope.

Authentication
projectBearer
Request body
none
Operation ID
getScheduleCalendarInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
fromqueryrequired
toqueryrequired
screen_idqueryoptional
folder_idqueryoptional
tagqueryoptional
campaign_idqueryoptional
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' 'https://api.screenrig.ai/api/projects/PROJECT_ID/schedule/calendar?from=FROM&to=TO'

Responses

StatusMeaningBody and headers
200The subject's calendar.ScheduleCalendar (application/json)
403

outside_screen_scope - the caller is limited to screens and the screen, screen folder, selector or audience the request names or reaches is outside them (docs/screen-scope.md). An id outside the scope and an id that does not exist get the same answer; errors[0].screen_scope carries the caller's scope, and the write is refused whole, never narrowed.

Problem (application/problem+json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/projects/{project_id}/schedule/imports/template

Get Schedule Import Template In Project

Answers a sheet with the columns a schedule import reads and three example rows (a screen code, a screen folder and a tag), as CSV or, with format=xlsx, an XLSX workbook.

Authentication
projectBearer
Request body
none
Operation ID
getScheduleImportTemplateInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
formatqueryoptional
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' 'https://api.screenrig.ai/api/projects/PROJECT_ID/schedule/imports/template'

Responses

StatusMeaningBody and headers
200The template sheet.string (text/csv), string (application/vnd.openxmlformats-officedocument.spreadsheetml.sheet)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
POST/api/projects/{project_id}/schedule/imports/preview

Preview Schedule Import In Project

Reads a sheet of schedule rows against the project and answers what committing it would do, writing nothing.

Each row names a target (a screen by id, by the value of a screen field such as a room code, or by name; folder:NAME; tag:NAME; several separated by ; or |), content (a media file name, or playlist:NAME or a playlist id), a start and an end (a date alone as the end closes that day), and optionally timezone, days (Mon-Fri), a daily window (daily_start, daily_end), priority 0 to 100, a name and display numbers.

Times are read on each screen's own clock; a timezone column converts them from another zone.

Every row is checked and reports its errors by column: unknown or ambiguous screen, folder or tag, missing or ambiguous file, a file that cannot fill a screen, invalid or reversed times, an end in the past, no timing at all, a screen without a time zone or a default playlist, two rows holding at once on a screen at the same priority, and more levels than a screen holds (32), or more campaigns than its organization holds across its projects (100; each shared level is one).

Rows that agree on content, times, priority and name become one level: one screen is an entry of that screen's own schedule; several screens, a folder or a tag are one shared level (a campaign), which outranks a screen's own levels.

The answer lists the levels with what a commit does to each (create, update, unchanged), the levels an earlier run of the same import made that the sheet no longer has (removals), the stacks of the screens as they would be (calendar), and a fingerprint to send to the commit. The sheet is JSON rows, CSV or XLSX, at most 5,000 rows.

Not available to a caller limited to screens (outside_screen_scope). Schedule import is part of the Enterprise plan; a project whose plan lacks it is refused with feature_not_in_plan (402). The template is open on every plan.

Authentication
projectBearer
Request body
ScheduleImportRequest
Operation ID
previewScheduleImportInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
namequeryoptionalThe import's name; importing again under the same name updates the levels it made (default import). Sent with a file body.
timezonequeryoptionalThe IANA zone the times are written in when a row has no timezone. Without one, times are read on each screen's own clock.
sourcequeryoptionalThe file name, recorded with the import.
code_fieldqueryoptionalRead a screen code only from this screen field (for example code or room_id); otherwise a code matches any field.

Request body fields

FieldDescription
name (optional, string)Identifies the import; the same name updates the levels it made (default import). minLength: 1 maxLength: 80
source (optional, string)The file the rows came from. maxLength: 200
timezone (optional, string)The IANA zone the times are written in when a row has no timezone.
code_field (optional, string)Read a screen code only from this screen field.
fingerprint (optional, string)The preview's fingerprint; required by the commit.
rows (required, array)
Request template and responses
shell · request template
curl --request POST --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --header 'Content-Type: application/json' --data '@request.json' 'https://api.screenrig.ai/api/projects/PROJECT_ID/schedule/imports/preview'

Responses

StatusMeaningBody and headers
200The preview. valid is false while any row has an error.ScheduleImportPreview (application/json)
402feature_not_in_plan — Schedule import is part of the Enterprise plan; the problem names the feature, the plan the account is on and required_plan.Problem (application/problem+json)
403

outside_screen_scope - the caller is limited to screens and the screen, screen folder, selector or audience the request names or reaches is outside them (docs/screen-scope.md). An id outside the scope and an id that does not exist get the same answer; errors[0].screen_scope carries the caller's scope, and the write is refused whole, never narrowed.

Problem (application/problem+json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
POST/api/projects/{project_id}/schedule/imports

Commit Schedule Import In Project

Commits a previewed import: the same sheet and the fingerprint its preview answered. Every level is created, updated or removed, the screens' schedules and the shared levels written in one transaction, and the import event schedule.imported appended: all rows apply or none does.

The one-file playlists the sheet's files need are made first (they change nothing on any screen). A sheet whose rows have errors is refused (schedule_import_invalid); a project that changed since the preview, or rows that read differently, is refused (schedule_import_stale), and the client previews again.

Importing the same sheet again under the same name changes nothing; a changed row updates its level and a removed row removes its level. Needs a person who can approve in the dashboard and a credential with write access for an agent.

A commit that would update or delete a reserved campaign answers reserved_item (403) and writes nothing, unless a person who can approve commits it.

A commit that reaches a protected screen is refused whole with protected_target, also when the import has no levels but removes import entries of a protected screen or deletes an import campaign whose audience reaches one.

In a project with protected screen folders a commit whose preview fails on a service, not on the sheet, answers dependency_unavailable and writes nothing: send the same request again after a short wait. A sheet, campaign or screen validation error answers as the commit would (invalid_request and the other problems above).

Not available to a caller limited to screens. Schedule import is part of the Enterprise plan; a project whose plan lacks it is refused with feature_not_in_plan (402). The template is open on every plan.

Authentication
projectBearer
Request body
ScheduleImportRequest
Operation ID
commitScheduleImportInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
Idempotency-KeyheaderoptionalOmit for a fresh operation. Supply and reuse a key to deduplicate retries; the CLI manages keys automatically.
fingerprintqueryoptionalThe preview's fingerprint, for a CSV or XLSX body; a JSON body carries it as a member.
namequeryoptionalThe import's name; importing again under the same name updates the levels it made (default import). Sent with a file body.
timezonequeryoptionalThe IANA zone the times are written in when a row has no timezone. Without one, times are read on each screen's own clock.
sourcequeryoptionalThe file name, recorded with the import.
code_fieldqueryoptionalRead a screen code only from this screen field (for example code or room_id); otherwise a code matches any field.

Request body fields

FieldDescription
name (optional, string)Identifies the import; the same name updates the levels it made (default import). minLength: 1 maxLength: 80
source (optional, string)The file the rows came from. maxLength: 200
timezone (optional, string)The IANA zone the times are written in when a row has no timezone.
code_field (optional, string)Read a screen code only from this screen field.
fingerprint (optional, string)The preview's fingerprint; required by the commit.
rows (required, array)
Request template and responses
shell · request template
curl --request POST --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --header 'Content-Type: application/json' --data '@request.json' 'https://api.screenrig.ai/api/projects/PROJECT_ID/schedule/imports'

Responses

StatusMeaningBody and headers
200What the commit applied.ScheduleImportCommitted (application/json)
402feature_not_in_plan — Schedule import is part of the Enterprise plan; the problem names the feature, the plan the account is on and required_plan.Problem (application/problem+json)
403

outside_screen_scope - the caller is limited to screens and the screen, screen folder, selector or audience the request names or reaches is outside them (docs/screen-scope.md). An id outside the scope and an id that does not exist get the same answer; errors[0].screen_scope carries the caller's scope, and the write is refused whole, never narrowed.

Problem (application/problem+json)
409

protected_target - the change reaches a screen in a protected screen folder and has no review form (docs/screen-scope.md). Clear the folder's protection through a review, make the change, and protect the folder again.

Problem (application/problem+json)
500dependency_unavailable - the check for protected screen folders could not run; send the same request again after a short wait.Problem (application/problem+json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
POST/api/projects/{project_id}/project/browser-links/claim

Claim Browser Link In Project

Claims one browser-link code for the authenticated project and atomically creates exactly one first pairing_pending screen plus its existing browser provisioning grant. Enrollment remains project-only. The response is safe metadata only and never contains a provisioning token, fragment URL, cookie, or proof.

Authentication
projectBearer
Request body
BrowserLinkClaimRequest
Operation ID
claimBrowserLinkInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
Idempotency-Keyheaderrequired

Request body fields

FieldDescription
code (required, string)pattern: "^[23456789ABCDEFGHJKMNPQRSTUVWXYZ]{3}-?[23456789ABCDEFGHJKMNPQRSTUVWXYZ]{3}$"
Request template and responses
shell · request template
curl --request POST --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --header 'Idempotency-Key: REQUEST_ID' --header 'Content-Type: application/json' --data '@request.json' 'https://api.screenrig.ai/api/projects/PROJECT_ID/project/browser-links/claim'

Responses

StatusMeaningBody and headers
201Exact replay-safe fragment-free browser-link claim.BrowserLinkClaim (application/json); headers: Cache-Control, RateLimit-Policy, RateLimit
400

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
403

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
404

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
409

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
410

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
429

Stable rate_limited problem. Retry only after the authoritative Retry-After interval. Fixed-window denials also include the applicable RateLimit-Policy and RateLimit members; concurrency and byte-budget denials omit those optional disclosures.

Problem (application/problem+json); headers: Retry-After, RateLimit-Policy, RateLimit
500

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
POST/api/projects/{project_id}/screens/pair

Pair Screen In Project

Claims one fleet-global six-character Player pairing session. Exact Idempotency-Key retries return the durable original result without consuming quota again.

The dashboard session claims into its current project with the same body, Idempotency-Key, budgets and problems, except that its not_found for an unknown or already-claimed code names no CLI command; it is a state change, so it follows the dashboard mutation rules, a shadow session without staff write mode is refused, and the events the claim appends name the dashboard user. folder_id names the folder the screen lands in.

A caller limited to screens (docs/screen-scope.md) must send a folder inside its scope and pairs only as a person who can approve (outside_screen_scope, approver_required).

Authentication
projectBearer
Request body
PairScreen
Operation ID
pairScreenInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
Idempotency-Keyheaderrequired

Request body fields

FieldDescription
code (required, string)pattern: "^[23456789ABCDEFGHJKMNPQRSTUVWXYZ]{6}$"
label (optional, string)minLength: 1 maxLength: 120
folder_id (optional, string)

The screen folder the screen lands in; omitted lands it at the project root. A caller limited to screens must send a folder inside its scope (outside_screen_scope otherwise). A folder the project does not hold is invalid_request for a caller of the whole project.

Part of the idempotent request: another folder_id under the same Idempotency-Key is idempotency_mismatch. minLength: 1

Request template and responses
shell · request template
curl --request POST --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --header 'Idempotency-Key: REQUEST_ID' --header 'Content-Type: application/json' --data '@request.json' 'https://api.screenrig.ai/api/projects/PROJECT_ID/screens/pair'

Responses

StatusMeaningBody and headers
201Durable pairing_pending screen claim.PairingClaim (application/json); headers: Cache-Control, RateLimit-Policy, RateLimit
400

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
401

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
404

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
409

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
413

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
429

Stable rate_limited problem. Retry only after the authoritative Retry-After interval. Fixed-window denials also include the applicable RateLimit-Policy and RateLimit members; concurrency and byte-budget denials omit those optional disclosures.

Problem (application/problem+json); headers: Retry-After, RateLimit-Policy, RateLimit
500

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
403outside_screen_scope as on OutsideScreenScope, or approver_required - a member limited to screens who cannot approve reviews does not change what a screen plays or when (docs/screen-scope.md).Problem (application/problem+json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
POST/api/projects/{project_id}/screens/provision

Provision Screen In Project

Optional browser-only new-screen provisioning. Always creates one new pairing_pending screen; at most five wait to pair at once (quota_exceeded). Exact retries redeliver the same fragment token for ten minutes. Six-character pairing remains the default and only recovery flow. folder_id names the folder the screen lands in.

A caller limited to screens (docs/screen-scope.md) must send a folder inside its scope (outside_screen_scope otherwise).

Authentication
projectBearer
Request body
ProvisionScreen
Operation ID
provisionScreenInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
Idempotency-Keyheaderrequired

Request body fields

FieldDescription
label (optional, string)minLength: 1 maxLength: 120
folder_id (optional, string)The screen folder the screen lands in, as on PairScreen. minLength: 1
Request template and responses
shell · request template
curl --request POST --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --header 'Idempotency-Key: REQUEST_ID' --header 'Content-Type: application/json' --data '@request.json' 'https://api.screenrig.ai/api/projects/PROJECT_ID/screens/provision'

Responses

StatusMeaningBody and headers
201New browser provisioning link.ScreenProvisioning (application/json); headers: Cache-Control, RateLimit-Policy, RateLimit
400

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
401

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
409

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
410

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
413

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
429

Stable rate_limited problem. Retry only after the authoritative Retry-After interval. Fixed-window denials also include the applicable RateLimit-Policy and RateLimit members; concurrency and byte-budget denials omit those optional disclosures.

Problem (application/problem+json); headers: Retry-After, RateLimit-Policy, RateLimit
500

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
403outside_screen_scope as on OutsideScreenScope, or approver_required - a member limited to screens who cannot approve reviews does not change what a screen plays or when (docs/screen-scope.md).Problem (application/problem+json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
POST/api/projects/{project_id}/screens/actions

Apply Screen Actions In Project

Applies one action to a selected fleet with no screen-count cap. Select unique screen_ids or a tag matching active screens in creation order. The resolved selection is pinned before any mutation, stored in bounded chunks, and kept for twenty-four hours under Idempotency-Key.

Each step uses its single-screen mutation path, preserving revisions, events, runtime signals and per-screen limits. A response contains one bounded page of results; matched, succeeded and failed describe that page. HTTP 202 includes total, offset and next_cursor. Continue with the same selector, action and Idempotency-Key, passing next_cursor as after.

Honor Retry-After when present, including a page with zero results. The response echoes Idempotency-Key, including a generated key when the caller omitted it; retain this key for continuations. HTTP 200 finishes the selection. Answered pages replay exactly, including per-screen failures; interrupted steps replay without repeating their effects.

Large actions are paced against the existing 600-per-minute organization budgets for reload, toast, takeover, playlist schedules, reboot, display and display schedules; organization exhaustion pauses the action instead of refusing the fleet. Per-screen exhaustion fails that screen alone.

An assign, takeover or set_playlist_schedule step that binds a playlist with a format to a screen whose wall has another shape fails that screen alone with 409 playlist_format_mismatch. Assign and tag changes have no message budget.

An assign whose playlist has an iframe src or application params that read a screen token some screen of the page lacks adds a screen_fact_missing warning to that page (warnings, PlaylistWarning). Partial failure is a normal result. All pages and retries under one key are one metered action.

Requests use a bounded byte payload; use a tag for a selection larger than the transport payload. A malformed selector or action is refused before any screen is touched. selector or action is refused before any screen is touched.

A caller limited to screens (docs/screen-scope.md) selects by screen_ids or by folder, every screen inside its scope; a tag selector, a screen outside the scope or an unknown one refuses the whole action (outside_screen_scope) before anything is pinned or proposed.

Assign, takeover, takeover_clear, set_playlist_schedule and clear_playlist_schedule that reach a protected screen become a review decided by a second approver (202 pending_review) at every access level; set_tags, add_tags and remove_tags on a protected screen are protected_target (409).

A set_playlist_schedule action with a paused entry (a draft) is schedule change control, which the Enterprise plan includes; a project whose plan lacks it is refused with feature_not_in_plan (402).

Authentication
projectBearer
Request body
ScreenActionRequest
Operation ID
applyScreenActionsInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
Screenrig-Review-Noteheaderoptional

Optional proposer note on a review-class write, sent as percent-encoded UTF-8 (what JavaScript's encodeURIComponent writes). The server percent-decodes it (an invalid escape is 400 invalid_request); the decoded note is plain text, at most 280 characters after trimming, no control characters (else 400 invalid_request).

Stored on the review when the write becomes one; ignored when it applies live.

Idempotency-KeyheaderoptionalOmit for a fresh operation. Supply and reuse a key to deduplicate retries; the CLI manages keys automatically.
afterqueryoptionalnext_cursor from the preceding result page. Reuse the original Idempotency-Key and request body.

Request body fields

FieldDescription
selector (required, ScreenActionSelector)
action (required, ScreenAction)One fleet action, discriminated by type. Each member carries only its own parameters; a member of another type is an unknown field and invalid_request.
Request template and responses
shell · request template
curl --request POST --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --header 'Content-Type: application/json' --data '@request.json' 'https://api.screenrig.ai/api/projects/PROJECT_ID/screens/actions'

Responses

StatusMeaningBody and headers
200Per-screen results. Partial success is a normal answer.ScreenActionResult (application/json); headers: Idempotency-Key, Cache-Control, RateLimit-Policy, RateLimit
202

More screens remain (continue with next_cursor and the same Idempotency-Key and body, honoring Retry-After), or, with status pending_review, the action became a review under Propose access (docs/reviews.md), or at any access level because it reaches a screen in a protected screen folder (docs/screen-scope.md).

Only assign, takeover, takeover_clear, set_playlist_schedule and clear_playlist_schedule become reviews; every other action is insufficient_access for Propose.

inline (application/json); headers: Idempotency-Key, Retry-After, Cache-Control, RateLimit-Policy, RateLimit
400

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
401

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
402

feature_not_in_plan — set_reboot_schedule with enabled true (Scheduled reboots) and set_playlist_schedule with a displays lock (Video walls) are part of Plus; the clearing actions and one-off commands are open. payment_required — the project has no credit left. The problem names the feature, the project's plan and required_plan.

Problem (application/problem+json)
403insufficient_access, outside_screen_scope when a caller limited to screens selects outside its scope, or approver_required for a member limited to screens who cannot approve.Problem (application/problem+json)
409

playlist_format_mismatch and the other conflicts of the action, or protected_target when set_tags, add_tags, remove_tags, toast, display, display_clear, set_display_schedule or clear_display_schedule reaches a screen in a protected screen folder.

Problem (application/problem+json)
429

Stable rate_limited problem. Retry only after the authoritative Retry-After interval. Fixed-window denials also include the applicable RateLimit-Policy and RateLimit members; concurrency and byte-budget denials omit those optional disclosures.

Problem (application/problem+json); headers: Retry-After, RateLimit-Policy, RateLimit
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
POST/api/projects/{project_id}/tab-shares

Start Tab Share In Project

Shows browser tabs on screens in the named project; the request, answer, access and limits are those of POST /api/tab-shares.

Authentication
projectBearer
Request body
TabShareWrite
Operation ID
startTabShareInProject

Parameters

NameSend inRequired?Description
project_idpathrequired

Request body fields

FieldDescription
screen_ids (optional, array)Screens by id. Duplicates collapse.
folder_ids (optional, array)Screen folders; each includes every folder inside it.
tags (optional, array)A screen carrying any of the tags.
tabs (required, array)
cookies (optional, array)The sender's cookies for the pages, at most 64 KiB encoded. Secrets; see POST /api/tab-shares.
reload_s (optional, integer)0 (never, the default) or 60 to 86400: every page's iframe reloads this often.
until (optional, string)Strictly in the future and at most 24 hours ahead; 24 hours from now when omitted. The end of the takeover on every target and the expiry of the temporary playlist. format: "date-time"
qr (optional, boolean)When true every page carries a QR code of its address in the bottom-right corner. Default false.
Request template and responses
shell · request template
curl --request POST --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --header 'Content-Type: application/json' --data '@request.json' 'https://api.screenrig.ai/api/projects/PROJECT_ID/tab-shares'

Responses

StatusMeaningBody and headers
200The share. At least one screen was taken over.TabShare (application/json); headers: RateLimit-Policy, RateLimit
400

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
401

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
404

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
409

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
429

Stable rate_limited problem. Retry only after the authoritative Retry-After interval. Fixed-window denials also include the applicable RateLimit-Policy and RateLimit members; concurrency and byte-budget denials omit those optional disclosures.

Problem (application/problem+json); headers: Retry-After, RateLimit-Policy, RateLimit
403outside_screen_scope as on OutsideScreenScope, or approver_required - a member limited to screens who cannot approve reviews does not change what a screen plays or when (docs/screen-scope.md).Problem (application/problem+json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/projects/{project_id}/campaigns

List Campaigns In Project

Lists the project's campaigns in precedence order (at most 100), the order resolution reads them. reserved is present on every campaign.

A caller limited to screens (docs/screen-scope.md) sees every campaign, with editable true only when the whole audience is inside its scope (a tag leaf and the root every-screen rule never are; an all rule needs one contained child, an any rule every child) and the caller may change what plays.

Authentication
projectBearer
Request body
none
Operation ID
listCampaignsInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' 'https://api.screenrig.ai/api/projects/PROJECT_ID/campaigns'

Responses

StatusMeaningBody and headers
200The project's campaigns.CampaignList (application/json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
POST/api/projects/{project_id}/campaigns

Create Campaign In Project

createCampaign for the project named in the path. reserved true reserves the campaign, and only a person who can approve sets it (reserved_item for an agent, a service client or anyone else), appending campaign.reserved_changed.

A caller limited to screens (docs/screen-scope.md) creates a campaign only for an audience inside its scope (folder and screen_id leaves; no tag, no every screen), else outside_screen_scope, and only as a person who can approve (approver_required).

A campaign whose audience reaches a protected screen is a protected_change review decided by a second approver (202 pending_review) at every access level. reserved true is protected folders and paused true on a new campaign (a draft) is schedule change control, both part of the Enterprise plan; a project whose plan lacks it is refused with feature_not_in_plan (402).

Authentication
projectBearer
Request body
CampaignWrite
Operation ID
createCampaignInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
Idempotency-KeyheaderoptionalOmit for a fresh operation. Supply and reuse a key to deduplicate retries; the CLI manages keys automatically.

Request body fields

FieldDescription
name (required, string)minLength: 1 maxLength: 120
playlist_id (required, string)minLength: 1
audience (required, CampaignAudience)

Which screens a campaign targets: exactly one of all (every rule matches), any (at least one matches), tag (the screen carries the tag), screen_id (that screen) or folder (the screens in that screen folder and every folder inside it, GET /api/screen-folders; the folder must exist).

Rules nest at most 3 deep and an audience has at most 500 rules. {"all": []} is every screen of the project; elsewhere all and any list at least one rule.

from (optional, string)pattern: "^[0-9]{4}-[0-9]{2}-[0-9]{2}T([01][0-9]|2[0-3]):[0-5][0-9]$"
until (optional, string)Later than from. pattern: "^[0-9]{4}-[0-9]{2}-[0-9]{2}T([01][0-9]|2[0-3]):[0-5][0-9]$"
windows (optional, array)
monthly (optional, array)
dates (optional, array)
except (optional, array)Civil dates, stored ascending and once each. An exception removes every occurrence its date starts, overnight tails included; it falls between from and until.
data (optional, PageDataCondition)

A card-data predicate, evaluated before civil time. Missing or expired data never matches. The page also respects its ordinary time bounds. Requires host capability page.conditions; older hosts receive the page disabled.

interaction (optional, LevelInteraction)

The level holds while someone is using the screen: from a touch, click or key until idle_s seconds pass with no input. Typical use: an interactive page above an attract loop. idle_s is stored and returned (60 when omitted).

covers (optional, string)

Where the level plays: the full page (default, stored absent) or main, the page itself, for an ordinary playlist; header, footer or side, a strip drawn over the page, for a region playlist of that region only (PlaylistRegionFormat). A region playlist is refused with full or main, and a strip needs a region playlist that is laid out on a targeted display.

Allowed: "full", "main", "header", "footer", "side"

displays (optional, array)The outputs of a video wall it plays on; absent plays on every output.
start (optional, string)on_time switches at the edge, interrupting the current item; next_item (default, stored absent) waits for it to end. Allowed: "next_item", "on_time"
priority (optional, integer)default: 0 minimum: 0 maximum: 100
paused (optional, boolean)default: false
reserved (optional, boolean)Only a person who can approve reserves a campaign (reserved_item otherwise). default: false
Request template and responses
shell · request template
curl --request POST --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --header 'Content-Type: application/json' --data '@request.json' 'https://api.screenrig.ai/api/projects/PROJECT_ID/campaigns'

Responses

StatusMeaningBody and headers
201Created.Campaign (application/json); headers: ETag
202

The write became a review and waits for a person's approval (docs/reviews.md), under Propose access, or at any access level when it reaches a screen in a protected screen folder, where a second approver decides it (docs/screen-scope.md). A person approves, rejects or requests changes in the dashboard at review.url.

An Idempotency-Key replay answers the same body.

ReviewPending (application/json)
402

feature_not_in_plan — Protected folders and schedule change control are part of the Enterprise plan; the problem names the feature, the plan the account is on and required_plan. A campaign that locks a playlist to display 2 or beyond of a video wall (displays) is part of Plus. The problem names the feature, the project's plan and required_plan.

Problem (application/problem+json)
403

outside_screen_scope or approver_required as on ScreenScopePlays, or reserved_item - a reserved campaign is changed, paused, deleted or un-reserved only by a person who can approve reviews, never by an agent or a service client (docs/screen-scope.md).

Problem (application/problem+json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/projects/{project_id}/connections

List Connections In Project

Lists the project's connections, newest first, at most 200 a page; pass next_cursor back as after for the next. A secret, a key or a refresh token is never returned: secret shows whether one is held and a hint that is not secret. A read never carries a consent link.

Authentication
projectBearer
Request body
none
Operation ID
listConnectionsInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
afterqueryoptionalnext_cursor of the previous page of the same list, with the same filters. Omitted starts at the newest row. A value that is not such a cursor is invalid_request.
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' 'https://api.screenrig.ai/api/projects/PROJECT_ID/connections'

Responses

StatusMeaningBody and headers
200One page of connections.ConnectionList (application/json); headers: Cache-Control
400invalid_request, including a malformed cursor.Problem (application/problem+json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
POST/api/projects/{project_id}/connections

Create Connection In Project

Creates a connection to Microsoft or Google in this project: mode own_app with the customer's own credentials, or mode screenrig_app, which answers consent_url, a one-time link for the person who completes it (see createConnection). Appends connection.created. An exact retry with the same Idempotency-Key returns the same connection.

Authentication
projectBearer
Request body
ConnectionWrite
Operation ID
createConnectionInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
Idempotency-KeyheaderoptionalOmit for a fresh operation. Supply and reuse a key to deduplicate retries; the CLI manages keys automatically.

Request body fields

FieldDescription
provider (required, string)Allowed: "microsoft", "google"
mode (required, string)Allowed: "own_app", "screenrig_app"
name (required, string)minLength: 1 maxLength: 80
config (optional, ConnectionConfigWrite)Microsoft, mode own_app: both members. Not accepted for a Google connection or for mode screenrig_app.
secret (optional, string)

Mode own_app. Microsoft: the value of one of the app's client secrets (not its id; at most 1024 characters), with config.tenant_id and config.client_id. Google: the service account's JSON key file, whole (at most 16384 bytes). Sealed on arrival and never returned; the CLI reads it from a file or stdin, never an argument.

Not accepted in mode screenrig_app. minLength: 1 maxLength: 16384

Request template and responses
shell · request template
curl --request POST --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --header 'Content-Type: application/json' --data '@request.json' 'https://api.screenrig.ai/api/projects/PROJECT_ID/connections'

Responses

StatusMeaningBody and headers
201Created. A connection in mode screenrig_app carries consent_url and consent_expires_at.ConnectionConsent (application/json); headers: ETag, Location, Cache-Control
400invalid_request, naming the field that is not valid.Problem (application/problem+json)
409connection_app_not_configured, connection_limit_reached or idempotency_mismatch.Problem (application/problem+json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/projects/{project_id}/bi-connections

List BIConnections In Project

Lists the project's BI connections, oldest first, 200 to a page; pass next_cursor back as cursor for the next. A secret is never returned: secret shows whether it is set and its last 4 characters.

Authentication
projectBearer
Request body
none
Operation ID
listBIConnectionsInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
cursorqueryoptionalnext_cursor of the previous page.
limitqueryoptional
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' 'https://api.screenrig.ai/api/projects/PROJECT_ID/bi-connections'

Responses

StatusMeaningBody and headers
200One page of connections.BIConnectionList (application/json); headers: Cache-Control
400invalid_request, including a malformed cursor.Problem (application/problem+json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
POST/api/projects/{project_id}/bi-connections

Create BIConnection In Project

Adds a connection to a BI system the project owns. For Grafana: its address (http or https on a public host, with an optional path prefix) and a service-account token with the Viewer role. The token is sealed and never returned.

Grafana renders dashboards for screens through its Image Renderer plugin or remote rendering service, so the customer installs one; run POST /api/bi-connections/{id}/test to check. For Power BI (kind powerbi): config.tenant_id and config.client_id of a Microsoft Entra app registration and its client secret value as secret.

A Power BI admin must turn on the Developer settings Embed content in apps and Service principals can call Fabric public APIs for the app (admin portal, Tenant settings), the app must be a Member or Admin of each workspace it shows, and reports need an Embedded, Fabric or Premium capacity for production use.

For Tableau (kind tableau): config.url (the https address of Tableau Server, or of your Tableau Cloud pod such as https://10ay.online.tableau.com), config.site (the site content URL, empty for the default site), config.client_id and config.secret_id of a connected app with direct trust, config.username (the Tableau user the screens views are shown as) and the secret value as secret.

Add the answer embed_origin to the connected app domain allowlist and enable the secret. Anyone holding a screen ticket can embed any view that user can see, so use a user that sees only screen dashboards. Tableau Cloud, or Tableau Server 2023.3 or later.

For a signed-in web page (kind web): the service account of a site that shows its dashboard behind a sign-in. config.login_mode is auto (config.login_url, config.username and the password as secret: the renderer opens the sign-in page and fills the form), steps (config.login_url and config.steps, a script of goto, fill, click, press, wait_for and wait_ms steps whose values may hold {{username}}, {{password}} and {{otp}}) or none (no sign-in: the connection shows pages with the cookies you give it). totp_secret is the base32 key, or the otpauth:// address, of the account's authenticator app: the server computes the one-time code (RFC 6238) and sends the renderer only the code. cookies is a cookie jar exported from a signed-in browser, for a site whose sign-in cannot be scripted (single sign-on that approves on a phone, a device check); the server keeps the jar and renews it from the cookies each capture returns, so a sign-in is rare.

The password, the seed and the cookies are sealed and never returned. Use a read-only service account. The password is typed only into config.login_url and the goto steps, so moving those to another origin needs secret again. After five refused sign-ins in a row the connection stops signing in until its credentials change.

A server with no page renderer answers bi_web_unavailable. Appends bi_connection.created. An exact retry with the same Idempotency-Key returns this same answer.

Authentication
projectBearer
Request body
BIConnectionWrite
Operation ID
createBIConnectionInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
Idempotency-KeyheaderoptionalOmit for a fresh operation. Supply and reuse a key to deduplicate retries; the CLI manages keys automatically.

Request body fields

FieldDescription
name (required, string)minLength: 1 maxLength: 80
kind (required, string)Allowed: "grafana", "powerbi", "tableau", "web"
config (required, BIConnectionConfig)
secret (optional, string)

Required except for web, and for a Power BI connection that names connection_id. The service-account token (Grafana), the app's client secret value (Power BI), the connected app's secret value (Tableau) or the service account's password (web: required by login_mode auto, not used by none).

Sealed on arrival; the CLI reads it from a file or stdin, never an argument. minLength: 1 maxLength: 4096

totp_secret (optional, string)

Web: the base32 key of the account's authenticator app (16 to 128 characters, spaces allowed), or its otpauth://totp address, which may set the algorithm (SHA1, SHA256, SHA512), the digits (6 to 8) and the period. Sealed; only the computed code leaves the server. maxLength: 1024

cookies (optional, array)Web: a cookie jar exported from a signed-in browser. Sealed; renewed from every capture.
Request template and responses
shell · request template
curl --request POST --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --header 'Content-Type: application/json' --data '@request.json' 'https://api.screenrig.ai/api/projects/PROJECT_ID/bi-connections'

Responses

StatusMeaningBody and headers
201Created.BIConnection (application/json); headers: ETag, Cache-Control
400invalid_request, including an address that is not a public Internet host.Problem (application/problem+json)
402feature_not_in_plan — the project's plan does not include BI dashboards; required_plan names the plan that does.Problem (application/problem+json)
409idempotency_mismatch.Problem (application/problem+json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/projects/{project_id}/bi-views

List BIViews In Project

Lists the project's BI views, oldest first, 200 to a page; pass next_cursor back as cursor for the next. Each carries embed_url, the address an iframe primitive shows (content_fit fill); it is null where this server has no embed host.

Authentication
projectBearer
Request body
none
Operation ID
listBIViewsInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
cursorqueryoptionalnext_cursor of the previous page.
limitqueryoptional
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' 'https://api.screenrig.ai/api/projects/PROJECT_ID/bi-views'

Responses

StatusMeaningBody and headers
200One page of views.BIViewList (application/json); headers: Cache-Control
400invalid_request, including a malformed cursor.Problem (application/problem+json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
POST/api/projects/{project_id}/bi-views

Create BIView In Project

Adds a view of a connection's Grafana dashboard or one panel of it (url: a /d/{uid}/... address on the connection's host, or target), or of a Grafana public dashboard link (kind grafana and target.public_url, no connection).

Put the answer's embed_url in an iframe primitive: the server renders the dashboard as a PNG through Grafana's /render API, refreshed every refresh_s (30 to 86400, default 300) and shared by every screen of the same size; the screen never talks to Grafana. A public dashboard plays live from Grafana, which must allow embedding.

The embed page shows only a ticket the screen's manifest carries, so a view plays only on the screens of its own project.

For Power BI (kind powerbi): a report of a workspace the connection's app is a member of (url: an app.powerbi.com /groups/{workspace}/reports/{report} address, or target with workspace_id and report_id), with pages to show and rotate_s to rotate through them (pages listing two or more, or rotate_all_pages, need rotate_s of 10 to 3600; one report page needs none), and refresh_s of 0 (no refresh) or 60 to 86400 (default 300).

The page asks the server for a short-lived view-only embed token (GenerateToken, App owns data) and renews it before it expires; the screen never holds the client secret. A Power BI Publish to web link is a view without a connection (kind powerbi, target.public_url https://app.powerbi.com/view?r=...), framed as it is.

For Tableau (kind tableau): a view of the connection site (url: an address copied from Tableau, such as https://HOST/t/SITE/views/WORKBOOK/VIEW or Tableau Cloud https://HOST/#/site/SITE/views/WORKBOOK/VIEW, or Workbook/View; or target.view), optionally with target.rotate_sheets and rotate_s of 10 to 3600 to turn the workbook published sheets (rotate_s and rotate_sheets go together; rotate_sheets may be given as the whole target beside url), and refresh_s of 0 (no refresh) or 60 to 86400 (default 300).

The page asks the server for a five minute JWT with only the embed scope, signed with the connected app secret, and builds the Embedding API v3 tableau-viz from the Tableau host; the screen never holds the secret.

A Tableau Public viz is a view without a connection (kind tableau, target.public_url, rebuilt as https://public.tableau.com/views/WORKBOOK/VIEW) and takes rotate_sheets too. For a web page (kind web): a page of the web connection's site (url: an https address on a public host, with no target).

The browser on the edge opens it signed in, waits for the element wait_for when set and wait_ms milliseconds (up to 10000), and draws clip, a CSS selector, when set, else the whole page.

The image is drawn every refresh_s (60 to 86400, default 300) and shared by every screen of the same size, and only while a screen shows the view; when a capture fails the last image stays on glass. Set wait_for to an element that exists only when the page is signed in, so a sign-in page is never shown. Appends bi_view.created.

Authentication
projectBearer
Request body
BIViewWrite
Operation ID
createBIViewInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
Idempotency-KeyheaderoptionalOmit for a fresh operation. Supply and reuse a key to deduplicate retries; the CLI manages keys automatically.

Request body fields

FieldDescription
connection_id (optional, string)
kind (optional, string)Required without a connection_id; otherwise it must match the connection. Allowed: "grafana", "powerbi", "tableau", "web"
name (required, string)minLength: 1 maxLength: 80
url (optional, string)

A /d/{uid}/... dashboard address on the connection's host. The server reads orgId, viewPanel (N or panel-N) or panelId, from, to, var-* and theme from it. Tableau: a view address on the connection's host (/views/W/V, /t/SITE/views/W/V, #/site/SITE/views/W/V) or Workbook/View. Web: the page's https address on a public host. maxLength: 2048

target (optional, BITarget)

What a view shows. Grafana with a connection: dashboard_uid (and optionally one panel). Power BI with a connection: workspace_id and report_id, with pages or rotate_all_pages. Tableau with a connection: view (Workbook/View), with rotate_sheets. Web with a connection: url. Without a connection: only public_url (and rotate_sheets for Tableau).

refresh_s (optional, integer)Grafana 30 to 86400; Power BI and Tableau 0 or 60 to 86400; web 60 to 86400. default: 300 minimum: 0 maximum: 86400
rotate_s (optional, integer)Power BI and Tableau: 0 or 10 to 3600; required for a target that rotates pages or sheets. default: 0 minimum: 0 maximum: 3600
fit (optional, string)Allowed: "contain", "cover", "fill" default: "contain"
wait_for (optional, string)Web: a CSS selector of an element that shows when the page is ready, and only when it is signed in. maxLength: 512
wait_ms (optional, integer)Web: milliseconds to wait after the page is ready. minimum: 0 maximum: 10000
clip (optional, string)Web: a CSS selector of the part of the page to draw. maxLength: 512
Request template and responses
shell · request template
curl --request POST --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --header 'Content-Type: application/json' --data '@request.json' 'https://api.screenrig.ai/api/projects/PROJECT_ID/bi-views'

Responses

StatusMeaningBody and headers
201Created.BIView (application/json); headers: ETag, Cache-Control
400invalid_request, including a url that is not a dashboard address of the connection.Problem (application/problem+json)
402feature_not_in_plan — the project's plan does not include BI dashboards; required_plan names the plan that does.Problem (application/problem+json)
404not_found, the connection is not in this project.Problem (application/problem+json)
409idempotency_mismatch.Problem (application/problem+json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/projects/{project_id}/triggers

List Triggers In Project

Lists the project's CAP alert triggers, oldest first (at most 20), each with its ingest url, username and latest alert. The password is never returned here.

Authentication
projectBearer
Request body
none
Operation ID
listTriggersInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' 'https://api.screenrig.ai/api/projects/PROJECT_ID/triggers'

Responses

StatusMeaningBody and headers
200The project's triggers.TriggerList (application/json); headers: Cache-Control
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
POST/api/projects/{project_id}/triggers

Create Trigger In Project

Creates a CAP alert trigger: one inbound URL an emergency notification system (Everbridge, Rave, Alertus, IPAWS relays and other CAP 1.2 senders) posts alerts to, with HTTP Basic credentials.

The answer is the only place the password appears (with the rotate answer): store it in the sending system at once. target is a tag (every active screen with it when the alert arrives) or up to 500 screen_ids.

An alert takes every target screen with a default playlist over until the alert's <expires>, else for default_for_seconds (60 to 604800, default 3600); see POST /api/triggers/{id}/cap. An organization has at most 20 triggers across its projects (trigger_limit_reached). Appends trigger.created.

An exact retry with the same Idempotency-Key returns this same answer, password included, for twenty-four hours. A trigger whose selector reaches a protected screen is protected_target (409), and a failed read of screen protection is dependency_unavailable (500, retry the same request); a trigger is not available to a caller limited to screens.

Authentication
projectBearer
Request body
TriggerWrite
Operation ID
createTriggerInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
Idempotency-KeyheaderoptionalOmit for a fresh operation. Supply and reuse a key to deduplicate retries; the CLI manages keys automatically.

Request body fields

FieldDescription
kind (optional, string)Allowed: "cap", "overlay" default: "cap"
label (required, string)minLength: 1 maxLength: 80
target (required, TriggerTarget)Exactly one of tag and screen_ids.
default_for_seconds (optional, integer)

How long an alert without <expires> holds the screens: 60 to 604800, default 3600, for a CAP trigger; how long a post without duration holds its alert: 10 to 604800, default 600, for an overlay trigger. minimum: 10 maximum: 604800

pull (optional, CapPull)

CAP sources the platform reads for the trigger, with where the target screens are and which alerts count: the params of a cap-alert card placement (docs/feeds.md "CAP alerts"). Each source URL is fetched once per minute for every trigger and placement that names it.

With no sources the platform's public feeds covering location are read (NWS, Canada NAAD, and MeteoAlarm for a location with area codes). The most severe matching alert takes the target screens over exactly as a pushed message would; when the sources show none (a cancel or an expiry) a pulled alert ends.

A stale or failing source never ends an alert. location is required unless sources are given.

overlay (optional, TriggerOverlayWrite)
Request template and responses
shell · request template
curl --request POST --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --header 'Content-Type: application/json' --data '@request.json' 'https://api.screenrig.ai/api/projects/PROJECT_ID/triggers'

Responses

StatusMeaningBody and headers
201Created, with its url, username and password.TriggerWithPassword (application/json); headers: ETag, Cache-Control
400invalid_request, including a malformed tag or both tag and screen_ids.Problem (application/problem+json)
409trigger_limit_reached, idempotency_mismatch, or protected_target when the selector reaches a screen in a protected screen folder.Problem (application/problem+json)
500dependency_unavailable - the check for protected screen folders could not run; send the same request again after a short wait.Problem (application/problem+json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/projects/{project_id}/events

List Events In Project

Lists durable project events ascending by sequence.

Paging is contiguous: pass the returned next_cursor as after to continue exactly where the page stopped. next_cursor is the cursor of the last returned event while newer events already exist, and null at the end of the history. limit defaults to 50 and accepts 1-200; a value outside that range is refused with invalid_request and an errors[] member naming limit.

Offset paging is not supported. source=log lists the Player log instead: the condition reports Players send (runtime.reported) ascending by receipt time, filtered by screen_id and severity over a window from to (default the last 24 hours, at most 31 days).

Its cursors are opaque: lg1_ or ev1_ by where the server keeps the Player log, so pass back the one a page returned; a cursor of the other kind is refused with invalid_request naming the field. Player log records have no sequence, are not on GET /stream/project and are not delivered to webhooks.

A record is acknowledged when the Player log queue accepts it and is kept for the project's event retention. A poll with the last cursor and the default window follows the log. Player log records are not in the default (source=project) list. from and to are refused with invalid_request unless source is log.

The project list takes screen_id, playlist_id and application_id to read the events of one screen, playlist or application, all scoped to the project of the credential (an id names which events to read, never whose): screen_id keeps the events whose resource is that screen; playlist_id the events whose resource is that playlist plus the events that name it as details.playlist_id (a screen taking it); application_id the events whose resource is that application plus those whose resource carries it as application_id (its releases and key/value entries).

A value that is not an id of its kind is refused with invalid_request naming the field; playlist_id and application_id are refused with source=log, whose records belong to a screen only.

Both sources take resource_id, type and severity (a minimum), combined with each other, with the id filters and with paging; a Player log record is a runtime.reported record whose resource is its screen, so a resource_id that is not that screen or a type that excludes runtime.reported answers an empty page. before (or order=desc) pages newest first: next_cursor is then the cursor of the oldest returned item and passed back as before continues to older items.

Without from, a newest-first source=log page reaches past the default 24 hours to the oldest record the project's event retention keeps, at most 31 days below the page's upper edge per request. A newest-first source=log page may hold fewer than limit records, even none, with a next_cursor; null still ends it, at the end of the retained log.

A caller limited to screens (docs/screen-scope.md) reads a filtered feed: events of screens inside its scope, of the screen folders it can see (its own, the folders above and inside; screen.moved only when the destination is inside its scope), of campaigns, playlists, media, applications and cards, and playlist_change reviews.

Every other event is left out, so a page can hold fewer events than limit, even none, with a next_cursor; keep paging with it. source=log needs a screen_id inside its scope. Events about the project itself are not sent.

Authentication
projectBearer
Request body
none
Operation ID
listEventsInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
afterqueryoptional

A cursor from a previous response: ev1_ for project events (and the event streams). The Player log (source=log) pages with lg1_ or ev1_ cursors by where the server keeps it; treat them as opaque and pass back the one a page returned. A cursor of another kind is refused with invalid_request.

beforequeryoptional

Pages newest first, strictly older than this cursor: a next_cursor of a newest-first page, or any item cursor (ev1_ for project events; for source=log the opaque cursor its items carry). Empty or absent with order=desc starts at the newest item.

orderqueryoptionalasc pages oldest first with after; desc pages newest first with before. before implies desc; order=asc with before is refused.
limitqueryoptionalPage size. A value outside 1-200 is refused with invalid_request and an errors[] member whose field is limit.
sourcequeryoptionalproject lists the sequenced project events. log lists the Player log: Player condition reports (runtime.reported), ascending by receipt time.
resource_idqueryoptionalOnly items whose resource.id is this id (a screen, playlist, media, webhook, agent or application id). With source=log it is the screen of the record.
typequeryoptionalAn exact event type such as playlist.updated, or a family prefix ending in a dot such as playlist. for every playlist.* type.
screen_idqueryoptionalOnly the events of this screen: with source=project those whose resource is the screen, with source=log its Player log records. Another id kind is refused with invalid_request.
playlist_idqueryoptionalWith source=project, only the events of this playlist: those whose resource is the playlist and those naming it as details.playlist_id. Refused with source=log.
application_idqueryoptional

With source=project, only the events of this application: those whose resource is the application and those whose resource carries it as application_id (its releases and key/value entries). Refused with source=log.

severityqueryoptionalMinimum severity: info is every item, warning keeps warnings and errors, error keeps errors. Both sources.
fromqueryoptionalWith source=log, the start of the window (inclusive). Defaults to 24 hours before to; a newest-first page without from reaches back to the project's event retention instead.
toqueryoptionalWith source=log, the end of the window (exclusive). Defaults to now. The window is at most 31 days.
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' 'https://api.screenrig.ai/api/projects/PROJECT_ID/events'

Responses

StatusMeaningBody and headers
200Durable events (source=project) or Player log records (source=log)EventList (application/json)
403

outside_screen_scope - the caller is limited to screens and the screen, screen folder, selector or audience the request names or reaches is outside them (docs/screen-scope.md). An id outside the scope and an id that does not exist get the same answer; errors[0].screen_scope carries the caller's scope, and the write is refused whole, never narrowed.

Problem (application/problem+json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/projects/{project_id}/project/capabilities

Get Project Capabilities In Project

The calling project's plan, independent advertiser/screens flags with their revision, the derived effective capability set, the plan features it has (plan_features) and its limits (limits). Never reflects a client claim; an unknown plan fails closed as forbidden.

Authentication
projectBearer
Request body
none
Operation ID
getProjectCapabilitiesInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' 'https://api.screenrig.ai/api/projects/PROJECT_ID/project/capabilities'

Responses

StatusMeaningBody and headers
200Project capabilities.ProjectCapabilities (application/json); headers: Cache-Control
403forbidden - the project plan is not in the catalog.Problem (application/problem+json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/projects/{project_id}/billing/balance

Get Billing Balance In Project

The calling project's source-aware balance snapshot. All millicredit amounts are canonical decimal strings. It is a snapshot, not authority to pay; rails_available is false while card, tax and cash-out rail are unavailable.

Authentication
projectBearer
Request body
none
Operation ID
getBillingBalanceInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' 'https://api.screenrig.ai/api/projects/PROJECT_ID/billing/balance'

Responses

StatusMeaningBody and headers
200Balance snapshot.BillingBalance (application/json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/projects/{project_id}/billing/statement

Get Billing Statement In Project

Stable cursor pagination over immutable posted journal entries for the calling project. Holds are not posted entries. Corrections link to the original event instead of rewriting it. There is no arbitrary grant or payout mutation on this surface.

Authentication
projectBearer
Request body
none
Operation ID
getBillingStatementInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
cursorqueryoptional
limitqueryoptional
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' 'https://api.screenrig.ai/api/projects/PROJECT_ID/billing/statement'

Responses

StatusMeaningBody and headers
200Statement page.BillingStatement (application/json)
400invalid_request - limit is out of range.Problem (application/problem+json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/projects/{project_id}/billing/usage

Get Billing Usage In Project

The calling project's use for one UTC month, with the bytes served and received (never charged), the storage charged above the free storage of the payer's plan (allowance.storage_bytes), and the API requests, billed project stream events and webhook delivery attempts counted against the free 10,000 a month. A project paying for itself reads its own pool.

A project another payer pays for shares that payer's pool with the payer's other projects; it reads its own share, and payer names the payer. The payer's pool total stays on the payer's billing reads.

Authentication
projectBearer
Request body
none
Operation ID
getBillingUsageInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
periodqueryoptionalUTC month in YYYY-MM form; defaults to the current month.
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' 'https://api.screenrig.ai/api/projects/PROJECT_ID/billing/usage'

Responses

StatusMeaningBody and headers
200Project usage.ProjectBillingUsage (application/json); headers: Cache-Control
400invalid_request - period is not a UTC month in YYYY-MM form.Problem (application/problem+json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/projects/{project_id}/advertising/network

Get Advertising Network In Project

The calling seller's one network, including its resolved ScreenRig serving fee. Sellers cannot change that fee.

Authentication
projectBearer
Request body
none
Operation ID
getAdvertisingNetworkInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' 'https://api.screenrig.ai/api/projects/PROJECT_ID/advertising/network'

Responses

StatusMeaningBody and headers
200Network.AdvertisingNetwork (application/json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
POST/api/projects/{project_id}/advertising/network

Create Advertising Network In Project

Creates the calling seller's one network if absent. Requires screens=true. Idempotent; repeating returns the same network.

Authentication
projectBearer
Request body
AdvertisingNetworkCreate
Operation ID
createAdvertisingNetworkInProject

Parameters

NameSend inRequired?Description
project_idpathrequired

Request body fields

FieldDescription
name (required, string)maxLength: 120
Request template and responses
shell · request template
curl --request POST --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --header 'Content-Type: application/json' --data '@request.json' 'https://api.screenrig.ai/api/projects/PROJECT_ID/advertising/network'

Responses

StatusMeaningBody and headers
200Network.AdvertisingNetwork (application/json)
403forbidden - the project lacks screen capability or has an unknown plan.Problem (application/problem+json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
POST/api/projects/{project_id}/advertising/network/rate

Set Advertising Default Rate In Project

Sets the seller's project default rate per 15 seconds of completed playback. A change that alters an accepted campaign's effective rate pauses that whole campaign with price_change_pending; a masked or no-op change does not. If-Match carries the network revision.

Authentication
projectBearer
Request body
AdvertisingRate
Operation ID
setAdvertisingDefaultRateInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
If-MatchheaderoptionalOptional positive resource revision. Omit to write the current resource; a supplied stale revision is revision_conflict.

Request body fields

FieldDescription
rate_mcr_per_15s (required, McrString)Exact integer millicredit amount as a canonical decimal string. 1 credit is 1000 mcr. pattern: "^-?[0-9]+$"
Request template and responses
shell · request template
curl --request POST --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --header 'Content-Type: application/json' --data '@request.json' 'https://api.screenrig.ai/api/projects/PROJECT_ID/advertising/network/rate'

Responses

StatusMeaningBody and headers
200Updated network.AdvertisingNetwork (application/json)
412revision_conflict - If-Match is stale.Problem (application/problem+json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/projects/{project_id}/advertising/inventory

List Advertising Inventory In Project

The calling seller's opted-in inventory.

Authentication
projectBearer
Request body
none
Operation ID
listAdvertisingInventoryInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' 'https://api.screenrig.ai/api/projects/PROJECT_ID/advertising/inventory'

Responses

StatusMeaningBody and headers
200Inventory.AdvertisingInventoryList (application/json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/projects/{project_id}/advertising/slots

List Advertising Slots In Project

Authentication
projectBearer
Request body
none
Operation ID
listAdvertisingSlotsInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' 'https://api.screenrig.ai/api/projects/PROJECT_ID/advertising/slots'

Responses

StatusMeaningBody and headers
200Slots.AdvertisingSlotList (application/json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
POST/api/projects/{project_id}/advertising/slots

Create Advertising Slot In Project

Creates a reusable seller slot. Images are 5-30 seconds and videos at most the platform ceiling of 120 seconds. Ads are always muted.

Authentication
projectBearer
Request body
AdvertisingSlotWrite
Operation ID
createAdvertisingSlotInProject

Parameters

NameSend inRequired?Description
project_idpathrequired

Request body fields

FieldDescription
name (required, string)minLength: 1 maxLength: 120
enabled (optional, boolean)
accepted_media (required, array)
max_image_duration_ms (required, integer)minimum: 5000 maximum: 30000
max_video_duration_ms (required, integer)minimum: 1000 maximum: 120000
rate_override_mcr_per_15s (optional, inline)
vast_tag_url (optional, inline)

The seller's own VAST 2-4 ad tag, tried when no invited campaign fills this slot on the seller's own screens. HTTPS on port 443 or 8443 to a public host only.

The backend fetches it, follows up to five Wrappers, ingests the chosen progressive MP4 or WebM MediaFile into the project's media, and fires Impression, creativeView and start on an accepted start, complete on an accepted completion, and Error on failure. Quartile trackers are not fired.

Macros [CACHEBUSTING], [TIMESTAMP], [SCREENRIG_SCREEN_ID], [SCREENRIG_SLOT_ID] and [SCREENRIG_PAGE_ID] are expanded. The slot must accept video. Null, absent, or empty clears the tag. Buyers never see it.

Request template and responses
shell · request template
curl --request POST --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --header 'Content-Type: application/json' --data '@request.json' 'https://api.screenrig.ai/api/projects/PROJECT_ID/advertising/slots'

Responses

StatusMeaningBody and headers
201Slotslot.AdvertisingSlot (application/json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/projects/{project_id}/advertising/memberships

List Advertising Memberships In Project

Authentication
projectBearer
Request body
none
Operation ID
listAdvertisingMembershipsInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' 'https://api.screenrig.ai/api/projects/PROJECT_ID/advertising/memberships'

Responses

StatusMeaningBody and headers
200Memberships.AdvertisingMembershipList (application/json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/projects/{project_id}/advertising/networks

List Advertising Joined Networks In Project

Networks the calling advertiser currently belongs to, with the scope and review policy it was granted. Screen count is not a guaranteed impression count.

Authentication
projectBearer
Request body
none
Operation ID
listAdvertisingJoinedNetworksInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' 'https://api.screenrig.ai/api/projects/PROJECT_ID/advertising/networks'

Responses

StatusMeaningBody and headers
200Joined networks.AdvertisingJoinedNetworkList (application/json)
403forbidden - the project lacks the advertiser flag.Problem (application/problem+json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/projects/{project_id}/advertising/creatives

List Advertising Creatives In Project

Authentication
projectBearer
Request body
none
Operation ID
listAdvertisingCreativesInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' 'https://api.screenrig.ai/api/projects/PROJECT_ID/advertising/creatives'

Responses

StatusMeaningBody and headers
200Creatives.AdvertisingCreativeList (application/json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
POST/api/projects/{project_id}/advertising/creatives

Create Advertising Creative In Project

Binds one ready owned media revision to an immutable creative. Does not copy bytes, re-upload, or re-charge generation. Unknown or non-ready media is rejected.

Authentication
projectBearer
Request body
AdvertisingCreativeCreate
Operation ID
createAdvertisingCreativeInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
Idempotency-KeyheaderoptionalOmit for a fresh operation. Supply and reuse a key to deduplicate retries; the CLI manages keys automatically.

Request body fields

FieldDescription
media_id (required, string)
copy (optional, string)maxLength: 500
Request template and responses
shell · request template
curl --request POST --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --header 'Content-Type: application/json' --data '@request.json' 'https://api.screenrig.ai/api/projects/PROJECT_ID/advertising/creatives'

Responses

StatusMeaningBody and headers
201Creative.AdvertisingCreative (application/json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/projects/{project_id}/advertising/campaigns

List Advertising Campaigns In Project

Authentication
projectBearer
Request body
none
Operation ID
listAdvertisingCampaignsInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' 'https://api.screenrig.ai/api/projects/PROJECT_ID/advertising/campaigns'

Responses

StatusMeaningBody and headers
200Campaigns.AdvertisingCampaignList (application/json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
POST/api/projects/{project_id}/advertising/campaigns

Create Advertising Campaign In Project

Creates a draft campaign. Drafts hold no money, reserve nothing, and authorize no delivery. Activation requires an explicitly accepted quote.

Authentication
projectBearer
Request body
AdvertisingCampaignDraft
Operation ID
createAdvertisingCampaignInProject

Parameters

NameSend inRequired?Description
project_idpathrequired

Request body fields

FieldDescription
name (required, string)minLength: 1 maxLength: 120
category (optional, AdvertisingCategory)

The advertiser category. Two ads of one category never play in the same ad break on a screen; an ad without a category is never separated.

Allowed: "alcohol", "apparel", "automotive", "beauty", "cannabis", "consumer_electronics", "education", "entertainment", "financial_services", "food_and_beverage", "gambling", "government", "grocery", "health_and_pharma", "home_and_garden", "insurance", "jobs", "legal", "media", "political", "quick_service_restaurants", "real_estate", "restaurants", "retail", "sports_and_fitness", "technology", "telecom", "tobacco_and_vaping", "travel", "utilities"

daily_cap_mcr (required, McrString)Exact integer millicredit amount as a canonical decimal string. 1 credit is 1000 mcr. pattern: "^-?[0-9]+$"
lifetime_cap_mcr (required, McrString)Exact integer millicredit amount as a canonical decimal string. 1 credit is 1000 mcr. pattern: "^-?[0-9]+$"
image_duration_ms (optional, integer)Campaign-wide image dwell time. Videos keep their server-verified duration. default: 10000 minimum: 5000 maximum: 30000
max_play_price_mcr (optional, inline)Positive maximum completed-play price. Omit for no additional ceiling.
flight_start (required, string)format: "date-time"
flight_end (required, string)format: "date-time"
networks (required, array)
Request template and responses
shell · request template
curl --request POST --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --header 'Content-Type: application/json' --data '@request.json' 'https://api.screenrig.ai/api/projects/PROJECT_ID/advertising/campaigns'

Responses

StatusMeaningBody and headers
201Draft campaign.AdvertisingCampaign (application/json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/projects/{project_id}/advertising/reviews

List Advertising Reviews In Project

Creative versions submitted to the calling seller for review. A seller sees only exact submitted creative, never the buyer's library.

Authentication
projectBearer
Request body
none
Operation ID
listAdvertisingReviewsInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' 'https://api.screenrig.ai/api/projects/PROJECT_ID/advertising/reviews'

Responses

StatusMeaningBody and headers
200Reviews.AdvertisingReviewList (application/json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/projects/{project_id}/advertising/reports/spend

Get Advertising Spend In Project

Buyer-scoped spend and delivery counts for one campaign. Amounts are decimal mcr strings. It never exposes the seller's income, bank status, or project-wide usage.

Authentication
projectBearer
Request body
none
Operation ID
getAdvertisingSpendInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
formatqueryoptionaljson (default) returns the report as JSON. csv, xlsx and pdf return the same rows as a file attachment (every page of a paged report, up to 50000 rows).
campaign_idqueryrequired
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' 'https://api.screenrig.ai/api/projects/PROJECT_ID/advertising/reports/spend?campaign_id=CAMPAIGN_ID'

Responses

StatusMeaningBody and headers
200Spend report.AdvertisingSpendReport (application/json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/projects/{project_id}/advertising/reports/delivery

Get Advertising Delivery In Project

Seller-scoped gross, serving fee and net for one window, with its own delivery evidence. It never exposes the buyer's wallet or other networks. Only authorized completed-play evidence establishes billable delivery. The window is at most 92 days; a wider window is invalid_request.

When it holds more than 5000 settlements the response sets truncated, totals and counts still cover all of them and rows lists only the earliest 5000.

Authentication
projectBearer
Request body
none
Operation ID
getAdvertisingDeliveryInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
formatqueryoptionaljson (default) returns the report as JSON. csv, xlsx and pdf return the same rows as a file attachment (every page of a paged report, up to 50000 rows).
fromqueryrequired
toqueryrequired
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' 'https://api.screenrig.ai/api/projects/PROJECT_ID/advertising/reports/delivery?from=FROM&to=TO'

Responses

StatusMeaningBody and headers
200Delivery report.AdvertisingDeliveryReport (application/json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/projects/{project_id}/playback

List Playback Aggregates In Project

Daily playback aggregates.

JSON returns at most 200 rows and is not rate limited. format=csv (or Accept text/csv without application/json) streams every matching row inside day_from to day_to (inclusive UTC days; defaults day_to today and day_from 30 days earlier; at most 366 days, else invalid_request) as CSV with a fixed header row (PlaybackAggregateCsv); only the CSV form spends the playback-export-org (30 per minute) and playback-export-ip (60 per minute) budgets.

Either form is one metered API request. Responses carry Vary Accept. A caller limited to screens (docs/screen-scope.md) must send screen_id and it must be a screen inside its scope (outside_screen_scope otherwise); the CSV forms follow the same rule.

Authentication
projectBearer
Request body
none
Operation ID
listPlaybackAggregatesInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
screen_idqueryoptional
media_idqueryoptional
dayqueryoptionalUTC calendar day of the aggregate.
day_fromqueryoptionalFirst UTC day, inclusive. Excludes day. With day_to spans at most 366 days. CSV defaults it to 30 days before day_to.
day_toqueryoptionalLast UTC day, inclusive. Excludes day. CSV defaults it to today (UTC).
formatqueryoptionaljson (default), csv, xlsx or pdf. Omitted, an Accept header naming text/csv but not application/json selects csv. xlsx and pdf write the first 50000 rows of the same list.
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' 'https://api.screenrig.ai/api/projects/PROJECT_ID/playback'

Responses

StatusMeaningBody and headers
200

Daily playback aggregates for the calling project, images and videos alike. One row per screen, media, and UTC day. Newest days first. Identifiers filter the caller's own rows and are never a cross-project lookup.

PlaybackAggregateList (application/json), PlaybackAggregateCsv (text/csv); headers: Vary, RateLimit-Policy, RateLimit
400

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
429

Stable rate_limited problem. Retry only after the authoritative Retry-After interval. Fixed-window denials also include the applicable RateLimit-Policy and RateLimit members; concurrency and byte-budget denials omit those optional disclosures.

Problem (application/problem+json); headers: Retry-After, RateLimit-Policy, RateLimit
403

outside_screen_scope - the caller is limited to screens and the screen, screen folder, selector or audience the request names or reaches is outside them (docs/screen-scope.md). An id outside the scope and an id that does not exist get the same answer; errors[0].screen_scope carries the caller's scope, and the write is refused whole, never narrowed.

Problem (application/problem+json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/projects/{project_id}/playback/plays

List Playback Plays In Project

Per-play records: one row per accepted playback.media_started (or legacy playback.video_started) and one row per accepted playback.application_started (release_id set, media fields empty) of the calling project, oldest first by received_at, ties by insertion. from (inclusive) and to (exclusive) bound received_at; to defaults to now, from to 24 hours before to, and the range is at most 31 days (invalid_request otherwise).

The newest 5 seconds are not returned yet: the effective to is at most now minus 5 seconds (settle lag), so a live tail never skips a row that commits behind its cursor. screen_id, media_id, playlist_id (the playlist the start was shown from), and tag (a screen tag the screen carried when the play was received) filter.

A playlist_id page may hold fewer than limit rows, even none, with a next_cursor when a long stretch of plays of other playlists was scanned; null still ends the range.

JSON is a page of at most limit rows (default 200, at most 1000) with next_cursor, null at the end of the range; pass it back as cursor with the same filters. order=desc (or before) pages newest first within the same range: next_cursor is then the cursor of the oldest returned row, null at the start of the range, and is passed back as before (exclusive) with the same filters; order=asc with before is refused with invalid_request naming order, and cursor with a newest-first page naming cursor.

A newest-first page may hold fewer than limit rows, even none, with a next_cursor; null still ends it.

A later page never skips a row that existed when the earlier page was read and does not repeat one, except that a start the Player re-sent after an unacknowledged report (the same play_id, received a moment later) can appear again on a later page; the CSV stream lists it once. format=csv (or Accept text/csv without application/json) streams every play from cursor to the end of the range as CSV (PlaybackPlayCsv), newest first below before with order=desc; limit is refused with CSV.

Metering is per request: every JSON page costs one API request credit, while one CSV stream of the whole range costs one. Every plays request (page or stream) spends the playback-export-org (30 per minute) and playback-export-ip (60 per minute) budgets.

A stream bounds each write (15 seconds) and ends when the client disconnects; if it fails after the 200 header the connection is aborted, so an export that reads to a clean end is complete. Responses carry Vary Accept. Plays are kept for the plan's event retention (30 days is the shipped floor; plan-based retention uses the plan's own 7- or 90-day window).

A caller limited to screens (docs/screen-scope.md) must send screen_id and it must be a screen inside its scope (outside_screen_scope otherwise); the CSV forms follow the same rule.

Authentication
projectBearer
Request body
none
Operation ID
listPlaybackPlaysInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
fromqueryoptionalInclusive lower bound on received_at. Defaults to 24 hours before to.
toqueryoptionalExclusive upper bound on received_at. Defaults to now. to - from is at most 31 days.
screen_idqueryoptional
media_idqueryoptional
playlist_idqueryoptionalOnly plays shown from this playlist.
tagqueryoptionalA screen tag the screen carried when the play was received.
cursorqueryoptionalnext_cursor of the previous page, with the same filters. Opaque.
orderqueryoptionalasc pages oldest first with cursor; desc pages newest first with before. before implies desc; order=asc with before is refused.
beforequeryoptionalPages newest first, strictly older than this position: the next_cursor of a newest-first page, with the same filters. Opaque.
limitqueryoptionalJSON page size. Refused with CSV.
formatqueryoptionaljson (default), csv, xlsx or pdf. Omitted, an Accept header naming text/csv but not application/json selects csv. xlsx and pdf write the first 50000 rows of the same list.
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' 'https://api.screenrig.ai/api/projects/PROJECT_ID/playback/plays'

Responses

StatusMeaningBody and headers
200A page of plays, or the CSV stream.PlaybackPlayList (application/json), PlaybackPlayCsv (text/csv); headers: Cache-Control, Vary, RateLimit-Policy, RateLimit
400

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
401

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
429

Stable rate_limited problem. Retry only after the authoritative Retry-After interval. Fixed-window denials also include the applicable RateLimit-Policy and RateLimit members; concurrency and byte-budget denials omit those optional disclosures.

Problem (application/problem+json); headers: Retry-After, RateLimit-Policy, RateLimit
403

outside_screen_scope - the caller is limited to screens and the screen, screen folder, selector or audience the request names or reaches is outside them (docs/screen-scope.md). An id outside the scope and an id that does not exist get the same answer; errors[0].screen_scope carries the caller's scope, and the write is refused whole, never narrowed.

Problem (application/problem+json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/projects/{project_id}/playback/totals

Get Playback Totals In Project

Play totals of the calling project over inclusive UTC days, read from the daily rollups: by=day returns one row per day with plays (screen_id or media_id narrows it to one screen or media), by=screen and by=media rank the busiest screens or media (top, at most 100), and by=screen_day returns the day series of the top screens (top at most 10). day_to defaults to today (UTC) and day_from to 29 days before it.

A day series spans at most 366 days (92 when narrowed to a screen or media); a ranking at most 92. Counts include every start the project has recorded, including those stored before play rollups existed.

Rollups follow ingestion by up to about 21 minutes. truncated is true when a ranking was built from slices of a window too large for one read: it covers the best keys of each slice. Not rate limited. One metered API request.

A caller limited to screens (docs/screen-scope.md) must send screen_id and it must be a screen inside its scope (outside_screen_scope otherwise); the CSV forms follow the same rule.

Authentication
projectBearer
Request body
none
Operation ID
getPlaybackTotalsInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
formatqueryoptionaljson (default) returns the report as JSON. csv, xlsx and pdf return the same rows as a file attachment (every page of a paged report, up to 50000 rows).
byqueryoptionalday: plays per day; screen, media: the busiest keys; screen_day: the day series of the top screens.
day_fromqueryoptionalFirst UTC day, inclusive. Defaults to 29 days before day_to. A day series spans at most 366 days (92 when narrowed to a screen or media), a ranking at most 92.
day_toqueryoptionalLast UTC day, inclusive. Defaults to today (UTC).
screen_idqueryoptional
media_idqueryoptional
topqueryoptionalHow many screens or media a ranking returns (at most 10 for by=screen_day). Refused with by=day.
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' 'https://api.screenrig.ai/api/projects/PROJECT_ID/playback/totals'

Responses

StatusMeaningBody and headers
200Totals of the requested grouping.PlaybackTotals (application/json); headers: Cache-Control
400

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
401

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
403

outside_screen_scope - the caller is limited to screens and the screen, screen folder, selector or audience the request names or reaches is outside them (docs/screen-scope.md). An id outside the scope and an id that does not exist get the same answer; errors[0].screen_scope carries the caller's scope, and the write is refused whole, never narrowed.

Problem (application/problem+json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/projects/{project_id}/playback/completeness

Get Playback Completeness In Project

How many of the plays the screens made reached the backend, and where the missing ones were. Players number their media starts, so a start that never arrived leaves a hole in the numbering, for example when a screen stays offline past its 24 hour report queue or the queue drops reports.

Over the inclusive UTC days day_from to day_to (day_to defaults to today, UTC, and day_from to 29 days before it; the window spans at most 92 days) the answer holds measured_plays, the numbered plays that arrived; missing_plays, the numbers the Players skipped; completeness, measured_plays over their sum, null when both are 0; days, the same three figures for each day that has any, oldest first, a hole counted on the UTC day of the play after it; and gaps, the holes newest first, each with its screen_id, its day, from and to (the start times of the plays on either side of it) and missing_plays. screen_id narrows days and gaps to one screen; limit (default 100, at most 500) caps gaps, and truncated is true when more exist.

A switched-off screen makes no plays and leaves no gap. Plays without a number (older Players, starts stored before play numbers) are not measured: they are in play_count of GET /api/playback/totals and in none of these figures. Not rate limited. One metered API request.

A caller limited to screens (docs/screen-scope.md) must send screen_id and it must be a screen inside its scope (outside_screen_scope otherwise); the CSV forms follow the same rule.

Authentication
projectBearer
Request body
none
Operation ID
getPlaybackCompletenessInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
formatqueryoptionaljson (default) returns the report as JSON. csv, xlsx and pdf return the same rows as a file attachment (every page of a paged report, up to 50000 rows).
day_fromqueryoptionalFirst UTC day, inclusive. Defaults to 29 days before day_to. With day_to spans at most 92 days.
day_toqueryoptionalLast UTC day, inclusive. Defaults to today (UTC).
screen_idqueryoptional
limitqueryoptionalThe most gaps to list, newest first.
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' 'https://api.screenrig.ai/api/projects/PROJECT_ID/playback/completeness'

Responses

StatusMeaningBody and headers
200The completeness of the window and its gaps.PlaybackCompleteness (application/json); headers: Cache-Control
400

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
401

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
403

outside_screen_scope - the caller is limited to screens and the screen, screen folder, selector or audience the request names or reaches is outside them (docs/screen-scope.md). An id outside the scope and an id that does not exist get the same answer; errors[0].screen_scope carries the caller's scope, and the write is refused whole, never narrowed.

Problem (application/problem+json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/projects/{project_id}/health/trend

Get Health Trend In Project

The project's fleet health by UTC hour: how many screens reported, and how many of them were hot (at or above 80 °C), had a disconnected display, or were crashing (3 or more crashes in 24 hours). from (inclusive) and to (exclusive) default to the last 24 hours, at most 93 days; a page holds at most limit rows (default 100, at most 500) with next_cursor, null at the end.

Hours follow reports by up to about 5 minutes. Refused to a caller limited to screens (outside_screen_scope); GET /api/screens/{id}/health/history is the per-screen form.

Authentication
projectBearer
Request body
none
Operation ID
getHealthTrendInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
formatqueryoptionaljson (default) returns the report as JSON. csv, xlsx and pdf return the same rows as a file attachment (every page of a paged report, up to 50000 rows).
fromqueryoptionalInclusive lower bound on the report time. Defaults to 24 hours before to.
toqueryoptionalExclusive upper bound on the report time. Defaults to now.
limitqueryoptionalPage size.
cursorqueryoptionalnext_cursor of the previous page, with the same filters. Opaque.
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' 'https://api.screenrig.ai/api/projects/PROJECT_ID/health/trend'

Responses

StatusMeaningBody and headers
200A page of hourly fleet health.HealthTrend (application/json); headers: Cache-Control
400

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
401

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
403

outside_screen_scope - the caller is limited to screens and the screen, screen folder, selector or audience the request names or reaches is outside them (docs/screen-scope.md). An id outside the scope and an id that does not exist get the same answer; errors[0].screen_scope carries the caller's scope, and the write is refused whole, never narrowed.

Problem (application/problem+json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/projects/{project_id}/uptime/daily

Get Project Uptime In Project

Daily availability of the project's screens over inclusive UTC days (defaults and range as GET /api/screens/{id}/uptime). Each row sums the online and offline seconds of the screens with a recorded state that day; coverage is the share of those screens' day with a recorded state.

Intervals count when they end, so today's row covers intervals that ended so far; the live online count is in the dashboard summary. Refused to a caller limited to screens (outside_screen_scope); GET /api/screens/{id}/uptime is the per-screen form.

Authentication
projectBearer
Request body
none
Operation ID
getProjectUptimeInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
formatqueryoptionaljson (default) returns the report as JSON. csv, xlsx and pdf return the same rows as a file attachment (every page of a paged report, up to 50000 rows).
day_fromqueryoptionalFirst UTC day, inclusive. Defaults to 29 days before day_to. With day_to spans at most 366 days.
day_toqueryoptionalLast UTC day, inclusive. Defaults to today (UTC).
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' 'https://api.screenrig.ai/api/projects/PROJECT_ID/uptime/daily'

Responses

StatusMeaningBody and headers
200Daily uptime rows, oldest first.ProjectUptime (application/json); headers: Cache-Control
400

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
401

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
403

outside_screen_scope - the caller is limited to screens and the screen, screen folder, selector or audience the request names or reaches is outside them (docs/screen-scope.md). An id outside the scope and an id that does not exist get the same answer; errors[0].screen_scope carries the caller's scope, and the write is refused whole, never narrowed.

Problem (application/problem+json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/projects/{project_id}/card-types

List Card Types In Project

Discover built-in cards from this environment's published catalogue, merged with the vendored floor. Refreshes and schema verification happen in the background; this route never calls the edge bucket. Each entry lists its current copy, its tier and the layouts that tier allows, and every served major.

Authentication
projectBearer
Request body
none
Operation ID
listCardTypesInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' 'https://api.screenrig.ai/api/projects/PROJECT_ID/card-types'

Responses

StatusMeaningBody and headers
200Built-in card catalogue, ordered by idCardCatalogue (application/json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/projects/{project_id}/card-data

List Card Data In Project

Lists the project's card data documents, at most 200 in ascending key order. next_cursor is the last returned key; pass it back as after for the next page, null when there are no more. Card data documents hold the dynamic properties of card placements (menu sections, ticker items, KPI tiles); the placement's data key names one.

Authentication
projectBearer
Request body
none
Operation ID
listCardDataInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
afterqueryoptional
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' 'https://api.screenrig.ai/api/projects/PROJECT_ID/card-data'

Responses

StatusMeaningBody and headers
200Card data documentsCardDataList (application/json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/projects/{project_id}/media

List Media In Project

Lists ready media newest first, at most 1000 per page. folder keeps only the files directly inside one media folder (its ID), or with root only those at the library root; a well-formed folder ID that names no folder lists nothing. next_cursor is the position of the last returned row while more rows remain; pass it back as after, with the same filters, for the next page. next_cursor is null on the last page.

Authentication
projectBearer
Request body
none
Operation ID
listMediaInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
tagqueryoptionalExact media tag. Untagged objects are omitted when this filter is present.
primitivequeryoptional
folderqueryoptionalA media folder ID keeps only the files directly inside that folder, not those of its subfolders; root keeps only the files at the library root. Omitted lists every file.
idsqueryoptional

Comma-separated media ids, at most 200 distinct; more is invalid_request at ids. Keeps only those files: an id that names no ready file is absent, and the other filters and paging still apply. An empty value lists nothing.

libraryqueryoptional

true lists the organization's Library project instead of this project: its items are read-only here and carry library true. An organization with no Library, or the Library project itself, lists nothing with true.

afterqueryoptionalnext_cursor of the previous page of the same list, with the same filters. Omitted starts at the newest row. A value that is not such a cursor is invalid_request.
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' 'https://api.screenrig.ai/api/projects/PROJECT_ID/media'

Responses

StatusMeaningBody and headers
200MediaMediaList (application/json)
POST/api/projects/{project_id}/media/generations

Create Media Generation In Project

Generate one still image from a prompt, store it as ready private project media, and bill its usage. The POST answers 202 at once with the Operation, with or without Prefer: respond-async, because a proxy in front of the API drops a request that sends no byte for 100 s and a high-quality still can take longer.

Poll GET /api/operations/{id} until it is succeeded, when its result is {media_id, usage: {quality, credits, usd}} (MediaGenerationUsage), or failed, when its error is the problem. A refusal decided before any vendor work (payment_required, reseller_generation_limit, rate_limited, not_ready, invalid_request) still answers the POST.

It never includes image bytes, b64_json, object keys, signed URLs, vendor URLs, vendor cost, vendor tokens, or the deployment model name. The prompt is customer bytes and is not echoed.

Before the prompt reaches the image vendor the server appends fixed framing requirements to it: the artwork must fill the frame edge to edge, and no television, monitor, screen, display, bezel, frame, border, mounting, stand, wall, room, device mockup, drop shadow, or photograph of an installed sign may be depicted, and any wording in the caller's prompt describing where the sign will hang or what device will show it is treated as placement metadata rather than subject matter.

Decorative rules and borders inside the design itself remain available. The caller's prompt is never rewritten or stripped and is stored unchanged. Idempotency-Key replays the same Operation, never a second billed attempt. Clients do not PUT or commit generated bytes.

The stored rendition is lossy WebP (quality 90) at the exact aspect size with a 1080 px short edge (16:9 is 1920x1080, 9:16 1080x1920, 1:1 1080x1080, 4:3 1440x1080, 3:4 1080x1440, 3:2 1620x1080, 2:3 1080x1620); the vendor canvas is centre-cropped and resampled to that size.

The filename is distinctive per generation, generated-16x9-1a2b3c4d.webp, with the suffix taken from the media id. Fetch the bytes with GET /api/media/{id}/content. Own-gen-then-upload remains valid.

On Standard, remaining that cannot cover twice the vendor cost of the still, rounded up to whole credits, after the intro floor (negative 1,000,000 credits until 2027-01-01, then zero) returns payment_required, except SCREENRIG__ENVIRONMENT=development, and admission before the vendor call requires remaining above that floor by the per-quality minimum: 200 credits for low, 800 for medium, 2000 for high.

Other plans are never refused for their balance.

An organization billed through a reseller is refused with reseller_generation_limit (402) once its reseller's delegated customers have been billed the month's image generation limit ($100 at list price while the reseller awaits review, $1,000 after, counted per UTC month), unless the organization's own credit covers the image; a generation already admitted finishes.

Empty selected-vendor configuration returns not_ready. Project bearer only. One in-flight generation per organization; further parallelism is rate_limited.

Authentication
projectBearer
Request body
MediaGenerationRequest
Operation ID
createMediaGenerationInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
Idempotency-Keyheaderrequired
PreferheaderoptionalOptional. The route answers 202 with the Operation at once with or without it; poll the Operation.

Request body fields

FieldDescription
prompt (required, string)minLength: 1 maxLength: 4000
aspect_ratio (optional, string)Allowed: "1:1", "16:9", "9:16", "4:3", "3:4", "3:2", "2:3" default: "16:9"
quality (optional, string)Allowed: "low", "medium", "high" default: "medium"
tag (optional, string)pattern: "^[A-Za-z0-9]{1,32}$"
references (optional, array)
Request template and responses
shell · request template
curl --request POST --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --header 'Idempotency-Key: REQUEST_ID' --header 'Content-Type: application/json' --data '@request.json' 'https://api.screenrig.ai/api/projects/PROJECT_ID/media/generations'

Responses

StatusMeaningBody and headers
202

The generation was accepted and runs on; poll GET /api/operations/{id} until the Operation is succeeded (result media_id and usage) or failed (error). The same Idempotency-Key answers with the same Operation.

Operation (application/json); headers: Preference-Applied, RateLimit-Policy, RateLimit
402

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
404

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
500

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/projects/{project_id}/media-folders

List Media Folders In Project

Lists every media folder in the project, at most 1000, ordered by name. Folders organize the media library, and a playlist selector by:folder plays the files directly inside one folder. A folder's parent_id is null at the library root.

Build the tree from parent_id; a file's folder is Media.folder_id. library=true lists the organization Library's folders instead (read-only; a by:folder selector may name one).

Authentication
projectBearer
Request body
none
Operation ID
listMediaFoldersInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
libraryqueryoptional

true lists the organization's Library project instead of this project: its items are read-only here and carry library true. An organization with no Library, or the Library project itself, lists nothing with true.

Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' 'https://api.screenrig.ai/api/projects/PROJECT_ID/media-folders'

Responses

StatusMeaningBody and headers
200Media foldersMediaFolderList (application/json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
POST/api/projects/{project_id}/media-folders

Create Media Folder In Project

Creates one media folder at the library root (parent_id null or absent) or inside parent_id. Names are trimmed, hold 1 to 100 Unicode characters with no controls, are not "." or "..", and may repeat. An organization holds at most 1000 folders across its projects (quota_exceeded) nested at most 10 deep (invalid_request). Emits media.folder_created.

Authentication
projectBearer
Request body
MediaFolderCreate
Operation ID
createMediaFolderInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
Idempotency-KeyheaderoptionalOmit for a fresh operation. Supply and reuse a key to deduplicate retries; the CLI manages keys automatically.

Request body fields

FieldDescription
name (required, string)Trimmed; 1 to 100 Unicode characters, no controls, not . or .. minLength: 1 maxLength: 100
parent_id (optional, inline)The folder to create it in; null or absent for the library root.
Request template and responses
shell · request template
curl --request POST --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --header 'Content-Type: application/json' --data '@request.json' 'https://api.screenrig.ai/api/projects/PROJECT_ID/media-folders'

Responses

StatusMeaningBody and headers
201Created folder.MediaFolder (application/json); headers: ETag
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
POST/api/projects/{project_id}/media/move

Move Media In Project

Moves files (media_ids) and folders (folder_ids) into one folder (folder_id), or to the library root when folder_id is null, in one all-or-nothing request of at most 1000 ids. Every id must exist (not_found). A folder cannot move into itself or a folder inside it, and the move must keep every folder within 10 levels (invalid_request).

Items already in the destination are left as they are; each moved file and folder advances its revision. Moving files changes what the by:folder selectors of their old and new folders play, from each screen's next selector resolve; moving a folder changes no folder's own files. Emits media.moved.

A Propose credential's move makes each moved file pending and queues its media review, and approved playlists' selectors resolve it by the folder it was approved with until a person approves the change (docs/reviews.md).

Authentication
projectBearer
Request body
MediaMove
Operation ID
moveMediaInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
Idempotency-KeyheaderoptionalOmit for a fresh operation. Supply and reuse a key to deduplicate retries; the CLI manages keys automatically.

Request body fields

FieldDescription
folder_id (required, inline)Destination folder; null for the library root.
media_ids (optional, array)
folder_ids (optional, array)
Request template and responses
shell · request template
curl --request POST --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --header 'Content-Type: application/json' --data '@request.json' 'https://api.screenrig.ai/api/projects/PROJECT_ID/media/move'

Responses

StatusMeaningBody and headers
200How many files and folders moved.MediaMoveResult (application/json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
POST/api/projects/{project_id}/media/uploads

Create Media Upload In Project

Authentication
projectBearer
Request body
MediaUploadDeclaration
Operation ID
createMediaUploadInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
Idempotency-Keyheaderrequired
project_idqueryoptional

Required with dashboardSession: the project where the file was queued. Must match the session's selected project, otherwise resource_conflict. This binds upload admission across tabs. The returned upload id remains project-scoped for byte upload and commit. Omitted with a project bearer.

Request body fields

FieldDescription
filename (required, string)Name of the bytes being uploaded, as they will be sent: a bare file name of at most 255 UTF-8 bytes, without a directory, backslash or control characters. minLength: 1 maxLength: 255
source_filename (optional, string)

Caller's original file name before any client-side transcode. Bare file name only, at most 255 UTF-8 bytes. Stored verbatim on the ready media as source_filename and used to derive filename. minLength: 1 maxLength: 255

content_type (required, string)Allowed: "image/png", "image/jpeg", "image/webp", "image/gif", "video/mp4", "video/webm", "audio/mpeg"
bytes (required, integer)minimum: 1 maximum: 1073741824
sha256 (required, string)pattern: "^[a-f0-9]{64}$"
tag (optional, string)pattern: "^[A-Za-z0-9]{1,32}$"
folder_id (optional, string)

The media folder the ready media lands in; omitted lands it at the library root. The folder must exist when the upload is declared (invalid_request at folder_id otherwise) and when it commits (the operation fails with invalid_request: declare it again). An uploader (docs/uploaders.md) must send one of its folders (outside_upload_scope otherwise).

Request template and responses
shell · request template
curl --request POST --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --header 'Idempotency-Key: REQUEST_ID' --header 'Content-Type: application/json' --data '@request.json' 'https://api.screenrig.ai/api/projects/PROJECT_ID/media/uploads'

Responses

StatusMeaningBody and headers
201

Short-lived signed authorization for exactly one private object PUT. Send the returned method and every returned header verbatim. This is also how the dashboard uploads. Its browser PUTs the bytes straight to the object store, never through the API, because a proxy in front of the API refuses a request body over 100 MB.

A browser sets Content-Length itself from the body, so it sends every returned header except that one.

MediaUploadSession (application/json); headers: Cache-Control, RateLimit-Policy, RateLimit
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
POST/api/projects/{project_id}/selectors/preview

Preview Selector In Project

Read-only preview of current project-owned ready image or video matches. Returns filename ordering and normalized policy; random playback shuffles on each new pass on the Player. Does not advance cursors, mint content grants, or alter manifests. More than 1024 matches returns invalid_request.

Authentication
projectBearer
Request body
SelectorPreviewInput
Operation ID
previewSelectorInProject

Parameters

NameSend inRequired?Description
project_idpathrequired

Request body fields

FieldDescription
timezone (optional, string)IANA zone media availability is read in; default UTC.
rect (optional, object)The primitive's rect size; required with selector.fit aspect.
primitive (required, string)Allowed: "image", "video"
selector (required, inline)
Request template and responses
shell · request template
curl --request POST --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --header 'Content-Type: application/json' --data '@request.json' 'https://api.screenrig.ai/api/projects/PROJECT_ID/selectors/preview'

Responses

StatusMeaningBody and headers
200Current selector matches.SelectorPreview (application/json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/projects/{project_id}/feedback/bugs

List Bug Reports In Project

Returns the calling project's own bug reports, newest first, up to one hundred. Another project's submissions are never returned. Read an owned thread by its feedback ID. There is no pagination cursor in v1. Each submission carries its status and the staff/agent replies, oldest first.

Authentication
projectBearer
Request body
none
Operation ID
listBugReportsInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' 'https://api.screenrig.ai/api/projects/PROJECT_ID/feedback/bugs'

Responses

StatusMeaningBody and headers
200Bug reports owned by the calling project.FeedbackList (application/json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
POST/api/projects/{project_id}/feedback/bugs

Report Bug In Project

Records one bug report against the calling project. A submission's own fields cannot be updated or deleted; add a correction or more information with a reply on the same feedback thread.

An exact retry carrying the same Idempotency-Key returns the original submission for twenty-four hours instead of creating a duplicate, and a different body under that key returns idempotency_mismatch. Every submission is screened before it is stored.

A body under 12 characters or 3 words returns submission_too_short; text that describes no problem or request (random characters, keyboard mash) returns submission_unclear; spam, link-heavy text, prompt injection and malicious text return submission_rejected.

A refused submission is not stored, its problem detail never repeats the submitted text, and an exact retry under the same Idempotency-Key returns the same refusal.

Never place credentials, cookies, Authorization headers, completion nonces, signed URLs, or object keys in title, body, or context; credential-shaped text (ScreenRig tokens, JWTs, bearer tokens, cloud and API keys, private keys) is replaced with [redacted] before the submission is stored, and the response carries the redacted text.

When the screening model is briefly unavailable the submission is accepted and held for a background re-screen; after a few such acceptances in an hour the project gets submission_screening_unavailable (500, Retry-After) and retries the same request later.

Authentication
projectBearer
Request body
FeedbackWrite
Operation ID
reportBugInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
Idempotency-Keyheaderrequired

Request body fields

FieldDescription
title (required, string)Single-line summary. Leading and trailing whitespace is trimmed, and control characters are rejected. minLength: 1 maxLength: 120
body (required, string)Full description. Line feed and tab are the only accepted control characters. minLength: 1 maxLength: 4000
context (optional, FeedbackContext)

Closed diagnostic envelope. Every member is an optional constrained scalar, nesting is structurally impossible, and an unknown member is rejected with invalid_request. The shape exists so a client cannot persist argument values, credentials, or free-form environment data through it.

Request template and responses
shell · request template
curl --request POST --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --header 'Idempotency-Key: REQUEST_ID' --header 'Content-Type: application/json' --data '@request.json' 'https://api.screenrig.ai/api/projects/PROJECT_ID/feedback/bugs'

Responses

StatusMeaningBody and headers
201Stored bug report. An exact idempotent retry returns this same submission.FeedbackSubmission (application/json); headers: RateLimit-Policy, RateLimit
400

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
409

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
422

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
429

Stable rate_limited problem. Retry only after the authoritative Retry-After interval. Fixed-window denials also include the applicable RateLimit-Policy and RateLimit members; concurrency and byte-budget denials omit those optional disclosures.

Problem (application/problem+json); headers: Retry-After, RateLimit-Policy, RateLimit
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/projects/{project_id}/feedback/features

List Feature Requests In Project

Returns the calling project's own feature requests, newest first, up to one hundred. Another project's submissions are never returned. Read an owned thread by its feedback ID. There is no pagination cursor in v1. Each submission carries its status and the staff/agent replies, oldest first.

Authentication
projectBearer
Request body
none
Operation ID
listFeatureRequestsInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' 'https://api.screenrig.ai/api/projects/PROJECT_ID/feedback/features'

Responses

StatusMeaningBody and headers
200Feature requests owned by the calling project.FeedbackList (application/json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
POST/api/projects/{project_id}/feedback/features

Request Feature In Project

Records one feature request against the calling project. A submission's own fields cannot be updated or deleted; add a correction or more information with a reply on the same feedback thread.

An exact retry carrying the same Idempotency-Key returns the original submission for twenty-four hours instead of creating a duplicate, and a different body under that key returns idempotency_mismatch. Every submission is screened before it is stored.

A body under 12 characters or 3 words returns submission_too_short; text that describes no problem or request (random characters, keyboard mash) returns submission_unclear; spam, link-heavy text, prompt injection and malicious text return submission_rejected.

A refused submission is not stored, its problem detail never repeats the submitted text, and an exact retry under the same Idempotency-Key returns the same refusal.

Never place credentials, cookies, Authorization headers, completion nonces, signed URLs, or object keys in title, body, or context; credential-shaped text (ScreenRig tokens, JWTs, bearer tokens, cloud and API keys, private keys) is replaced with [redacted] before the submission is stored, and the response carries the redacted text.

When the screening model is briefly unavailable the submission is accepted and held for a background re-screen; after a few such acceptances in an hour the project gets submission_screening_unavailable (500, Retry-After) and retries the same request later.

Authentication
projectBearer
Request body
FeedbackWrite
Operation ID
requestFeatureInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
Idempotency-Keyheaderrequired

Request body fields

FieldDescription
title (required, string)Single-line summary. Leading and trailing whitespace is trimmed, and control characters are rejected. minLength: 1 maxLength: 120
body (required, string)Full description. Line feed and tab are the only accepted control characters. minLength: 1 maxLength: 4000
context (optional, FeedbackContext)

Closed diagnostic envelope. Every member is an optional constrained scalar, nesting is structurally impossible, and an unknown member is rejected with invalid_request. The shape exists so a client cannot persist argument values, credentials, or free-form environment data through it.

Request template and responses
shell · request template
curl --request POST --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --header 'Idempotency-Key: REQUEST_ID' --header 'Content-Type: application/json' --data '@request.json' 'https://api.screenrig.ai/api/projects/PROJECT_ID/feedback/features'

Responses

StatusMeaningBody and headers
201Stored feature request. An exact idempotent retry returns this same submission.FeedbackSubmission (application/json); headers: RateLimit-Policy, RateLimit
400

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
409

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
422

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
429

Stable rate_limited problem. Retry only after the authoritative Retry-After interval. Fixed-window denials also include the applicable RateLimit-Policy and RateLimit members; concurrency and byte-budget denials omit those optional disclosures.

Problem (application/problem+json); headers: Retry-After, RateLimit-Policy, RateLimit
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/projects/{project_id}/service-clients

List Service Clients In Project

The project's service clients (spec: a customer's server, script or CI job owned by the project), newest first, live and revoked, with their public keys, secret ids and usage; never a secret or its digest. Needs the project capability.

Authentication
projectBearer
Request body
none
Operation ID
listServiceClientsInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' 'https://api.screenrig.ai/api/projects/PROJECT_ID/service-clients'

Responses

StatusMeaningBody and headers
200The service client.ServiceClientList (application/json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
POST/api/projects/{project_id}/service-clients

Create Service Client In Project

Creates a service client owned by the project with a name, capabilities (omitted means all six; each must be one the manager holds, else 403), access (read, the default, or manage), and a public JWK key (OKP Ed25519, EC P-256 or RSA of at least 2048 bits) and/or secret true. The secret is returned once, here only. At most 50 live clients per organization.

Agents need identity scope, live identity Manage, their own Manage grant with the project capability on the project, and a live organization admin role; a person uses the dashboard session with project_id and a fresh proof (kind service_client_change, subject the client id, or the project id when creating) in the body. A service token is refused 403.

A member limited to screens does not connect agents, issue credentials or manage the project's people: outside_screen_scope (ask the project owner).

Authentication
agentIdentityBearer
Request body
ServiceClientChange
Operation ID
createServiceClientInProject

Parameters

NameSend inRequired?Description
project_idpathrequired

Request body fields

FieldDescription
project_id (optional, string)Dashboard session only.
proof (optional, DashboardProof)
name (optional, string)minLength: 1 maxLength: 80
capabilities (optional, array)
access (optional, string)Manage needs a person who can approve reviews (403 approver_required). Allowed: "read", "propose", "manage"
key (optional, object)A public JWK: OKP Ed25519, EC P-256 or RSA of at least 2048 bits.
secret (optional, boolean)Generate a secret (creation only).
upload_scope (optional, UploadScope)

What an uploader may use (docs/uploaders.md): the playlists it changes pages of and the media folders it uploads into. Folders are exactly the listed ones, never their subfolders. An id that names no live object of the project when written is invalid_request at its position; a later deletion leaves a dead id, which grants nothing.

The scope is read on each request, so a change applies to the next one.

Request template and responses
shell · request template
curl --request POST --header 'Content-Type: application/json' --data '@request.json' 'https://api.screenrig.ai/api/projects/PROJECT_ID/service-clients'

Responses

StatusMeaningBody and headers
201The service client.ServiceClientResult (application/json)
402

feature_not_in_plan — an upload scope makes an uploader, and the project's plan does not include uploaders; required_plan names the plan that does. Narrowing a scope and removing it are always allowed.

Problem (application/problem+json)
403

outside_screen_scope - the caller is limited to screens and the screen, screen folder, selector or audience the request names or reaches is outside them (docs/screen-scope.md). An id outside the scope and an id that does not exist get the same answer; errors[0].screen_scope carries the caller's scope, and the write is refused whole, never narrowed.

Problem (application/problem+json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/projects/{project_id}/media-sync-accounts

List Media Sync Accounts In Project

Lists the project's media sync accounts, newest first (200 per page; next_cursor continues). Each shows its tenant and client id, its state and its last test; the client secret is never returned, only whether one is set and its last four characters.

Authentication
projectBearer
Request body
none
Operation ID
listMediaSyncAccountsInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
cursorqueryoptionalThe next_cursor of the previous page.
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' 'https://api.screenrig.ai/api/projects/PROJECT_ID/media-sync-accounts'

Responses

StatusMeaningBody and headers
200The project's accounts.MediaSyncAccountList (application/json); headers: Cache-Control
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
POST/api/projects/{project_id}/media-sync-accounts

Create Media Sync Account In Project

Adds an account that syncs read through. kind microsoft365 stores the credentials of the project's own Microsoft Entra app, so syncs can read a SharePoint or OneDrive for work folder: config.tenant_id is the tenant's directory id or primary domain (common, organizations and consumers are refused), config.client_id the app's application id, and secret the value of one of the app's client secrets; the app needs the Microsoft Graph application permission Sites.Selected (granted on each site) or Files.Read.All, with admin consent.

Instead of those three, config.connection_id names a Microsoft connection of the project (createConnection), in either mode, which signs in and holds the secret. kind canva takes only a name: the account is pending_consent and the answer carries authorize_url, a one-time link (valid for authorize_expires_at) that the person who owns the Canva account opens, signed in to Canva, to connect it through screenRIG's Canva integration.

The grant belongs to the project, so its syncs outlive the person who connected it.

A server without the Canva integration answers 409 canva_not_configured. kind dropbox works like canva: the account is pending_consent and authorize_url is a one-time link that the person who owns the Dropbox account opens, signed in to Dropbox, to allow read-only access (files.metadata.read, files.content.read, account_info.read, sharing.read).

It goes through screenRIG's Dropbox app, or through the customer's own Dropbox app when config.app_key names it (PKCE, so no app secret; the app must list https://API_ORIGIN/api/dropbox/callback as a redirect URI).

A server without screenRIG's Dropbox app answers 409 dropbox_not_configured to a dropbox account with no app_key. kind google_drive is ready at once and reads the folders shared with config.service_account_email: screenRIG's service account, or the customer's own when secret is that service account's JSON key.

A folder shared with screenRIG's service account syncs only when a member of the project with a verified email shared it or owns it. A server without screenRIG's service account answers 409 google_drive_not_configured to a google_drive account with no key. A secret is sealed at rest and never returned or logged. Appends media_sync_account.created.

An exact retry with the same Idempotency-Key returns the same account (a Canva or Dropbox retry gets a new link).

Authentication
projectBearer
Request body
MediaSyncAccountWrite
Operation ID
createMediaSyncAccountInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
Idempotency-KeyheaderoptionalOmit for a fresh operation. Supply and reuse a key to deduplicate retries; the CLI manages keys automatically.

Request body fields

FieldDescription
kind (required, string)Allowed: "microsoft365", "canva", "dropbox", "google_drive"
name (required, string)minLength: 1 maxLength: 80
config (optional, object)

For microsoft365, either tenant_id and client_id (both) with secret, or connection_id alone: the id of a Microsoft connection of this project. For dropbox, app_key optionally names the customer's own Dropbox app. Not accepted for canva or google_drive.

secret (optional, string)

Required for microsoft365 with tenant_id and client_id: the value of one of the app's client secrets (not its id), at most 1024 characters.

For google_drive, optional: the JSON key of the customer's own Google Cloud service account (type service_account), whose client_email becomes the account's service_account_email; without it the account reads through screenRIG's service account. Not accepted with connection_id, nor for canva or dropbox. minLength: 1 maxLength: 8192

Request template and responses
shell · request template
curl --request POST --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --header 'Content-Type: application/json' --data '@request.json' 'https://api.screenrig.ai/api/projects/PROJECT_ID/media-sync-accounts'

Responses

StatusMeaningBody and headers
201Created, with its secret masked; a Canva or Dropbox account also carries authorize_url.MediaSyncAccountConnect (application/json); headers: ETag, Cache-Control
400invalid_request.Problem (application/problem+json)
402feature_not_in_plan — the project's plan does not include media sync; required_plan names the plan that does.Problem (application/problem+json)
409

canva_not_configured (this server has no Canva integration; kind canva only), dropbox_not_configured (no screenRIG Dropbox app and no config.app_key; kind dropbox only), google_drive_not_configured (no screenRIG service account and no key; kind google_drive only), resource_conflict or idempotency_mismatch.

Problem (application/problem+json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/projects/{project_id}/media-syncs

List Media Syncs In Project

Lists the project's media syncs, newest first (200 per page; next_cursor continues), optionally of one account_id or state. Each shows its source folder, the media folder it fills, its cadence, state, next run and the summary of its last run.

Authentication
projectBearer
Request body
none
Operation ID
listMediaSyncsInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
cursorqueryoptionalThe next_cursor of the previous page.
account_idqueryoptionalLists only the syncs that read through this account.
statequeryoptionalLists only the syncs in this state.
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' 'https://api.screenrig.ai/api/projects/PROJECT_ID/media-syncs'

Responses

StatusMeaningBody and headers
200The project's syncs.MediaSyncList (application/json); headers: Cache-Control
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
POST/api/projects/{project_id}/media-syncs

Create Media Sync In Project

provider canva: reads the design (design is its id or its canva.com/design/ID/... address) through a connected Canva account, and stores the sync, due now.

Each run asks Canva for the design's last change and, when it moved, exports the pages (pages, default all; format png gives one image per page and mp4 one video) and imports them into the media folder, replacing the bytes of a page already imported under the same media id so the playlists that use it update; a page the design no longer has leaves play like a removed SharePoint file.

A design Canva no longer shows stops the sync in state error (run error design_unavailable) and keeps the media.

A design or page the account cannot see is 409 media_sync_source_refused. provider dropbox: url is the folder's address in Dropbox (https://www.dropbox.com/home/...), a shared folder link the connected account has added to its Dropbox, or a path starting with /; it is read once through a connected Dropbox account and the sync is stored, due now.

Folders in a team space are read from the team's root. Each run continues from Dropbox's saved position in the folder, so only changes are read.

A folder the account cannot open is 409 media_sync_source_refused; an account whose connection Dropbox no longer honors is 409 dropbox_reconnect_required. provider google_drive: url is the folder's Google Drive address (https://drive.google.com/drive/folders/ID) or its id, shared (Viewer is enough) with the account's service_account_email.

Each run lists the folder and compares each file's checksum. Google Docs, Sheets and Slides files are skipped as unsupported_type. A folder the address cannot open is 409 media_sync_source_refused.

Through screenRIG's service account the folder must be shared or owned by a member of the project with a verified email (403 media_sync_sharer_not_member), and every run checks it again (run error sharer_not_member stops the sync in state error). provider sharepoint: reads the folder's address through the account (a SharePoint site address such as https://TENANT.sharepoint.com/sites/SITE/LIBRARY/FOLDER, or a sharing link; the app must be able to see it: Sites.Selected needs a grant on the site, a sharing link needs Files.Read.All) and stores the sync, due now. folder_id is the media folder the files land in; without it the sync creates one named after the source folder.

Each run imports the images (png, jpeg, webp, gif), videos (mp4, webm) and audio (mp3) directly in the source folder, replaces the bytes of a file that changed under the same media id so playlists that use it update, and takes a file removed at the source out of play: its media is deleted, or, while screens still hold it, moved to a Removed subfolder and deleted later.

Subfolders are ignored; other files are listed as skipped with the reason. every is the seconds between runs, 300 to 86400, default 900. A folder the provider refuses is 409 media_sync_source_refused and one it cannot reach is 500 media_sync_source_unavailable; nothing is stored. Appends media_sync.created.

Authentication
projectBearer
Request body
MediaSyncWrite
Operation ID
createMediaSyncInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
Idempotency-KeyheaderoptionalOmit for a fresh operation. Supply and reuse a key to deduplicate retries; the CLI manages keys automatically.

Request body fields

FieldDescription
provider (required, string)Allowed: "sharepoint", "canva", "dropbox", "google_drive"
account_id (required, string)An account of the provider's kind: microsoft365 for sharepoint, canva, dropbox or google_drive.
url (optional, string)

sharepoint (required): the folder's SharePoint address or sharing link, read once to find the folder and not stored. dropbox (required): the folder's Dropbox address, a shared folder link the account has added, or a path starting with /. google_drive (required): the folder's Google Drive address or its id. maxLength: 4096

design (optional, string)canva (required): the design's id, or its canva.com/design/ID/... address. maxLength: 2048
pages (optional, array)canva: the pages to sync; omit for every page. A design that later has fewer pages takes the missing ones out of play.
format (optional, string)canva: png gives one image per page; mp4 one video of the pages. Allowed: "png", "mp4" default: "png"
folder_id (optional, string)The media folder the files land in. Omit it to create one named after the source folder.
every (optional, integer)Seconds between runs; defaults to 900. minimum: 300 maximum: 86400
name (optional, string)Defaults to the source folder's name. minLength: 1 maxLength: 80
Request template and responses
shell · request template
curl --request POST --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --header 'Content-Type: application/json' --data '@request.json' 'https://api.screenrig.ai/api/projects/PROJECT_ID/media-syncs'

Responses

StatusMeaningBody and headers
201Created, due now.MediaSync (application/json); headers: ETag, Cache-Control
400invalid_request.Problem (application/problem+json)
402feature_not_in_plan — the project's plan does not include media sync; required_plan names the plan that does.Problem (application/problem+json)
403media_sync_sharer_not_member — a Google Drive folder read through screenRIG's service account was not shared or owned by a member of the project with a verified email.Problem (application/problem+json)
409

media_sync_source_refused (the provider refused the app, its permission or the folder), dropbox_reconnect_required (the Dropbox account must be connected again), dropbox_not_configured, google_drive_not_configured, resource_conflict (the same source is already synced into that media folder) or idempotency_mismatch.

Problem (application/problem+json)
500media_sync_source_unavailable — the provider could not be reached or answered with a failure.Problem (application/problem+json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/projects/{project_id}/fleet-links

List Fleet Links In Project

Lists the project's fleet links, oldest first (at most 50). Below effective Manage each url is empty and url_redacted is true, since the URL creates screens.

Authentication
projectBearer
Request body
none
Operation ID
listFleetLinksInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' 'https://api.screenrig.ai/api/projects/PROJECT_ID/fleet-links'

Responses

StatusMeaningBody and headers
200The project's fleet links.FleetLinkList (application/json); headers: Cache-Control
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
POST/api/projects/{project_id}/fleet-links

Create Fleet Link In Project

Creates a fleet link: one Player URL (https://play.<domain>/player/#fleet=<secret>) that turns every device opening it into its own screen in this project, without a pairing code. Put it in a device manager, such as a Google Admin console kiosk app.

Each new screen gets the link's tags, fields and playlist, and a label from the device (its administrator asset ID, then location), else the next default label. A Player that already holds a screen never makes another: its key stays the screen's identity across reloads and relaunches.

After a powerwash or reinstall, a device that reports the serial or DUID of a screen a fleet link of this project created recovers that screen (screen.recovered) instead of creating a new one, once the old key has been silent for ten minutes.

The secret travels in the URL fragment, which browsers never send to a server. max_screens caps the screens the link creates and expires_at ends the link at that time, as disabling it does. An organization has at most 50 fleet links across its projects (fleet_link_limit_reached). Appends fleet_link.created.

An exact retry with the same Idempotency-Key returns this same answer for twenty-four hours.

Authentication
projectBearer
Request body
FleetLinkWrite
Operation ID
createFleetLinkInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
Idempotency-KeyheaderoptionalOmit for a fresh operation. Supply and reuse a key to deduplicate retries; the CLI manages keys automatically.

Request body fields

FieldDescription
label (required, string)minLength: 1 maxLength: 80
enabled (optional, boolean)Defaults to true.
tags (optional, ScreenTags)

Fleet selector tags, 0 to 16 unique exact tags, each matching the media tag grammar. On ScreenPatch the array replaces the whole set and an empty array clears it; a duplicate or malformed tag is invalid_request. Changing tags bumps the screen revision (If-Match guards it) and appends screen.updated with details.tags; it never changes the manifest revision.

Tags are never on the runtime manifest and never authorization.

fields (optional, object)Fields each screen the link creates starts with; card placements read them through {screen.field.NAME}.
playlist_id (optional, string)
max_screens (optional, integer)minimum: 1 maximum: 10000
expires_at (optional, string)When the link expires (RFC 3339); a link past it creates and recovers no screens. Absent means it never expires. A time already past is accepted and expires the link at once. format: "date-time"
Request template and responses
shell · request template
curl --request POST --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --header 'Content-Type: application/json' --data '@request.json' 'https://api.screenrig.ai/api/projects/PROJECT_ID/fleet-links'

Responses

StatusMeaningBody and headers
201Created, with its url.FleetLink (application/json); headers: Cache-Control
400invalid_request, including an unknown playlist_id or a malformed tag or field.Problem (application/problem+json)
409fleet_link_limit_reached or idempotency_mismatch.Problem (application/problem+json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/projects/{project_id}/webhooks

List Webhooks In Project

Lists the project's webhook notifications in the webhook shape, oldest first (at most 50); GET /api/notifications lists every channel. The signing secret is never returned here. Requires the project capability; a reports-only credential is refused 403 forbidden, because the response includes receiver URLs.

Authentication
projectBearer
Request body
none
Operation ID
listWebhooksInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' 'https://api.screenrig.ai/api/projects/PROJECT_ID/webhooks'

Responses

StatusMeaningBody and headers
200The project's webhooks.WebhookList (application/json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
POST/api/projects/{project_id}/webhooks

Create Webhook In Project

Creates a webhook that receives the project's own durable events as signed HTTPS POSTs. url must be https on a public Internet host: an IP literal or every current DNS answer of the name must be public (private, loopback, link-local, CGNAT, IPv6 outside 2000::/3, documentation, and other reserved ranges are refused with webhook_url_rejected).

The port must be 443 (the default) or 8443, else webhook_url_rejected. The host is resolved and checked again before every delivery and the connection is dialed to exactly the checked address, so a DNS answer that changes later cannot redirect deliveries. event_types lists exact event types (screen.online) or prefixes ending in .* (screen.*).

An organization has at most 50 notifications across every channel (webhook_limit_reached). The server generates the signing secret and returns it only in this answer and in rotate-secret; store it. An exact retry with the same Idempotency-Key returns this same answer, secret included, for twenty-four hours.

Delivery starts with the first event after notification.created.

Authentication
projectBearer
Request body
WebhookWrite
Operation ID
createWebhookInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
Idempotency-KeyheaderoptionalOmit for a fresh operation. Supply and reuse a key to deduplicate retries; the CLI manages keys automatically.

Request body fields

FieldDescription
url (required, string)https URL on a public Internet host, port 443 (the default) or 8443. No userinfo or fragment. maxLength: 2048 format: "uri"
event_types (required, WebhookEventTypes)

Exact event types such as screen.online, or prefixes ending in .* such as screen.* (every type starting with screen.). notification.test is never fanned out by a subscription; it is sent only by POST /api/webhooks/{id}/test.

enabled (optional, boolean)default: true
description (optional, string)maxLength: 200
Request template and responses
shell · request template
curl --request POST --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --header 'Content-Type: application/json' --data '@request.json' 'https://api.screenrig.ai/api/projects/PROJECT_ID/webhooks'

Responses

StatusMeaningBody and headers
201Created. secret is shown only here and on rotate-secret.WebhookWithSecret (application/json); headers: Cache-Control
400invalid_request or webhook_url_rejected.Problem (application/problem+json)
409webhook_limit_reached, idempotency_mismatch, or resource_conflict when the project belongs to no organization.Problem (application/problem+json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/projects/{project_id}/alerts

List Alerts In Project

Lists the project's screen alerts: one per screen and condition while it lasts (open), and those that ended within the plan's event retention (resolved).

An alert opens when its condition's event arrives (screen.offline, a display_disconnected, temperature_high or on_battery health change, screen.storage_shortfall, a stuck screen.manifest_upgrade, an error-level screen.status_changed, a stalled, blank or frozen screen.glass_changed) and resolves on the clearing event; crashing is a notice, not an alert. counts.attention counts open alerts that are not acknowledged, snoozed or muted, the number the dashboard shows.

A screen restarting for a reboot the backend sent opens no screen_offline or display_disconnected alert until the reboot is done or ten minutes after it was sent; a condition that still holds then opens its alert at that moment. Open alerts come first, newest first; pass next_cursor back as before for the next page.

Authentication
projectBearer
Request body
none
Operation ID
listAlertsInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
formatqueryoptionaljson (default) returns the report as JSON. csv, xlsx and pdf return the same rows as a file attachment (every page of a paged report, up to 50000 rows).
statequeryoptional
screen_idqueryoptional
beforequeryoptionalnext_cursor of the previous page.
limitqueryoptional
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' 'https://api.screenrig.ai/api/projects/PROJECT_ID/alerts'

Responses

StatusMeaningBody and headers
200One page of alerts.AlertList (application/json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/projects/{project_id}/alert-mutes

List Alert Mutes In Project

Lists the project's mutes that have not ended, soonest end first (at most 50).

Authentication
projectBearer
Request body
none
Operation ID
listAlertMutesInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' 'https://api.screenrig.ai/api/projects/PROJECT_ID/alert-mutes'

Responses

StatusMeaningBody and headers
200The project's current mutes.AlertMuteList (application/json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
POST/api/projects/{project_id}/alert-mutes

Create Alert Mute In Project

Mutes screens for maintenance until an instant at most 30 days ahead: the screens named by screen_ids, and every screen carrying any of tags at the time a notice is due. Their alerts still open and resolve, marked muted, and never need attention; every notification's notices about them are skipped (muted).

An organization has at most 50 current mutes across its projects (alert_mute_limit_reached). Appends alert_mute.created.

Authentication
projectBearer
Request body
AlertMuteWrite
Operation ID
createAlertMuteInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
Idempotency-KeyheaderoptionalOmit for a fresh operation. Supply and reuse a key to deduplicate retries; the CLI manages keys automatically.

Request body fields

FieldDescription
screen_ids (optional, array)
tags (optional, ScreenTags)

Fleet selector tags, 0 to 16 unique exact tags, each matching the media tag grammar. On ScreenPatch the array replaces the whole set and an empty array clears it; a duplicate or malformed tag is invalid_request. Changing tags bumps the screen revision (If-Match guards it) and appends screen.updated with details.tags; it never changes the manifest revision.

Tags are never on the runtime manifest and never authorization.

until (required, string)At most 30 days ahead. format: "date-time"
note (optional, string)maxLength: 200
Request template and responses
shell · request template
curl --request POST --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --header 'Content-Type: application/json' --data '@request.json' 'https://api.screenrig.ai/api/projects/PROJECT_ID/alert-mutes'

Responses

StatusMeaningBody and headers
201Created.AlertMute (application/json)
409alert_mute_limit_reached or idempotency_mismatch.Problem (application/problem+json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/projects/{project_id}/notifications

List Notifications In Project

Lists the organization's notifications that cover the project, of every channel, oldest first (at most 50). status, failing_since, last_success_at and last_failure_at are this project's. A webhook's signing secret is never returned here.

Requires the project capability; a reports-only credential is refused 403 forbidden, because the response includes receiver URLs and recipients.

Authentication
projectBearer
Request body
none
Operation ID
listNotificationsInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' 'https://api.screenrig.ai/api/projects/PROJECT_ID/notifications'

Responses

StatusMeaningBody and headers
200The project's notifications.NotificationList (application/json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
POST/api/projects/{project_id}/notifications

Create Notification In Project

Creates a notification. channel email sends to recipients (owner, or user_ids of the project's members); channel webhook POSTs, signed, to url, which follows the webhook URL rules (https on a public Internet host, port 443 or 8443, else webhook_url_rejected). conditions lists the screen state changes it fires on; an email notification needs at least one, a webhook needs conditions or event_types. screen_tags limits conditions to screens carrying any of those tags; empty means every screen, or audience says which screens in the rules of a campaign audience. min_severity and severity filter and rate the notices, and active_hours holds or drops them outside its windows.

A condition notifies only after it has lasted hold_minutes (default 10), and a resolved notice follows when it clears after a notice went out. The notification covers this project alone; an organization has at most 50 notifications, not counting the defaults the system makes (notification_limit_reached).

A webhook's signing secret is generated by the server and returned only in this answer and in rotate-secret; store it. An exact retry with the same Idempotency-Key returns this same answer, secret included, for twenty-four hours. Notices start with the first event after notification.created.

Authentication
projectBearer
Request body
NotificationWrite
Operation ID
createNotificationInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
Idempotency-KeyheaderoptionalOmit for a fresh operation. Supply and reuse a key to deduplicate retries; the CLI manages keys automatically.

Request body fields

FieldDescription
channel (required, string)Allowed: "email", "webhook", "slack", "teams", "pagerduty", "telegram"
description (optional, string)A name for people. maxLength: 200
conditions (optional, NotificationConditions)
screen_tags (optional, ScreenTags)

Fleet selector tags, 0 to 16 unique exact tags, each matching the media tag grammar. On ScreenPatch the array replaces the whole set and an empty array clears it; a duplicate or malformed tag is invalid_request. Changing tags bumps the screen revision (If-Match guards it) and appends screen.updated with details.tags; it never changes the manifest revision.

Tags are never on the runtime manifest and never authorization.

audience (optional, CampaignAudience)

Which screens a campaign targets: exactly one of all (every rule matches), any (at least one matches), tag (the screen carries the tag), screen_id (that screen) or folder (the screens in that screen folder and every folder inside it, GET /api/screen-folders; the folder must exist).

Rules nest at most 3 deep and an audience has at most 500 rules. {"all": []} is every screen of the project; elsewhere all and any list at least one rule.

min_severity (optional, NotificationSeverity)

The severity of a notice, least severe first. An opened notice has its condition's severity: error for screen_offline and warning for every other condition, unless the notification's severity says otherwise. A resolved notice and a test are info. Allowed: "info", "warning", "error"

severity (optional, NotificationSeverityOverrides)

Condition to severity for this notification, such as {"not_playing": "error"}. It counts for min_severity and is the severity Teams and PagerDuty show for the condition. A condition not listed keeps its default. On a patch an empty object, like null, clears every override.

active_hours (optional, NotificationActiveHours)

When opened notices go out: the windows (screenrig.schedule/v1), read in timezone. A notice that falls due while they are closed waits for the next opening (outside hold, the default) and goes out then if its condition still holds, so a condition that clears first sends nothing, or is skipped (outside drop; last_error outside_hours).

A resolved notice for an opened notice that was sent always goes out, inside the hours or not, and a test ignores them. crashing is held or dropped like any other condition. The hours judge a notice when it first goes out; a failed one is retried on the usual schedule whatever the hours.

Adding, changing or removing the hours judges the notices held for the old ones again at once.

reach_drop (optional, NotificationReachDrop)

The smallest drop in a campaign's reach a reach_dropped notice is sent for: screens is the fewest screens lost (default 1) and percent, when set, the smallest share of the screens the campaign reached when it was published; a drop must meet both.

A smaller drop queues no notice, and a queued notice whose drop shrank below it by the time it is due is skipped (condition_cleared). Only with the reach_dropped condition; on a notification without it, invalid_request.

hold_minutes (optional, integer)How long a condition must last before it notifies. crashing is never held. default: 10 minimum: 0 maximum: 1440
recipients (optional, NotificationRecipients)

Email only. owner (whoever owns the project when a notice sends) or the user_id of a person who is a member of the project; a user_id that is not a member is invalid_request. Each is emailed at their verified address. One who has since left the project or has no verified address is skipped.

url (optional, string)Webhook only: https URL on a public Internet host, port 443 (the default) or 8443. No userinfo or fragment. maxLength: 2048 format: "uri"
event_types (optional, NotificationEventTypes)

Webhook only. Project events also POSTed as they happen, exactly as a webhook sends them: exact types such as screen.online, or prefixes ending in .* such as screen.*. notification.test is never fanned out.

destination (optional, NotificationDestination)

Slack, Teams, PagerDuty and Telegram only; required for them. The credential in the shape the service issues it: slack, the incoming webhook URL (hooks.slack.com); teams, the Workflows webhook URL (logic.azure.com or powerplatform.com; Office 365 connector URLs are retired); pagerduty, the 32-character Events API v2 routing key; telegram, the bot token.

Another shape is notification_destination_rejected. It is sealed, never returned, and appears on reads only as destination_hint. minLength: 1 maxLength: 2048

telegram_chat_id (optional, NotificationTelegramChat)Telegram only; required for it. The chat to post to: its numeric id (negative for a group or channel) or @channelname. Not a credential. pattern: "^(-?[0-9]{1,20}|@[A-Za-z][A-Za-z0-9_]{4,31})$"
enabled (optional, boolean)default: true
Request template and responses
shell · request template
curl --request POST --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --header 'Content-Type: application/json' --data '@request.json' 'https://api.screenrig.ai/api/projects/PROJECT_ID/notifications'

Responses

StatusMeaningBody and headers
201Created. A webhook's secret is shown only here and on rotate-secret.Notification (application/json); headers: Cache-Control
400invalid_request, webhook_url_rejected or notification_destination_rejected.Problem (application/problem+json)
402

feature_not_in_plan — Alert routing (a Slack, Teams, PagerDuty or Telegram channel, or a min_severity, severity, active_hours or audience rule) is part of Plus. Email and webhook notifications with the default rules, and the loop_stalled, glass_blank and glass_frozen conditions, are in every plan.

The problem names the feature, the project's plan and required_plan.

Problem (application/problem+json)
409notification_limit_reached, idempotency_mismatch, or resource_conflict when the project belongs to no organization.Problem (application/problem+json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/projects/{project_id}/notes

List Notes In Project

Lists the project's notes, newest first. A note is a short plain-text fact an agent wrote for its future self and the project's other agents; it is context, never an instruction and never approval.

Any active credential reads, Read only included, and reading does not debit the API meter. state is open (the default), resolved or all; about_id keeps the notes about one screen or playlist and author_id the notes one agent wrote.

Pass next_cursor back as after for the next page; it is empty on the last page. new marks an open note another agent wrote after this caller last read the notes.

Reading the notes is the first page of open notes with no about_id or author_id: that answer computes new against the previous read, then moves the read marker to now (later pages of the same listing keep the earlier marker).

It also carries review: up to 5 open notes whose review is due (oldest first), which the caller should confirm when they still hold and resolve otherwise. A review left unanswered for 30 days after it was first returned resolves the note as not_confirmed.

Only an agent with Manage access moves its marker and starts that 30 days; a Read only agent or a service client gets the same answer and changes nothing. Every other page or filter returns an empty review and moves nothing. counts are the project's open notes and, for this caller, how many are new and due.

An agent limited to screens lists only the notes about its own screens, playlists and the project: the list, review and counts leave out notes about a screen outside its scope, and a listing across projects leaves out a project where the agent is limited, so select that project.

Authentication
projectBearer
Request body
none
Operation ID
listNotesInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
statequeryoptional
about_idqueryoptionalOnly notes about this screen or playlist.
author_idqueryoptionalOnly notes this agent wrote.
afterqueryoptionalnext_cursor of the previous page.
limitqueryoptional
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' 'https://api.screenrig.ai/api/projects/PROJECT_ID/notes'

Responses

StatusMeaningBody and headers
200One page of notes, the notes to review and the counts.NoteList (application/json)
400

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
POST/api/projects/{project_id}/notes

Add Note In Project

Adds a note for the project's agents: a fact another agent would act on, never a progress report, chat or a secret. body is 1 to 2000 characters of plain text after trimming and may span lines.

Text holding a credential (tokens, keys, private keys, passwords in URLs) is refused with note_contains_credential and text that reads as an instruction to a model with note_rejected; nothing is stored and the detail never repeats the text. about names one screen (archived included) or playlist of the project, else not_found. ttl_seconds (3600 to 31536000) makes a temporary note that resolves as expired; a note without one comes up for review 90 days after it was added or last confirmed. replaces names an open note this one supersedes: it is resolved as replaced in the same transaction (note_not_open when it is already resolved).

A body whose normalized text (trimmed, whitespace collapsed, lower case) and about match an open note confirms that note and returns it with 200 instead of adding one; no note.added event is appended. An organization holds at most 200 open notes across its projects; the 201st is note_limit_reached, whose detail names up to 5 notes to resolve first.

Appends note.added (and note.resolved for a replaced note) without the text. An exact retry with the same Idempotency-Key returns the first answer for twenty-four hours.

For an agent limited to screens (docs/screen-scope.md) an about that is a screen outside its scope or unknown to the project, or a replaces that names a note about a screen outside its scope, is outside_screen_scope (403) and nothing is stored.

Authentication
projectBearer
Request body
NoteWrite
Operation ID
addNoteInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
Idempotency-KeyheaderoptionalOmit for a fresh operation. Supply and reuse a key to deduplicate retries; the CLI manages keys automatically.

Request body fields

FieldDescription
body (required, string)Plain text, 1 to 2000 characters after trimming; line breaks are kept. minLength: 1 maxLength: 2000
about (optional, inline)
ttl_seconds (optional, integer)Expire the note this long after it is added. Without it the note comes up for review after 90 days. minimum: 3600 maximum: 31536000
replaces (optional, string)An open note this one supersedes; it is resolved as replaced. pattern: "^(?:(?:stage|qa|development)_)?nte_[A-Za-z0-9_-]{16,24}$"
Request template and responses
shell · request template
curl --request POST --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --header 'Content-Type: application/json' --data '@request.json' 'https://api.screenrig.ai/api/projects/PROJECT_ID/notes'

Responses

StatusMeaningBody and headers
201Added.Note (application/json)
200The text matched an open note, which is confirmed and returned.Note (application/json)
400

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
403

outside_screen_scope - the caller is limited to screens and the screen, screen folder, selector or audience the request names or reaches is outside them (docs/screen-scope.md). An id outside the scope and an id that does not exist get the same answer; errors[0].screen_scope carries the caller's scope, and the write is refused whole, never narrowed.

Problem (application/problem+json)
404

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
409note_not_open, note_limit_reached or idempotency_mismatch.Problem (application/problem+json)
422note_contains_credential or note_rejected.Problem (application/problem+json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/projects/{project_id}/support/status

Support Status In Project

Availability and hours for any active project. chat_allowed is true for every active project, including Standard. human_available is true when a person can join the chat on request (Education, Premium and Enterprise); Standard and Plus get documentation and AI support. staffed says whether staff are in their hours now. Luna answers right away on every plan.

Authentication
projectBearer
Request body
none
Operation ID
supportStatusInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' 'https://api.screenrig.ai/api/projects/PROJECT_ID/support/status'

Responses

StatusMeaningBody and headers
200Support result.SupportStatus (application/json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/projects/{project_id}/support/conversations

List Support Conversations In Project

Project conversations, newest first, at most 100. Staff unread counts are per authenticated person or agent.

Authentication
projectBearer
Request body
none
Operation ID
listSupportConversationsInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
beforequeryoptionalConversation ID from the preceding page's next cursor.
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' 'https://api.screenrig.ai/api/projects/PROJECT_ID/support/conversations'

Responses

StatusMeaningBody and headers
200Support result.SupportConversationList (application/json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
POST/api/projects/{project_id}/support/conversations

Create Support Conversation In Project

Available on every plan; Luna answers first, right away. Where a person can join (human_available on the support status) a request for one pauses Luna for staff; on Standard and Plus it is ignored and Luna answers. Screened before storage or Slack.

An opening message under 8 characters or 3 words returns submission_too_short; one that is not a question or problem returns submission_unclear; spam, link-heavy text, prompt injection and unsafe text return submission_rejected. Rejected text is not retained or sent to Luna, and the problem detail never repeats it.

Credential-shaped text other than ScreenRig credentials (bearer tokens, cloud and API keys, private keys) is replaced with [redacted] before storage; ScreenRig credential material returns invalid_request. A new conversation starts one Slack thread; follow-ups stay in it. Requests with the same key replay for 24 hours, a refusal included.

Authentication
projectBearer
Request body
SupportWrite
Operation ID
createSupportConversationInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
Idempotency-Keyheaderrequired

Request body fields

FieldDescription
body (required, string)minLength: 1 maxLength: 4000
human_requested (optional, boolean)

Ask for a person, which pauses Luna and waits for staff. It counts only where a person can join (human_available: Education, Premium and Enterprise); on Standard and Plus it is ignored and Luna answers. default: false

Request template and responses
shell · request template
curl --request POST --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --header 'Idempotency-Key: REQUEST_ID' --header 'Content-Type: application/json' --data '@request.json' 'https://api.screenrig.ai/api/projects/PROJECT_ID/support/conversations'

Responses

StatusMeaningBody and headers
201Support result.SupportSubmission (application/json)
422The message was refused by screening: submission_too_short or submission_unclear (the opening message only) or submission_rejected. The detail never repeats the text.Problem (application/problem+json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/projects/{project_id}/reviews

List Reviews In Project

The project's reviews (docs/reviews.md): playlist and screen changes proposed under Propose access, and for an ad network the creatives buyers submitted (kind ad_creative).

Newest first, at most limit (default 50, at most 100) per page; pass next_cursor back as cursor with the same filters. state pending (the default), decided (every other state) or all; kind narrows to one kind.

A dashboard session reads every kind; a bearer reads the kinds its capabilities cover (playlists for playlist_change, screens for screen_change, advertising for ad_creative), and a kind it cannot read is an empty page. pending_count counts the pending reviews of every kind the caller sees.

Authentication
projectBearer
Request body
none
Operation ID
listReviewsInProject

Parameters

NameSend inRequired?Description
project_idpathrequired
statequeryoptional
kindqueryoptional
limitqueryoptional
cursorqueryoptional
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' 'https://api.screenrig.ai/api/projects/PROJECT_ID/reviews'

Responses

StatusMeaningBody and headers
200One page of reviews.ReviewList (application/json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/projects/{project_id}/card-data/{key}

Project Scoped_get Card Data

Returns the document and its revision. ETag is the revision, for If-Match on the next write.

Authentication
projectBearer
Request body
none
Operation ID
projectScoped_getCardData

Parameters

NameSend inRequired?Description
project_idpathrequired
ScreenRig-ProjectheaderoptionalDeprecated for one release. Must be consistent with the JWT projects grants; adds Deprecation and Warning headers. No token exchange.
keypathrequiredCard data key. May not start with feed:.
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' 'https://api.screenrig.ai/api/projects/PROJECT_ID/card-data/KEY'

Responses

StatusMeaningBody and headers
200Card data documentCardDataEntry (application/json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
PUT/api/projects/{project_id}/card-data/{key}

Project Scoped_put Card Data

Creates or replaces a card data document. When card placements in the project's playlists bind the key, the document must hold only each bound card's dynamic properties and validate against them; otherwise the write is refused with card_data_invalid naming the card and the property path, and nothing changes. A key no placement binds accepts any JSON object.

Every string that begins with media: is a media reference, media:<id>, for a card to draw (a photo); on any key it must name a ready, approved image in this project, at most 256 distinct media per document, or the write is refused with card_media_invalid naming the property path and media_id.

Screens whose content reads the key may then fetch those media from GET /media/{media_id}. Screens showing a placement that reads the key receive screen.card_data_changed and refetch it in place; the project log records kv.updated with a card_data_entry resource, which never reaches a Player.

Limits, quota, metering, revisions and idempotency are the application K/V store's.

Agent and webhook writes are also rate limited, per organization by plan (Standard and Plus 60 a minute, Education and Premium 600, Enterprise 3,000) and to 60 a minute per key on every plan; a write over a limit is refused with rate_limited and Retry-After, and is not metered.

Authentication
projectBearer
Request body
CardDataWrite
Operation ID
projectScoped_putCardData

Parameters

NameSend inRequired?Description
project_idpathrequired
ScreenRig-ProjectheaderoptionalDeprecated for one release. Must be consistent with the JWT projects grants; adds Deprecation and Warning headers. No token exchange.
keypathrequiredCard data key. May not start with feed:.
If-MatchheaderoptionalOptional positive resource revision. Omit to create or overwrite a key; a supplied stale revision is revision_conflict.
Idempotency-KeyheaderoptionalOmit for a fresh operation. Supply and reuse a key to deduplicate retries; the CLI manages keys automatically.

Request body fields

FieldDescription
document (required, object)

The card data document: a JSON object of at most 1 MiB. When a card placement binds the key it holds only that card's dynamic properties. A string that begins with media: is a media reference, media:<id>, naming a ready, approved image in this project.

expires_at (optional, string)Absolute expiry; omitted data never expires. format: "date-time"
ttl_seconds (optional, integer)

TTL from the first committed write. Mutually exclusive with expires_at. A retry preserves the original expiry. Omitting both clears expiry.

Size it to the writer's schedule: when a card's document expires with no write to renew it while a screen shows the card, the card goes blank and the card_data_stale notification condition tells the project, so a job that stopped is noticed. minimum: 1 maximum: 31536000

Request template and responses
shell · request template
curl --request PUT --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --header 'Content-Type: application/json' --data '@request.json' 'https://api.screenrig.ai/api/projects/PROJECT_ID/card-data/KEY'

Responses

StatusMeaningBody and headers
200Card data documentCardDataEntry (application/json)
429

Stable rate_limited problem. Retry only after the authoritative Retry-After interval. Fixed-window denials also include the applicable RateLimit-Policy and RateLimit members; concurrency and byte-budget denials omit those optional disclosures.

Problem (application/problem+json); headers: Retry-After, RateLimit-Policy, RateLimit
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
DELETE/api/projects/{project_id}/card-data/{key}

Project Scoped_delete Card Data

Deletes a card data document. A card bound to the key is hidden on glass until a document is written again.

Authentication
projectBearer
Request body
none
Operation ID
projectScoped_deleteCardData

Parameters

NameSend inRequired?Description
project_idpathrequired
ScreenRig-ProjectheaderoptionalDeprecated for one release. Must be consistent with the JWT projects grants; adds Deprecation and Warning headers. No token exchange.
keypathrequiredCard data key. May not start with feed:.
If-MatchheaderoptionalOptional positive resource revision. Omit to write the current resource; a supplied stale revision is revision_conflict.
Idempotency-KeyheaderoptionalOmit for a fresh operation. Supply and reuse a key to deduplicate retries; the CLI manages keys automatically.
Request template and responses
shell · request template
curl --request DELETE --header 'Authorization: Bearer [SCREENRIG_TOKEN]' 'https://api.screenrig.ai/api/projects/PROJECT_ID/card-data/KEY'

Responses

StatusMeaningBody and headers
204Deletedno body
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/projects/{project_id}/feeds/{family}

Project Scoped_get Feed

Reads a shared third-party feed document: the same document a built-in card placement with the same params reads (docs/feeds.md).

Query parameters normalize into the card's feed key, named by the ScreenRig-Feed-Key header: weather, airquality and alerts take lat and lon (rounded to a 0.25 degree cell); earthquakes lat, lon, radius_km (10 to 20000, default 500), min_magnitude (0 to 9, default 2.5) and hours (1 to 168, default 24); cyclones basins (comma separated at, ep, cp, wp; default all) and optionally lat, lon and radius_km (the storms near that place); tides station (a NOAA tide prediction station id such as 9414290) or lat and lon (the nearest station within 100 km, else invalid_request); launches no parameters (the next launches worldwide); rates base (an ECB reference currency, default EUR); crypto symbols (CoinGecko ids or tickers, comma separated, at most 20) and currency (default usd); headlines url (an http or https RSS or Atom URL); drugalerts (screenrig.drugalerts/v1) the recent recall reports of a country: country (us, ca or gb, required) and category (drug, the default, or food); respiratory (screenrig.respiratory/v1) the weekly flu, COVID-19 and RSV activity of a place: country (us or gb, required) and region (a US state, territory or DC by name or postal code, or England or a UKHSA region; the nation when empty).

The request never calls the provider. 200 is the document (schema, fetchedAt, attribution and the family's fields, as the cards contract defines them); its ETag is the sha256 of the bytes and If-None-Match answers 304; Cache-Control max-age runs to the next scheduled fetch. 202 means no document yet: the read registered demand, and the feed worker fetches the key within about a minute (Retry-After).

An API read keeps a key fetched for 24 hours. An organization registers at most 50 new keys a day across its projects (rate_limited past it). A family with no source on this deployment answers not_found.

Authentication
projectBearer
Request body
none
Operation ID
projectScoped_getFeed

Parameters

NameSend inRequired?Description
project_idpathrequired
ScreenRig-ProjectheaderoptionalDeprecated for one release. Must be consistent with the JWT projects grants; adds Deprecation and Warning headers. No token exchange.
familypathrequiredThe feed family.
latqueryoptional
lonqueryoptional
radius_kmqueryoptional
min_magnitudequeryoptionalearthquakes: the least magnitude.
hoursqueryoptionalearthquakes: the window in hours.
basinsqueryoptionalcyclones: comma separated at, ep, cp, wp.
stationqueryoptionaltides: a NOAA tide prediction station id, such as 9414290. Without it, lat and lon pick the nearest station within 100 km.
basequeryoptional
symbolsqueryoptional
currencyqueryoptional
urlqueryoptional
countryqueryoptionaldrugalerts: us, ca or gb. respiratory: us or gb. Both require it.
categoryqueryoptionaldrugalerts: drug (default) or food.
regionqueryoptionalrespiratory: a US state, territory or DC by name or postal code, or England or a UKHSA region; the nation when empty.
If-None-Matchheaderoptional
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' 'https://api.screenrig.ai/api/projects/PROJECT_ID/feeds/FAMILY'

Responses

StatusMeaningBody and headers
200Feed documentFeedDocument (application/json); headers: ETag, ScreenRig-Feed-Key
202No document yet; the feed worker fetches the key on its next pass.FeedPending (application/json); headers: Retry-After, ScreenRig-Feed-Key
304The document matches If-None-Match.no body
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/projects/{project_id}/advertising/networks/{seller_project_id}/inventory

Project Scoped_list Advertising Joined Inventory

Opted-in inventory and reusable slots inside the caller's membership. Never exposes the seller's screenshots, playlists, or project-wide data.

Authentication
projectBearer OR dashboardSession
Request body
none
Operation ID
projectScoped_listAdvertisingJoinedInventory

Parameters

NameSend inRequired?Description
project_idpathrequired
ScreenRig-ProjectheaderoptionalDeprecated for one release. Must be consistent with the JWT projects grants; adds Deprecation and Warning headers. No token exchange.
seller_project_idpathrequired
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --cookie cookies.txt --cookie-jar cookies.txt 'https://screenrig.ai/api/projects/PROJECT_ID/advertising/networks/SELLER_PROJECT_ID/inventory'

Responses

StatusMeaningBody and headers
200Permitted inventory and slots.AdvertisingJoinedInventory (application/json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
GET/api/projects/{project_id}/agents/self

Project Scoped_get Current Agent

Returns the agent installation linked to the calling project bearer plus connection_ready. A project is ready when at least one member has a passkey or password. Identity status is diagnostic and does not debit the API meter.

Authentication
projectBearer
Request body
none
Operation ID
projectScoped_getCurrentAgent

Parameters

NameSend inRequired?Description
project_idpathrequired
ScreenRig-ProjectheaderoptionalDeprecated for one release. Must be consistent with the JWT projects grants; adds Deprecation and Warning headers. No token exchange.
Request template and responses
shell · request template
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' 'https://api.screenrig.ai/api/projects/PROJECT_ID/agents/self'

Responses

StatusMeaningBody and headers
200Current agent and project connection readiness.AgentSelfStatus (application/json); headers: Cache-Control
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
POST/api/projects/{project_id}/agents/self/disconnect

Project Scoped_disconnect Current Agent

Revokes only the calling project membership and its project token, preserving the global identity, other memberships, project and content. Repeating with the same cryptographically valid revoked bearer is a no-op success. Disconnecting the last active agent returns agent_lockout_risk unless allow_last_agent is explicit. Does not debit the API meter.

An agent access JWT, Read only included, disconnects the agent from its token's project; the membership ends, the project's consent leaves the agent's grants and that identity/project pair is cut off for older access tokens. Other projects in the token keep working. A retry with the same JWT after the disconnect is a no-op success.

Authentication
revocableAgentBearer
Request body
AgentDisconnectRequest
Operation ID
projectScoped_disconnectCurrentAgent

Parameters

NameSend inRequired?Description
project_idpathrequired
ScreenRig-ProjectheaderoptionalDeprecated for one release. Must be consistent with the JWT projects grants; adds Deprecation and Warning headers. No token exchange.

Request body fields

FieldDescription
allow_last_agent (optional, boolean)Explicitly accept loss of the last active agent bearer. A registered dashboard passkey remains independent administrative authority. default: false
Request template and responses
shell · request template
curl --request POST --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --header 'Content-Type: application/json' --data '@request.json' 'https://api.screenrig.ai/api/projects/PROJECT_ID/agents/self/disconnect'

Responses

StatusMeaningBody and headers
204Agent disconnected.no body; headers: Cache-Control
401

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
409

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)
default

Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value.

Problem (application/problem+json)