Skip to main content

Stage API Reference

Stage operates through two interfaces: the gateway-proxied REST API (when STAGE_PROXY_URL is configured) and direct Convex mutations/queries used by the CLI. Published apps can also expose workflow handlers through the gateway's Stage runner.

Gateway Endpoints

When STAGE_PROXY_URL is set, the gateway proxies requests to the external Stage Next.js service:

MethodPathDescription
POST/api/v1/stage/sessionsCreate a new sandbox session
POST/api/v1/stage/sessions/:id/pushWrite files to a session
POST/api/v1/stage/sessions/:id/renderTrigger a render
GET/api/v1/stage/sessions/:id/statusGet session status, files, and render state
GET/api/v1/stage/sessions/:id/files/:pathRead a file from a session
PUT/api/v1/stage/sessions/:id/google-scopesSet the Google OAuth scopes stored for a session
GET/api/v1/stage/appsList published apps or resolve by sessionId
GET/api/v1/stage/apps/:sidGet a single published app
PATCH/api/v1/stage/apps/:sidUpdate app metadata and repository linkage
POST/api/v1/run/:appSid/:workflowNameExecute a published workflow from /app/shift.workflows.json

Convex Operations (CLI)

The Stage CLI communicates directly with the Convex backend using HTTP mutations and queries under the stage: namespace:

OperationConvex FunctionDescription
Create sessionstage:createSessionCreates a new isolated session
Write filestage:writeFileWrites content to a path in a session
Read filestage:readFileReads a file by path from a session
List filesstage:getAllFilesReturns all files in a session
Trigger renderstage:triggerRenderInitiates a React render with an entry point
Get render statestage:getRenderStateReturns current render entry and version
Get statusstage:getStatusReturns session info, render state, and file list
Create snapshotstage:createSnapshotCaptures a point-in-time snapshot
List snapshotsstage:getSnapshotsLists all snapshots for a session
File historystage:getFileHistoryReturns version history for a file
List appsstage:listAppsLists published Stage apps
Get appstage:getAppGets a single app by SID
Get app by sessionstage:getAppBySessionResolves the app attached to a session
Update appstage:updateAppUpdates app metadata and repository linkage
Set Google scopesstage:setGoogleScopesStores the requested Google scopes for a session
Get Google scopesstage:getGoogleScopesReturns the stored Google scopes for a session

Examples

Create a Session

curl -X POST http://localhost:3000/api/v1/stage/sessions

Response:

{
"success": true,
"data": {
"id": "k77abc123def"
}
}

Push Files to a Session

curl -X POST http://localhost:3000/api/v1/stage/sessions/k77abc123def/push \
-H "Content-Type: application/json" \
-d '{
"files": {
"/app/App.tsx": "export default function App() { return <h1>Hello</h1>; }"
}
}'

Response:

{
"success": true,
"data": {
"count": 1
}
}

Trigger a Render

curl -X POST http://localhost:3000/api/v1/stage/sessions/k77abc123def/render \
-H "Content-Type: application/json" \
-d '{"entry": "/app/App.tsx"}'

Response:

{
"success": true,
"data": {
"entry": "/app/App.tsx",
"version": 1
}
}

Set Session Google Scopes

curl -X PUT http://localhost:3000/api/v1/stage/sessions/k77abc123def/google-scopes \
-H "Content-Type: application/json" \
-d '{
"scopes": [
"https://www.googleapis.com/auth/drive.readonly",
"https://www.googleapis.com/auth/spreadsheets"
]
}'

Execute a Published Workflow

curl -X POST http://localhost:3000/api/v1/run/app_123/appendWebhookRow \
-H "Content-Type: application/json" \
-d '{
"input": {
"spreadsheetId": "sheet_123",
"range": "Events!A:G",
"customerEmail": "demo@example.com",
"amountCents": 1250
}
}'

The workflow route loads /app/shift.workflows.json from the published app's session and currently supports:

  • Google Sheets steps (createSpreadsheet, appendValues, getValues)
  • Billing item creation
  • Communication message delivery
  • Pulse event tracking
  • Ledger audit event creation
  • Templated response payloads

Communication Workflow Block

Workflows can send messages through the Communication service using the communication.send block:

{
"version": 1,
"workflows": {
"notifyOnSubmit": {
"steps": [
{
"communication.send": {
"channelId": "{{ config.slackChannelId }}",
"to": "{{ auth.email }}",
"subject": "Form submitted",
"text": "New submission from {{ input.name }}",
"html": "<p>New submission from <b>{{ input.name }}</b></p>",
"metadata": { "source": "{{ app.sid }}" }
}
}
]
}
}
}

The block resolves an active registration for the app and channel, then dispatches through the Communication service with delivery tracking.

Published API Endpoints

Published Stage apps can expose server-side API routes through the gateway:

MethodPathDescription
ANY/stage/:appSid/apiRoot API endpoint for the published app
ANY/stage/:appSid/api/*All sub-routes forwarded to the app's backend

The gateway compiles the app's backend entrypoint, injects virtual modules (@stage/inference, @stage/compute, @stage/utils), and forwards requests with the URL prefix stripped. See the Published API Backends reference for details.

Get Session Status

curl http://localhost:3000/api/v1/stage/sessions/k77abc123def/status

Response:

{
"success": true,
"data": {
"session": {
"createdAt": 1709640000000,
"lastAccessedAt": 1709640060000
},
"render": {
"entry": "/app/App.tsx",
"version": 1,
"error": null,
"renderedAt": 1709640060000
},
"files": [
{
"path": "/app/App.tsx",
"version": 1,
"size": 57
}
]
}
}
curl -X PATCH http://localhost:3000/api/v1/stage/apps/app_123 \
-H "Content-Type: application/json" \
-d '{
"repository": {
"provider": "github",
"owner": "tom",
"name": "drive-hasher",
"fullName": "tom/drive-hasher",
"url": "https://github.com/tom/drive-hasher",
"visibility": "private",
"defaultBranch": "main",
"remoteName": "origin",
"linkedAt": 1709640060000
}
}'

Response Envelope

All responses follow the standard envelope format:

Success:

{
"success": true,
"data": { ... }
}

Error:

{
"success": false,
"error": {
"code": "NOT_FOUND",
"message": "Session not found"
}
}