ShotDemo

ShotDemo

The ShotDemo API and MCP server

Last updated: 13 October 2026

ShotDemo has a REST API and an MCP server. With them, a script, a release job or an AI assistant such as Claude Code, Cursor or VS Code can make a demo from a website's address or from screenshots, change its words, put in new screenshots after a release, translate it, publish it, make links for one person, and read the analytics and the leads. Both are free to use, like building demos, and the app's own rules hold: one live demo is free, and more, or the paid features, come with buying a demo ($12 once per demo).

Keys

An admin of a workspace makes a key in the app: Settings, API and AI agents. Name it after what will use it ("Claude", "Release script"). The key is shown once, when it is made; ShotDemo keeps only a fingerprint of it, so copy it then. A key:

  • works in its own workspace only, even when the person who made it is in other workspaces too;
  • acts as the person who made it, with their role there: an admin or a creator changes and publishes demos, a viewer only reads;
  • stops when it is revoked in the same place, or when the person who made it leaves the workspace;
  • never manages the workspace: people, keys, settings and payments stay in the app.

Send the key with every call, in a header:

Authorization: Bearer sd_...

Keep keys on servers and in your own tools, never in a web page: anyone who has a key can do what it does. A call without a working key answers 401.

Connect an AI assistant (MCP)

The MCP server is at https://app.shotdemo.com/mcp (Streamable HTTP). An assistant that connects by signing in (OAuth 2.1, as the MCP specification describes) needs no key: add the address as a custom connector, sign in to ShotDemo when it asks, pick the workspace and allow it. The connection then shows in Settings, API and AI agents as "(name) (connected)", where you disconnect it. Other assistants take your key.

Claude Code, in a terminal:

claude mcp add --transport http shotdemo https://app.shotdemo.com/mcp --header "Authorization: Bearer sd_..."

Cursor, in ~/.cursor/mcp.json (or .cursor/mcp.json in a project):

{
  "mcpServers": {
    "shotdemo": {
      "url": "https://app.shotdemo.com/mcp",
      "headers": { "Authorization": "Bearer sd_..." }
    }
  }
}

VS Code, in .vscode/mcp.json:

{
  "servers": {
    "shotdemo": {
      "type": "http",
      "url": "https://app.shotdemo.com/mcp",
      "headers": { "Authorization": "Bearer sd_..." }
    }
  }
}

Then ask in your own words, for example: "Make a ShotDemo demo of https://example.com, translate it into Spanish and give me the link to edit it", or "Which of my demos had the most views this month, and where did viewers stop?" The assistant has these tools:

