Skip to content

API reference

REST reference for the Shadow API — auth, sites, captures, tutorials, videos, and webhooks.

The Shadow API is a REST JSON API mounted under /api. Authentication uses session cookies for browser clients, and long-lived bearer tokens for server-to-server calls.

All timestamps are ISO-8601 UTC. All id values are 24-character opaque identifiers unless stated otherwise.

Authentication

GET /api/orgs HTTP/1.1
Host: byshadow.ai
Cookie: better-auth.session_token=...

For server integrations, send a bearer token issued from the dashboard:

GET /api/sites/:siteId/videos HTTP/1.1
Authorization: Bearer ta_...

Organizations

List organizations

GET /api/orgs

Response:

[
  { "id": "661fcc...", "name": "Acme Inc", "slug": "acme", "plan": "growth" }
]

Sites

Create a site

POST /api/orgs/:orgId/sites
Content-Type: application/json

{ "name": "My SaaS", "url": "https://app.example.com" }

Response includes the secret key once:

{ "id": "...", "publicKey": "...", "apiKeySecret": "ta_secret_..." }

Verify install

POST /api/sites/:siteId/verify-install

Returns { verified: true, lastEventAt } once the SDK has posted at least one event.

Tutorials

Create a tutorial

POST /api/sites/:siteId/tutorials
Content-Type: application/json

{ "title": "How to create a project", "prompt": "Walk through creating a project from scratch." }

Compose the storyboard

POST /api/sites/:siteId/tutorials/:tutorialId/compose

Render the video

POST /api/sites/:siteId/tutorials/:tutorialId/render

Videos

List rendered videos

GET /api/sites/:siteId/videos

Get video detail (with presigned playback URL)

GET /api/sites/:siteId/videos/:videoId

Update video (publish, rename, feature)

PATCH /api/sites/:siteId/videos/:videoId
Content-Type: application/json

{ "embedEnabled": true, "isMarketingDemo": false, "title": "New title" }

Public endpoints

These endpoints don’t require authentication and are safe to call from browsers.

Get a public video

GET /api/public/videos/:slug

Returns the playback URL, title, duration, and brand overlay.

Record a video event (beacon)

POST /api/public/videos/:slug/events
Content-Type: application/json

{ "sessionId": "...", "event": "progress_50", "positionMs": 34200 }

Marketing demo

GET /api/public/marketing-demo

Returns { slug, title } for the currently featured demo video, or nulls.

Contact form

POST /api/public/contact
Content-Type: application/json

{ "name": "...", "email": "...", "company": "...", "message": "..." }

Errors

All errors return a structured JSON body:

{ "error": { "code": "NOT_FOUND", "message": "Video not found" } }

Common codes: UNAUTHORIZED, FORBIDDEN, NOT_FOUND, VALIDATION, RATE_LIMITED, INTERNAL.