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:
| Method | Path | Description |
|---|---|---|
| POST | /api/v1/stage/sessions | Create a new sandbox session |
| POST | /api/v1/stage/sessions/:id/push | Write files to a session |
| POST | /api/v1/stage/sessions/:id/render | Trigger a render |
| GET | /api/v1/stage/sessions/:id/status | Get session status, files, and render state |
| GET | /api/v1/stage/sessions/:id/files/:path | Read a file from a session |
| PUT | /api/v1/stage/sessions/:id/google-scopes | Set the Google OAuth scopes stored for a session |
| GET | /api/v1/stage/apps | List published apps or resolve by sessionId |
| GET | /api/v1/stage/apps/:sid | Get a single published app |
| PATCH | /api/v1/stage/apps/:sid | Update app metadata and repository linkage |
| POST | /api/v1/run/:appSid/:workflowName | Execute 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:
| Operation | Convex Function | Description |
|---|---|---|
| Create session | stage:createSession | Creates a new isolated session |
| Write file | stage:writeFile | Writes content to a path in a session |
| Read file | stage:readFile | Reads a file by path from a session |
| List files | stage:getAllFiles | Returns all files in a session |
| Trigger render | stage:triggerRender | Initiates a React render with an entry point |
| Get render state | stage:getRenderState | Returns current render entry and version |
| Get status | stage:getStatus | Returns session info, render state, and file list |
| Create snapshot | stage:createSnapshot | Captures a point-in-time snapshot |
| List snapshots | stage:getSnapshots | Lists all snapshots for a session |
| File history | stage:getFileHistory | Returns version history for a file |
| List apps | stage:listApps | Lists published Stage apps |
| Get app | stage:getApp | Gets a single app by SID |
| Get app by session | stage:getAppBySession | Resolves the app attached to a session |
| Update app | stage:updateApp | Updates app metadata and repository linkage |
| Set Google scopes | stage:setGoogleScopes | Stores the requested Google scopes for a session |
| Get Google scopes | stage:getGoogleScopes | Returns 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
responsepayloads
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:
| Method | Path | Description |
|---|---|---|
| ANY | /stage/:appSid/api | Root 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
}
]
}
}
Link a Repository to a Stage App
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"
}
}