Tool What it does
get_account The workspace, the key's role, whether its free live demo is used, whether it takes teammates, the price of a demo
list_demos The demos, with their status and their share, embed and editor links
get_demo One demo's steps: their words, spoken lines and screenshots
create_demo_from_website Captures up to ten pages of a public website into a new demo, the AI writing its words
get_job How a capture or a translation is getting on, and the demo it made
edit_steps Changes the words of steps: titles, the words on hotspots, spoken lines, chapters
check_demo A score out of 100 and what to fix before sharing, worst first
translate_demo Translates a demo into any of 32 other languages, each with a voice of its own
publish_demo Puts the draft on the air
create_personal_link A link for one person, whose views count as theirs (a bought demo's feature)
get_demo_analytics Views, completion, time, sources, devices, and how many viewers reached each step
get_workspace_analytics Every demo's views, completion and leads, most viewed first, and the totals
list_showcases The showcases (pages of several demos), whether live, their views and links
create_showcase A showcase of chosen demos, as a list, a checklist, a gallery or paths
tag_demo Sets a demo's tags, which the app filters its demos by
list_leads The people who filled in a demo's form

Changes always go to the draft, as in the editor. Viewers see them after the demo is published.

The REST API

Every address below starts with https://app.shotdemo.com/api/v1. Requests and answers are JSON, except screenshots, which go as a multipart form. Times are Unix seconds. A refused call answers {"detail": "..."} with a sentence saying why, and its status says what kind of refusal it is:

Status Meaning
401 No key, a revoked key, or a key whose maker left the workspace
402 The demo needs buying first (a fourth live demo, a lead form or password, personal links)
403 The key's role cannot do this (a viewer changing a demo)
404 No such demo, step or job in this workspace
409 The demo changed since the rev you sent
422 Something in the request: the answer names it
429 Too many calls at once (wait two seconds), or the day's allowance of captures or AI requests is used

GET /me

The key's workspace, its role, its name, and the plan: free_live of free_live_limit demos live, price_per_demo, and teammates (whether the workspace takes teammates: once it has bought a demo).

GET /demos

The workspace's demos, last changed first. ?q= keeps those whose title or a tag contains it; ?archived=true lists the archive. Each demo:

{
  "id": "k3j9x2m1q8wz",
  "title": "Release 4.2 tour",
  "status": "live",
  "step_count": 9,
  "bought": false,
  "created": 1760241600.0,
  "updated": 1760245200.0,
  "published_at": 1760245200.0,
  "share_url": "https://app.shotdemo.com/demo/k3j9x2m1q8wz",
  "embed_url": "https://app.shotdemo.com/embed/k3j9x2m1q8wz",
  "edit_url": "https://app.shotdemo.com/demos/k3j9x2m1q8wz",
  "thumbnail": "https://app.shotdemo.com/m/...",
  "tags": ["Onboarding"]
}

status is draft, live, edited (live, with changes not published yet) or archived.

POST /demos

A demo from screenshots, one step each, in the order sent. Send files (up to 100), and optionally title, write=true to have the AI write each step's words, use_case (marketing or instructional) and language (a code such as en, es, de, ja).

curl https://app.shotdemo.com/api/v1/demos \
  -H "Authorization: Bearer sd_..." \
  -F title="Release 4.2 tour" -F write=true \
  -F files=@1-dashboard.png -F files=@2-new-report.png -F files=@3-share.png

The answer is {"demo": {...}} with the demo and its steps, and, with write, a job for the writing.

POST /demos/from-website

{"url": "https://example.com", "title": "", "max_pages": 6, "use_case": "marketing", "language": "en"}. ShotDemo captures the site's pages (public sites only), makes a demo of them and writes the words. The answer is a job; read it until its state is done, when it names the demo_id.

GET /jobs/{id}

state (queued, running, done, failed, cancelled), progress from 0 to 1, the last message, and the demo_id and edit_url of the demo it made or changed. A failed job says why in error.

GET /demos/{id}

The demo with its draft's steps. Each step has its id, its kind (image, video or chapter), its title and its spoken line (voice); an image step its text (the words on its first hotspot), its hotspots and its image; a chapter its body and buttons. rev is the draft's revision.

PATCH /demos/{id}/steps

Changes the words of steps. Only the fields you send change:

{
  "steps": [
    { "id": "s1a2b3", "title": "Start a report", "text": "Click **New report**", "voice": "Start with a new report." },
    { "id": "c9d8e7", "body": "Two minutes, five clicks." }
  ],
  "rev": 14
}

Words can use bold, italics, links written [words](https://...), and variables such as {{ company }}, which a personal link fills in. A new spoken line is voiced when the demo is published. Send rev to be told (409) when someone changed the demo meanwhile; leave it out to write anyway.

GET /demos/{id}/check

The demo check: ?purpose= is marketing (on a website, the default), sales (after a sales call) or instructional (onboarding and training). The answer holds the score out of 100, a verdict, and the findings, worst first, each with its severity (high, medium, low), a title, why it matters, the steps it concerns and a suggested_fix. It reads the draft, and once 20 people watched the demo, also where they stop.

PUT /demos/{id}/steps/{step}/image

A new screenshot for an image step, as the multipart field file, for when a release changed the screen. The step keeps its hotspots, notes and blurs where they were, so the new screenshot must have the same shape as the old one (within 2 percent); add ?force=true to put in one of another shape, then check the step in the editor. Blurs cover the same places as before: if the screen's layout moved, check them before you publish.

This keeps demos true to the product without opening the editor:

# after a release: new screenshots of the same screens, then publish
curl -X PUT https://app.shotdemo.com/api/v1/demos/k3j9x2m1q8wz/steps/s1a2b3/image \
  -H "Authorization: Bearer sd_..." -F file=@dashboard.png
curl -X POST https://app.shotdemo.com/api/v1/demos/k3j9x2m1q8wz/publish \
  -H "Authorization: Bearer sd_..."

POST /demos/{id}/translations

{"language": "es", "missing": false}: a job in which the AI translates the draft's words; with missing, only the words added since the last translation. Viewers get the demo in their browser's language, or pick one in the player.

POST /demos/{id}/publish and /unpublish

Publishing puts the draft on the air and answers {"demo": {...}, "notes": []}; a note says when something could not be done, such as a spoken line without a voice yet. It answers 402 for a fourth free demo, or for a demo with a lead form or a password that is not bought.

POST /demos/{id}/links

{"name": "Jane Doe", "email": "jane@acme.com", "company": "Acme", "variables": {"plan": "Team"}, "expires_days": 30}: a link for one person, a bought demo's feature. Its views count as theirs, and its values fill the demo's variables, such as {{ name }} and {{ plan }}. The answer carries its url. When the demo shows a viewer's logo, ShotDemo reads their company's logo from "website" (or, without one, their work email's domain) and the link shows it.

PUT /demos/{id}/tags

{"tags": ["Onboarding", "Sales"]}: the demo's tags, all at once ([] removes them; at most 12, each up to 30 characters). The answer is the demo.

GET /demos/{id}/analytics

?days=30 (0 for all time). The summary holds views, unique, engagement, completion, avg_seconds, leads and the views by day, source, country and device; steps says how many viewers reached each step. Your workspace's own views are left out.

GET /showcases and POST /showcases

The workspace's showcases, each with its title, whether it is live, how many demos, its views, its url and its edit_url. To make one: {"title": "Every tour", "demo_ids": ["k3j9x2m1q8wz", "..."], "layout": "checklist", "live": false}, with layout one of list, checklist, gallery or paths. Demos of another workspace are left out.

GET /leads

The people who filled in a form, newest first: ?demo= for one demo's, ?q= to search their email, name or company, ?limit= (up to 1000).

Events: webhooks

For things that happen to you rather than calls you make, the app sends webhooks: Settings, Integrations posts lead.captured, demo.viewed and demo.completed (for viewers who are known by a personal link or a form) to your address, signed with a secret, or to Slack, HubSpot or Salesforce.

Questions

Write to email@shotdemo.com. Tell us what you are building and we will help.