Tours
Product tours as documents, any status the workspace owns.
Base URL https://api.showpilot.com/v1. Every call needs Authorization: Bearer <api key>; see Authentication.
List tours, newest first
GET /tours
Scope: tours:read. Operation id: listTours.
Templates are excluded. status is published when a frozen revision is live, else the row's own status.
Parameters
| Name | In | Type | Meaning |
|---|---|---|---|
limit | query | integer | Page size, 1 to 200. Default 50. |
cursor | query | string | The nextCursor from the previous page. Opaque; never build one. |
status | query | draft · published · archived | Only tours in this state. |
Example request
curl "https://api.showpilot.com/v1/tours?limit=50" \
-H "Authorization: Bearer $SHOWPILOT_API_KEY"Response
One page of tours.
| Field | Type | Always | Meaning |
|---|---|---|---|
items | array of Tour | yes | |
nextCursor | NextCursor | yes |
Tour
| Field | Type | Always | Meaning |
|---|---|---|---|
id | string (uuid) | yes | |
publicId | string | yes | The id in share links and embeds. |
name | string | yes | |
description | string or null | yes | |
status | draft · published · archived | yes | published when a frozen revision is live. |
isActive | boolean | yes | Inactive tours are not served to visitors. |
hubId | string or null (uuid) | yes | |
publishedAt | string or null (date-time) | yes | |
createdAt | string (date-time) | yes | |
updatedAt | string (date-time) | yes |
NextCursor
Pass as cursor for the next page; null on the last page.
Example response
{
"items": [
{
"id": "c5879294-795a-5430-88b1-7fdbdfa910ce",
"publicId": "t_9f3k2q",
"name": "A First Walk Through the App",
"description": null,
"status": "published",
"isActive": true,
"hubId": null,
"publishedAt": "2026-09-01T14:02:11.000Z",
"createdAt": "2026-08-20T09:12:40.000Z",
"updatedAt": "2026-09-01T14:02:11.000Z"
}
],
"nextCursor": "eyJhdCI6IjIwMjYtMDgtMjBUMDk6MTI6NDAuMDAwWiIsImlkIjoiYzU4NzkyOTQtLi4uIn0"
}Errors
| Status | When |
|---|---|
| 400 | A parameter is malformed, such as a cursor this API did not issue, a limit under 1, or an unknown status. Code invalid-request. |
| 401 | No key, or an unknown or revoked key. Code unauthorized. |
| 403 | A valid key without the operation's scope (code insufficient-scope), or a plan without API access (code plan-api-off). |
| 429 | The key's bucket is empty. Code rate-limited; wait the Retry-After seconds. |
One tour with its document
GET /tours/{id}
Scope: tours:read. Operation id: getTour.
id is the tour's UUID or its public id. The document is the frozen
published revision when there is one, else the live rows; pass
view=live to read the live rows regardless (the builder's view).
Media URLs are resolved on the way out. Without a bearer token this
path is the anonymous player route and serves published tours only.
Parameters
| Name | In | Type | Meaning |
|---|---|---|---|
id | path | string | The tour's UUID or public id. |
view | query | published · live | live reads the current rows even when a published revision exists. |
Example request
curl "https://api.showpilot.com/v1/tours/t_9f3k2q" \
-H "Authorization: Bearer $SHOWPILOT_API_KEY"Response
The tour summary plus its document.
Every field of Tour, plus:
| Field | Type | Always | Meaning |
|---|---|---|---|
document | TourDocument | yes |
Tour
| Field | Type | Always | Meaning |
|---|---|---|---|
id | string (uuid) | yes | |
publicId | string | yes | The id in share links and embeds. |
name | string | yes | |
description | string or null | yes | |
status | draft · published · archived | yes | published when a frozen revision is live. |
isActive | boolean | yes | Inactive tours are not served to visitors. |
hubId | string or null (uuid) | yes | |
publishedAt | string or null (date-time) | yes | |
createdAt | string (date-time) | yes | |
updatedAt | string (date-time) | yes |
TourDocument
The same document the player renders from. Screens in order with resolved media URLs; guides with their step settings and narration URL. Storage geometry is not part of the contract and may change.
| Field | Type | Always | Meaning |
|---|---|---|---|
tourId | string (uuid) | yes | |
publicId | string or null | yes | |
name | string | yes | |
description | string or null | no | |
display | string or null | no | |
transition | string or null | no | |
screens | array of object | yes | |
guides | array of object | yes |
Errors
| Status | When |
|---|---|
| 401 | No key, or an unknown or revoked key. Code unauthorized. |
| 403 | A valid key without the operation's scope (code insufficient-scope), or a plan without API access (code plan-api-off). |
| 404 | No object with that id in this workspace. Code not-found. |
| 429 | The key's bucket is empty. Code rate-limited; wait the Retry-After seconds. |
The tour as an authoring document, with its version
GET /tours/{id}/spec
Scope: tours:read. Operation id: getTourSpec.
The narrow shape an author edits: tour fields, the screens (read-only,
for reference) and the steps keyed by a stable ref. Storage geometry
never appears; the server expands what you write and keeps every
field you did not touch. version is what apply must name.
Parameters
| Name | In | Type | Meaning |
|---|---|---|---|
id | path | string | The tour's UUID or public id. |
Example request
curl "https://api.showpilot.com/v1/tours/<id>/spec" \
-H "Authorization: Bearer $SHOWPILOT_API_KEY"Response
The spec.
| Field | Type | Always | Meaning |
|---|---|---|---|
tourId | string (uuid) | yes | |
version | string | yes | |
spec | TourSpec | yes |
TourSpec
| Field | Type | Always | Meaning |
|---|---|---|---|
tour | object | yes | |
screens | array of TourSpecScreen | yes | Read-only; listed so steps can reference them. |
steps | array of TourSpecStep | yes |
TourSpecScreen
| Field | Type | Always | Meaning |
|---|---|---|---|
id | string | yes | |
type | string or null | yes | |
name | string or null | yes | |
orderIndex | integer | yes | |
durationSecs | number or null | yes |
TourSpecStep
| Field | Type | Always | Meaning |
|---|---|---|---|
ref | string | yes | Stable |
screen | string | yes | A screen id from screens. A step never moves between screens. |
at | number or null | no | Video screens only |
anchor | object | yes | center (a lightbox), { element } (a selector, accepted but not verified yet), or { region: [x, y, w, h] } as 0–1 fractions. |
title | string | yes | |
body | string | yes | What the step says. Narration follows it unless a human wrote their own. |
advance | auto · click · ask | yes | ask holds the frame for the agent; needs an agent-led tour. |
advanceAfterSecs | number or null | no | |
narrate | boolean | yes | |
openWhen | array of string | no | Phrases that should open this step from a conversation. |
Errors
| Status | When |
|---|---|
| 401 | No key, or an unknown or revoked key. Code unauthorized. |
| 403 | A valid key without the operation's scope (code insufficient-scope), or a plan without API access (code plan-api-off). |
| 404 | No object with that id in this workspace. Code not-found. |
| 429 | The key's bucket is empty. Code rate-limited; wait the Retry-After seconds. |
Apply a spec against a base version
PUT /tours/{id}/spec
Scope: tours:write. Operation id: applyTourSpec.
Requires Idempotency-Key. Lints first (400 lint-failed with the
problems), refuses if the tour changed since baseVersion
(409 stale with currentVersion), then writes: existing refs are
merged field by field, new refs are inserted, missing refs are
deleted, steps are reordered per screen. Narration audio is never
regenerated by an apply.
Parameters
| Name | In | Type | Meaning |
|---|---|---|---|
id | path | string | The tour's UUID or public id. |
Example request
curl "https://api.showpilot.com/v1/tours/<id>/spec" \
-H "Authorization: Bearer $SHOWPILOT_API_KEY"Response
The applied spec and its new version.
| Field | Type | Always | Meaning |
|---|---|---|---|
tourId | string (uuid) | yes | |
version | string | yes | |
spec | TourSpec | yes | |
problems | array of LintProblem | yes |
TourSpec
| Field | Type | Always | Meaning |
|---|---|---|---|
tour | object | yes | |
screens | array of TourSpecScreen | yes | Read-only; listed so steps can reference them. |
steps | array of TourSpecStep | yes |
TourSpecScreen
| Field | Type | Always | Meaning |
|---|---|---|---|
id | string | yes | |
type | string or null | yes | |
name | string or null | yes | |
orderIndex | integer | yes | |
durationSecs | number or null | yes |
TourSpecStep
| Field | Type | Always | Meaning |
|---|---|---|---|
ref | string | yes | Stable |
screen | string | yes | A screen id from screens. A step never moves between screens. |
at | number or null | no | Video screens only |
anchor | object | yes | center (a lightbox), { element } (a selector, accepted but not verified yet), or { region: [x, y, w, h] } as 0–1 fractions. |
title | string | yes | |
body | string | yes | What the step says. Narration follows it unless a human wrote their own. |
advance | auto · click · ask | yes | ask holds the frame for the agent; needs an agent-led tour. |
advanceAfterSecs | number or null | no | |
narrate | boolean | yes | |
openWhen | array of string | no | Phrases that should open this step from a conversation. |
LintProblem
| Field | Type | Always | Meaning |
|---|---|---|---|
path | string | yes | The field the problem is in. |
code | string | yes | empty, too-long, vocab-demo, vocab-project, vocab-folio, unknown-skill, tool-missing. |
message | string | yes | |
severity | error · warning | yes |
Errors
| Status | When |
|---|---|
| 400 | The edit has lint errors. Code lint-failed; problems lists them. |
| 401 | No key, or an unknown or revoked key. Code unauthorized. |
| 403 | A valid key without the operation's scope (code insufficient-scope), or a plan without API access (code plan-api-off). |
| 404 | No object with that id in this workspace. Code not-found. |
| 409 | The document changed since the baseVersion you read. Code stale; currentVersion at the top level says what to re-read. |
| 429 | The key's bucket is empty. Code rate-limited; wait the Retry-After seconds. |
Diff and lint a spec, writing nothing
POST /tours/{id}/propose
Scope: tours:read. Operation id: proposeTourSpec.
The loop is propose → fix → propose → apply. applicable is false while any problem is an error.
Parameters
| Name | In | Type | Meaning |
|---|---|---|---|
id | path | string | The tour's UUID or public id. |
Example request
curl "https://api.showpilot.com/v1/tours/<id>/propose" \
-H "Authorization: Bearer $SHOWPILOT_API_KEY"Response
The proposal.
TourProposal
| Field | Type | Always | Meaning |
|---|---|---|---|
tourId | string (uuid) | yes | |
baseVersion | string | yes | Pass to apply. |
diff | object | yes | |
problems | array of LintProblem | yes | |
applicable | boolean | yes |
LintProblem
| Field | Type | Always | Meaning |
|---|---|---|---|
path | string | yes | The field the problem is in. |
code | string | yes | empty, too-long, vocab-demo, vocab-project, vocab-folio, unknown-skill, tool-missing. |
message | string | yes | |
severity | error · warning | yes |
Errors
| Status | When |
|---|---|
| 400 | A parameter is malformed, such as a cursor this API did not issue, a limit under 1, or an unknown status. Code invalid-request. |
| 401 | No key, or an unknown or revoked key. Code unauthorized. |
| 403 | A valid key without the operation's scope (code insufficient-scope), or a plan without API access (code plan-api-off). |
| 404 | No object with that id in this workspace. Code not-found. |
| 429 | The key's bucket is empty. Code rate-limited; wait the Retry-After seconds. |
Freeze a revision and point visitors at it
POST /tours/{id}/publish
Scope: tours:write. Operation id: publishTour.
Requires Idempotency-Key. Lints the live rows first; a tour with lint errors does not publish.
Parameters
| Name | In | Type | Meaning |
|---|---|---|---|
id | path | string | The tour's UUID or public id. |
Example request
curl "https://api.showpilot.com/v1/tours/<id>/publish" \
-H "Authorization: Bearer $SHOWPILOT_API_KEY"Response
Status 201.
The new revision.
| Field | Type | Always | Meaning |
|---|---|---|---|
tourId | string (uuid) | yes | |
publicId | string or null | yes | |
revisionId | string (uuid) | yes | |
publishedVersion | integer | yes | |
publishedAt | string (date-time) | yes |
Errors
| Status | When |
|---|---|
| 400 | The edit has lint errors. Code lint-failed; problems lists them. |
| 401 | No key, or an unknown or revoked key. Code unauthorized. |
| 403 | A valid key without the operation's scope (code insufficient-scope), or a plan without API access (code plan-api-off). |
| 404 | No object with that id in this workspace. Code not-found. |
| 429 | The key's bucket is empty. Code rate-limited; wait the Retry-After seconds. |