{"openapi":"3.1.0","info":{"title":"Screenbird API","version":"1.0.0","description":"Control Screenbird digital signage screens from your own tools: list screens and content, push content to a screen or sub-screen, and activate Scenes (named moments that switch many screens at once). Authenticate with an API token from Settings > Connections. A token acts on behalf of the person who created it, in one team, limited to its scopes.","contact":{"name":"Screenbird support","url":"https://screenbird.app"}},"servers":[{"url":"https://api.screenbird.app/v1"}],"security":[{"bearer":[]}],"paths":{"/me":{"get":{"summary":"Who am I","description":"The token, account and team this token acts in.","operationId":"getMe","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Me"}}}},"400":{"description":"Invalid request (error.code says what, error.field which field)"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/screens":{"get":{"summary":"List screens","description":"Screens of the token's team, with sub-screens, online status and what is live on each.","operationId":"listScreens","x-scopes":["screens:read"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"screens":{"type":"array","items":{"$ref":"#/components/schemas/Screen"}}}}}}},"400":{"description":"Invalid request (error.code says what, error.field which field)"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/screens/{screenId}/push":{"post":{"summary":"Push content to a screen or sub-screen","description":"Shows content on a screen (or one of its sub-screens) on top of its normal content. Without 'until' it stays until you release it. A split screen only accepts pushes to a sub-screen.","operationId":"pushToScreen","x-scopes":["screens:push"],"parameters":[{"$ref":"#/components/parameters/screenId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["content_id"],"properties":{"content_id":{"type":"string","format":"uuid","description":"From GET /content."},"subscreen_id":{"type":"string","format":"uuid","description":"Target one sub-screen of a split screen."},"until":{"type":"string","description":"When to return to normal, at most 90 days ahead. Without an offset it is the local time of the account (GET /me, account.timezone), for example 2026-10-23T18:00; or include an offset, such as 2026-10-23T18:00:00+02:00. Omit to keep it until released."},"scaling":{"type":"string","enum":["cover","contain","fill","none"]}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"override_id":{"type":"string"},"live":{"$ref":"#/components/schemas/Live"},"timezone":{"type":"string","description":"Only when 'until' was given: the account's time zone; live.ends_at is in that zone, with its offset."}}}}}},"400":{"description":"Invalid request (error.code says what, error.field which field)"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/screens/{screenId}/release":{"post":{"summary":"Return a screen or sub-screen to normal","operationId":"releaseScreen","x-scopes":["screens:push"],"parameters":[{"$ref":"#/components/parameters/screenId"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"subscreen_id":{"type":"string","format":"uuid"}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"released":{"type":"integer"}}}}}},"400":{"description":"Invalid request (error.code says what, error.field which field)"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/content":{"get":{"summary":"List content","description":"Files, designs, apps, split screens and playlists the team can show. Newest first.","operationId":"listContent","x-scopes":["content:read"],"parameters":[{"name":"q","in":"query","schema":{"type":"string"},"description":"Search by name."},{"name":"type","in":"query","schema":{"type":"string"},"description":"Comma separated: file, design, app, split_screen, playlist."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":500,"default":100}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Content"}}}}}}},"400":{"description":"Invalid request (error.code says what, error.field which field)"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/scenes":{"get":{"summary":"List scenes","description":"Scenes of the team with their targets and whether each scene is fully live.","operationId":"listScenes","x-scopes":["scenes:read"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"scenes":{"type":"array","items":{"$ref":"#/components/schemas/Scene"}},"last_activated":{"type":["string","null"]}}}}}},"400":{"description":"Invalid request (error.code says what, error.field which field)"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/scenes/{sceneId}/activate":{"post":{"summary":"Activate a scene","description":"Every screen and sub-screen in the scene switches to its content (or back to normal for a target set to normal). Places that still show this scene but are no longer one of its targets go back to normal (released). Screens that were never in the scene are not touched. Running it again puts changes to the scene live.","operationId":"activateScene","x-scopes":["scenes:run"],"parameters":[{"$ref":"#/components/parameters/sceneId"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SceneRun"}}}},"400":{"description":"Invalid request (error.code says what, error.field which field)"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/scenes/{sceneId}/release":{"post":{"summary":"Return a scene's screens to normal","operationId":"releaseScene","x-scopes":["scenes:run"],"parameters":[{"$ref":"#/components/parameters/sceneId"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"released":{"type":"integer"}}}}}},"400":{"description":"Invalid request (error.code says what, error.field which field)"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/scenes/release-all":{"post":{"summary":"Return everything to normal","description":"Ends all scenes and pushes on the team's screens. Running screen mirror sessions are kept.","operationId":"releaseAll","x-scopes":["scenes:run"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"released":{"type":"integer"}}}}}},"400":{"description":"Invalid request (error.code says what, error.field which field)"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/scenes/next":{"post":{"summary":"Activate the next scene","description":"Activates the scene after the last activated one, in list order (wraps around).","operationId":"activateNextScene","x-scopes":["scenes:run"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SceneRun"}}}},"400":{"description":"Invalid request (error.code says what, error.field which field)"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/designs":{"post":{"summary":"Create a design with AI","description":"Creates a design from a description with Screenbird's AI designer (template, texts, photos) and saves it in the team's files. Uses the account's monthly AI budget; at most 20 per hour per account. Can take up to a minute.","operationId":"createDesign","x-scopes":["designs:write"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["brief"],"properties":{"brief":{"type":"string","maxLength":4000,"description":"What the design must show, with all texts. For a list whose entries are not known yet, give the number of entries as digits (\"a menu with 10 dishes\"); never placeholders or made-up names: the designer adds placeholders itself."},"orientation":{"type":"string","enum":["landscape","portrait"]},"name":{"type":"string","maxLength":100},"language":{"type":"string","description":"Two-letter language code of the texts."},"template_id":{"type":"string","description":"Optional template to build on."}}}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"design":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"orientation":{"type":"string"},"editor_url":{"type":"string"},"placeholders":{"type":"array","items":{"type":"string"}}}}}}}}},"400":{"description":"Invalid request (error.code says what, error.field which field)"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"budget_exceeded: the account's monthly AI budget is used up"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"description":"id_collision: try again"},"429":{"description":"design_limit (20 designs per hour per account; Retry-After and error.retry_after give the seconds to wait) or rate_limited"},"502":{"description":"design_failed: the design could not be made; try again or change the brief"}}}},"/help":{"get":{"summary":"Search the help center","description":"Up to 3 help articles for a question, in the requested language: title, summary and link; with full=1 also the complete text. Works for any valid token, also when the account has no active subscription.","operationId":"searchHelp","parameters":[{"name":"q","in":"query","schema":{"type":"string","maxLength":200}},{"name":"slugs","in":"query","schema":{"type":"string"},"description":"Comma-separated article slugs instead of a search."},{"name":"lang","in":"query","schema":{"type":"string"}},{"name":"full","in":"query","schema":{"type":"string","enum":["1","true"]},"description":"Include the complete article text."}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"articles":{"type":"array","items":{"type":"object","properties":{"slug":{"type":"string"},"title":{"type":"string"},"url":{"type":["string","null"]},"summary":{"type":"string"},"content":{"type":"string","description":"Only with full=1."}}}}}}}}},"400":{"description":"Invalid request (error.code says what, error.field which field)"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/install-steps":{"get":{"summary":"Install steps for a player","description":"Works for any valid token, also when the account has no active subscription.","operationId":"getInstallSteps","parameters":[{"name":"device","in":"query","required":true,"schema":{"type":"string","enum":["signage_stick","fire_tv","android_tv","windows","macos","linux","raspberry_pi","browser"]}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"device":{"type":"string"},"steps":{"type":"array","items":{"type":"string"}},"then":{"type":"string"}}}}}},"400":{"description":"Invalid request (error.code says what, error.field which field)"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/devices/check":{"get":{"summary":"Does a device work with Screenbird","description":"Works for any valid token, also when the account has no active subscription.","operationId":"checkDevice","parameters":[{"name":"device","in":"query","required":true,"schema":{"type":"string","maxLength":80}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["works","coming_soon","does_not_work","works_in_browser","unknown"]},"explanation":{"type":"string"}}}}}},"400":{"description":"Invalid request (error.code says what, error.field which field)"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/live":{"get":{"summary":"What is live","description":"Every screen and sub-screen that shows a scene or push. Anything not listed shows its normal content.","operationId":"getLive","x-scopes":["screens:read","scenes:read"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"live":{"type":"array","items":{"$ref":"#/components/schemas/LiveSlot"}}}}}}},"400":{"description":"Invalid request (error.code says what, error.field which field)"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/events":{"get":{"summary":"Live updates (WebSocket)","description":"Upgrade to a WebSocket with the same Authorization header. Messages: {type:'hello', ping, interval_seconds}, {type:'events', events:[{table, op, row}]} for the tables screen_live, scenes, scene_targets and scene_schedules (scenes:read) and screens, screen_zones and devices (screens:read; online status, new or split screens; these rows carry only their keys, or none for devices: treat them as a signal and fetch GET /screens again), and {type:'resync'} when you should fetch GET /scenes and GET /live again. Send exactly {\"type\":\"ping\"} at least every 120 seconds (every 30 is a good interval); the answer is {\"type\":\"pong\"}. Close codes: 4001 no ping for 120 seconds, 4008 too many connections for this token (at most 5; the oldest is closed), 4011 the token was revoked or lost its access, 1013 try again later. Reconnect after 4001, 4008 and 1013 with a growing delay; after 4011 stop.","operationId":"events","x-scopes":["screens:read","scenes:read"],"responses":{"101":{"description":"Switching protocols"},"400":{"description":"Invalid request (error.code says what, error.field which field)"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}}},"components":{"securitySchemes":{"bearer":{"type":"http","scheme":"bearer","description":"API token from Settings > Connections (sbk_...), or the credential of a connected app (sbo_...)."}},"parameters":{"screenId":{"name":"screenId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},"sceneId":{"name":"sceneId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}},"responses":{"Unauthorized":{"description":"Missing, invalid or revoked token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Forbidden":{"description":"Missing scope or permission, account inactive, or Scenes turned off.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"RateLimited":{"description":"Too many calls. Limits: about 120 calls per minute per token; 120 pushes per minute per token and 600 per account; 120 scene actions per minute per team and 600 per account; 120 GET /scenes and 120 releases per minute per token; 20 designs per hour per account. Wait for Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"field":{"type":"string","description":"The request field that is wrong, when known."},"allowed":{"type":"array","items":{"type":"string"},"description":"The values that field accepts, when it is a fixed list."},"retry_after":{"type":"integer","description":"Seconds to wait (design_limit)."}}}}},"Me":{"type":"object","properties":{"credential":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"kind":{"type":"string"},"scopes":{"type":"array","items":{"type":"string"}}}},"account":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"scenes_enabled":{"type":"boolean"},"timezone":{"type":"string"}}},"team":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}}}}},"Live":{"type":"object","properties":{"kind":{"type":"string","enum":["normal","push","scene","mirror"]},"scene":{"type":["object","null"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"revision":{"type":"integer"}}},"content":{"type":["object","null"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"type":{"type":"string"}}},"until_released":{"type":"boolean"},"ends_at":{"type":["string","null"],"format":"date-time"}}},"Screen":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"paired":{"type":"boolean"},"online":{"type":"boolean"},"orientation":{"type":["string","null"]},"width":{"type":["integer","null"]},"height":{"type":["integer","null"]},"locked":{"type":"boolean"},"content":{"type":["object","null"]},"live":{"$ref":"#/components/schemas/Live"},"subscreens":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"width":{"type":"integer"},"height":{"type":"integer"},"content":{"type":["object","null"]},"live":{"$ref":"#/components/schemas/Live"}}}}}},"Content":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"type":{"type":"string","enum":["file","design","app","split_screen","playlist"]},"file_type":{"type":["string","null"]},"thumbnail_url":{"type":["string","null"]},"updated_at":{"type":"string","format":"date-time"}}},"Scene":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"color":{"type":"string","enum":["green","blue","purple","orange","red","teal","pink","gray"]},"position":{"type":"integer"},"revision":{"type":"integer"},"status":{"type":"object","properties":{"state":{"type":"string","enum":["live","stale","partial","off","empty"],"description":"live = every target shows this scene; stale = changed and the change is not live yet (activate again to apply it); partial = some targets show it; off = none."},"deviating":{"type":"array","items":{"type":"object","properties":{"screen_id":{"type":"string"},"subscreen_id":{"type":["string","null"]},"reason":{"type":"string","enum":["subscreen_removed","screen_split","screen_locked","outdated","other_content","normal"]}}}}}},"targets":{"type":"array","items":{"type":"object","properties":{"screen_id":{"type":"string"},"subscreen_id":{"type":["string","null"]},"content":{"type":["object","null"]},"normal":{"type":"boolean"}}}}}},"SceneRun":{"type":"object","properties":{"scene":{"type":["object","null"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"revision":{"type":"integer"}}},"applied":{"type":"integer","description":"Targets that now show the scene."},"skipped":{"type":"integer","description":"Targets that could not be set (see results)."},"released":{"type":"integer","description":"Places that showed this scene but are no longer a target, put back to normal."},"results":{"type":"array","items":{"type":"object","properties":{"screen_id":{"type":"string"},"subscreen_id":{"type":["string","null"]},"status":{"type":"string","enum":["ok","skipped"]},"reason":{"type":"string","enum":["screen_not_found","subscreen_removed","screen_split","screen_locked","source_removed","source_invalid","mirror_active"]}}}}}},"LiveSlot":{"type":"object","properties":{"screen_id":{"type":"string"},"subscreen_id":{"type":["string","null"]},"kind":{"type":"string","enum":["push","scene","mirror"]},"scene_id":{"type":["string","null"]},"scene_revision":{"type":["integer","null"]},"content_id":{"type":["string","null"]},"until_released":{"type":"boolean"},"ends_at":{"type":["string","null"],"format":"date-time"}}}}}}