Skip to main content

Backend Workflows

JavaScript/TypeScript native W7S backends can declare workflow consumers in w7s.json. W7S owns the workflow runner, creates instances for app requests, and dispatches each instance to the declaring backend through a durable step with retries.

Declare a workflow

The simplest form declares a workflow named process-order:

w7s.json
{
"workflows": ["process-order"]
}

By default, W7S delivers that workflow to:

/_w7s/workflows/process-order

Use an object when you want a different consumer path:

w7s.json
{
"workflows": [
{
"name": "process-order",
"path": "/internal/workflows/process-order"
}
]
}

Workflows require a JavaScript or TypeScript native backend deployment. Static-only apps cannot declare workflows.

Runtime bindings

Every JavaScript/TypeScript native backend receives:

W7S_WORKFLOW
W7S_WORKFLOW_TOKEN
W7S_OWNER
W7S_REPO
W7S_REPOSITORY
W7S_ENVIRONMENT

W7S_WORKFLOW is an internal service binding to the W7S control plane. W7S_WORKFLOW_TOKEN is a secret used by W7S to prove which deployed app is starting the workflow.

Only send the bearer token. W7S resolves the caller repo and deployment environment from that token.

Start a workflow

Start workflow instances through:

/api/v1/workflows/<owner>/<repo>/<workflow>

Example:

backend/index.ts
type Env = {
W7S_WORKFLOW: Fetcher;
W7S_WORKFLOW_TOKEN: string;
};

export default {
async fetch(_request: Request, env: Env) {
const response = await env.W7S_WORKFLOW.fetch(
"https://w7s.internal/api/v1/workflows/w7s-io/example-workflows/process-order",
{
method: "POST",
headers: {
authorization: `Bearer ${env.W7S_WORKFLOW_TOKEN}`,
"content-type": "application/json",
"x-w7s-workflow-instance-id": crypto.randomUUID()
},
body: JSON.stringify({
orderId: "123"
})
}
);

return response.ok
? Response.json({ status: "started", result: await response.json() })
: new Response(await response.text(), { status: 502 });
}
};

x-w7s-workflow-instance-id is optional. If omitted, W7S generates an id.

W7S rejects workflow instance payloads larger than 64 KB by default. Starts also count against daily and short-window limits for the caller repo, owner, and global platform. Target repos are capped at 50 active workflow instances by default.

Receive workflow runs

Create a backend route for the workflow consumer path:

backend/index.ts
export default {
async fetch(request: Request) {
const url = new URL(request.url);

if (url.pathname === "/_w7s/workflows/process-order" && request.method === "POST") {
const run = await request.json();

console.log("workflow", run.instanceId, run.payload);

return Response.json({
ok: true,
processedOrderId: run.payload.orderId
});
}

return new Response("Not found", { status: 404 });
}
};

W7S sends this payload to the consumer route:

{
"workflow": "process-order",
"workflowName": "process-order",
"instanceId": "production-w7s-io-example-workflows-process-order-abc123",
"createdAt": "2026-05-26T00:00:00.000Z",
"caller": {
"orgSlug": "w7s-io",
"repoSlug": "example-workflows",
"repository": "w7s-io/example-workflows",
"environment": "production"
},
"target": {
"orgSlug": "w7s-io",
"repoSlug": "example-workflows",
"repository": "w7s-io/example-workflows",
"environment": "production",
"workflow": "process-order",
"path": "/_w7s/workflows/process-order"
},
"payload": {
"orderId": "123"
}
}

Return any 2xx response after processing. Non-2xx responses make the workflow step fail and retry according to W7S core retry policy. The default delivery policy is 3 retries, 10 second initial delay, exponential backoff, and 300 second timeout.

Status

Check an instance through:

GET /api/v1/workflows/<owner>/<repo>/<workflow>/<instance-id>

Use the same Authorization: Bearer ${env.W7S_WORKFLOW_TOKEN} header used to start the workflow.

Authorization

Apps under the same GitHub owner can start each other's workflows by default.

For cross-owner starts, the target app must allow the caller in w7s.json.

To allow one exact repo:

w7s.json
{
"workflow": {
"allow": ["guerrerocarlos/nodepad"]
}
}

To allow every repo under an owner:

w7s.json
{
"workflow": {
"allow": ["guerrerocarlos"]
}
}

Current model

W7S apps do not define platform-specific workflow classes directly. W7S starts a managed workflow instance and dispatches one durable step to the app's HTTP consumer path.

This keeps the app API simple and lets W7S keep the underlying workflow implementation transparent to the app.