Launch intelligence is in early access. Become a design partner

ProductRelease intake

Get releases into Shotsfrom wherever you ship.

Type a release into the form, send it from CI with an API key, or let GitHub, GitLab, or your own pipeline send it through a signed webhook. Every path creates the same release, ready for launch intelligence.

curl https://shots.playbookmedia.io/api/v1/releases \
  -H "x-api-key: $SCREENSHOT_STUDIO_API_KEY" \
  -H "Idempotency-Key: release-v2.4.0" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Recurring invoices",
    "benefitStatement": "Bill repeat customers without rebuilding the invoice.",
    "sourceUrls": [
      "https://github.com/acme/billing/pull/452",
      "https://acme.com/changelog/recurring-invoices"
    ]
  }'
201 Created
{
  "created": true,
  "release": { "id": "cm…", "status": "DRAFT", "title": "Recurring invoices" }
}

Three ways in

Pick the path that fits how you ship:the form, the REST API, or a webhook.

All three create the same release in your workspace.

  • The release form

    Name the release, say why it matters, and paste the links. Best when a teammate writes it.
  • The REST API

    POST /api/v1/releases with a workspace API key from CI or a deploy script. Retries are safe with an idempotency key.
  • Signed webhooks

    Point a GitHub or GitLab release webhook at your source app, or sign your own. GitHub and GitLab releases link their release page as a source.

The release

A release has six fields,and two are enough to start.

A release is what you send, and a launch is built from it. Editing the release later doesn't rewrite launches already built from it.

Release fields
FieldRule
titleRequired. Up to 160 characters.
benefitStatementWhy it matters, up to 500 characters. Optional when a source link is given.
descriptionWhat changed, in plain text. Up to 10,000 characters.
audienceWho should hear about it. Up to 1,000 characters.
sourceUrlsUp to 20 public http(s) links: the pull request, changelog, and docs.
productSurfaceIdOptional. The product page this release changes.

Webhooks

Unsigned webhooks are refused,and a redelivery never creates a second release.

Signatures are checked over the exact body bytes before anything is parsed. The table shows the header each sender signs with and the one that guards against replays.

Webhook signatures
SenderSignatureReplay protection
GitHubX-Hub-Signature-256X-GitHub-Delivery
GitLabwebhook-signaturewebhook-timestamp
Any pipelineX-Shots-SignatureX-Shots-Timestamp, -Event-Id

A release that arrives by webhook or API key has no author on your team. The AI treats its text as untrusted and shows it to the reviewer with the sources.

API keys

API keys can create releasesbut can't approve or publish.

Workspace API keys carry one of 8 scopes. They are hashed at rest and shown once, and a revoked key stops working on the next request. No key can manage teammates, SSO, SCIM, audit log export, retention, or publishing.

API key scopes
ScopeAllows
artifact:readRead releases, assets, and generated artifacts.
asset:writeCreate and complete workspace assets.
draft:writeCreate, update, and delete content drafts.
onboarding:runRead a product site into its profile and follow the run.
post:scheduleSchedule approved campaign posts. People still approve.
release:createCreate releases, the input to every launch.
source:writeRegister source apps that send signed webhooks.
upload:signRequest signed upload URLs for asset bytes.
REST endpoints
EndpointScopeDoes
POST /api/v1/releasesrelease:createCreate a release. Accepts Idempotency-Key.
GET /api/v1/releasesartifact:readList workspace releases.
POST /api/v1/source-appssource:writeRegister a source app for webhooks.
POST /api/v1/assets/upload-urlupload:signReserve an asset and get a write-once upload URL.
POST /api/v1/assets/{assetId}/completeasset:writeMark an upload complete.
GET /api/v1/assets/{assetId}/download-urlartifact:readGet a short-lived download URL.
DELETE /api/v1/assets/{assetId}asset:writeQueue deletion of an unused asset. Pro and up.

Conventions

The API follows the same rules everywhere:safe retries, request IDs, and one error format.

The public OpenAPI spec is generated from the same Zod contracts the routes validate with, and tests keep the two in sync.

  • Idempotency-Key

    Safe retries

    Up to 128 characters. Longer keys are rejected, not cut short. A replay returns 200 with the first result.
  • X-Request-Id

    Traceable

    Every response carries a request ID that also appears in the audit log.
  • /openapi.json

    OpenAPI 3.1

    Also at /.well-known/openapi.json, with an interactive reference at /api-reference.
  • Accept: text/markdown

    Readable by AI tools

    llms.txt, llms-full.txt, and Markdown versions of supported pages.
One error envelopelib/api/errors.ts
{
  "error": "This workspace has used its monthly AI credits.",
  "code": "workspace_quota_exceeded",
  "message": "This workspace has used its monthly AI credits.",
  "hint": "Wait for the next cycle or move to a larger plan.",
  "status": 429,
  "documentation": "https://shots.playbookmedia.io/api-reference#errors"
}

Rate limits

API write limitsfor each plan.

API writes are limited per workspace by plan. Reads are not counted.

API write limits
PlanAPI writes per minuteAI credits per month
Free00
Pro3003,600
Business1,50013,200
Enterprise10,00054,000

Questions

Anything else? Talk to us.

Is there an SDK?
Not yet. The API is plain REST with an OpenAPI 3.1 spec, so any generated client works.
Does the API send webhooks back to me?
Not yet. Outbound release and delivery events are planned. Today, poll the release list or watch the workspace.
Can the API create launches or approve posts?
Launch endpoints are planned. An API key will never be able to approve.
Is there a GitHub App?
Yes. Connect a repository, and merges are held for the next published release, which arrives with its notes and linked pull requests. A repository webhook pointed at your source app also works.

Related

See every integration,what the AI does with a release, and Shots for developer tools.

Create an API keyand send a release from your next deploy.