REST API

Everything in Boardwalk is an HTTP call. The dashboard, the CLI, and the MCP server all sit on the same REST surface, so anything they do, your own server can do too: fire a run when an event happens in your product, read its status and events, deploy from CI, or manage your org. The hosted API lives at https://api.boardwalk.sh; self-hosted is your own host. Every path is under /v1, requests and responses are JSON, and auth is a bearer token.

Authentication

For server-to-server calls, use an API key. Create one in the dashboard under Settings → API keys (key minting needs a logged-in session, so it is not something a key can do to itself). The full key begins with bwk_ and is shown once at creation; store it as a secret. Send it as a bearer token:

curl https://api.boardwalk.sh/v1/orgs/acme/workflows \
  -H "Authorization: Bearer bwk_your_key_here"

A key belongs to one org, so org-scoped routes still take your org slug in the path. The CLI and CI both read the same value from the BOARDWALK_API_KEY environment variable. Two other credentials reach the same routes: a Clerk session JWT (the dashboard) and the CLI's OAuth token (boardwalk login). Credential-minting actions below are marked session only; an API key can never perform them at any scope.

Key scopes

A key is least-privilege. Leave its scopes empty for full access at the key's role, or list scopes to restrict it to exactly the actions you need. For a key that only kicks off runs from your app, grant run:trigger and nothing else. Scopes are <resource>:<action> strings:

ResourceScopes
Workflowsworkflow:read, workflow:create, workflow:update, workflow:delete, workflow:trigger, workflow_version:read, workflow_version:create
Runsrun:read, run:trigger, run:cancel, run:delete
Inferenceinference:invoke (call the managed inference gateway directly)
Read-onlyaudit_log:read, billing:read

Credential-minting actions (writing secrets, minting API keys, wiring inference providers, inviting members) are never reachable by an API key at any scope; they require a logged-in session in the dashboard. See roles for the role each action needs.

Conventions

The whole surface is consistent: JSON in and out, ISO-free millisecond-epoch timestamps, cursor pagination, and one error shape.

Pagination & polling

List endpoints take ?limit (1 to 100, default 50) and an opaque ?cursor, and return a nextCursor that is null on the last page. Pass it back to page forward:

GET /v1/orgs/acme/runs?limit=50
// → { "runs": [ ... ], "nextCursor": "eyJ0IjoxNz..." }

GET /v1/orgs/acme/runs?limit=50&cursor=eyJ0IjoxNz...
// → { "runs": [ ... ], "nextCursor": null }   // last page

List and detail reads support a conditional GET: send the ETag you last saw back as If-None-Match and an unchanged resource answers 304 Not Modified with no body. That makes status polling cheap; for a live view, prefer the event stream over a poll loop (see Runs & observability).

Errors

Every non-2xx response is the same envelope: a stable code, a human message, and an optional detail object.

{
  "error": {
    "code": "VALIDATION_FAILED",
    "message": "triggers must contain at least one entry",
    "detail": { "path": "triggers" }
  }
}
  • 400 VALIDATION_FAILED: the request body or query failed schema validation.
  • 401 UNAUTHENTICATED / 403 FORBIDDEN: no usable credential, or the credential lacks the role or scope.
  • 404 NOT_FOUND: the resource is missing orbelongs to another org. Cross-tenant access is a 404, never a 403, so a key can't probe for ids it can't see.
  • 405: the path exists but not for that method; the response carries an Allow header.
  • 429: rate limited (a per-user and per-org bucket); back off and retry.

Trigger a run

This is the call you want when your own server or web app needs to start a workflow on demand. POST to the workflow's runs collection; the optional inputbody becomes the run's trigger payload, available to the program as input. An optional environment (a name) selects the environment the run executes in, with its secrets and variables; omit it for the organization base.

curl -X POST \
  https://api.boardwalk.sh/v1/orgs/acme/workflows/wf_123/runs \
  -H "Authorization: Bearer bwk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{ "input": { "pr_url": "https://github.com/acme/app/pull/42" } }'

Or from your application code:

trigger.ts
const res = await fetch(
  "https://api.boardwalk.sh/v1/orgs/acme/workflows/wf_123/runs",
  {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.BOARDWALK_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ input: { pr_url: prUrl } }),
  },
);
const { run } = await res.json(); // 201 Created
console.log(run.id, run.status);  // the new run's id + "queued"

The trigger returns immediately with the new run's id and status; the run executes asynchronously. To react to a workflow event instead of polling, point a workflow webhook at it, or subscribe with a watch.

Read a run

Poll the run by id for its terminal status, and read its event log for the full timeline (phases, agent turns, output):

GET  /v1/runs/{runId}          # status, timing, token + cost totals
GET  /v1/runs/{runId}/input   # the trigger payload this run was called with
GET  /v1/runs/{runId}/events  # the run's event log (phases, agent, output)
POST /v1/runs/{runId}/cancel  # stop a queued or in-flight run
POST /v1/runs/{runId}/retry   # re-run with the same input

A run's status moves through queued, running, then one of completed, failed, or cancelled. The value passed to output() in the program lands in the run's events under the output channel. For the event model, channels, and the live stream, see Runs & observability.

Endpoint reference

The full public surface, grouped by resource. All paths are under /v1 and take a bearer token; org-scoped routes take your org slug in the path.

Workflows

Method & pathWhat it does
GET /orgs/:slug/workflowsList the org's workflows (paginated).
POST /orgs/:slug/workflowsCreate a workflow from a built program artifact (the CLI's deploy).
POST /orgs/:slug/workflows/artifact-upload-urlMint a presigned upload URL for a program artifact before create/update.
GET /workflows/:idFetch one workflow, its manifest, and its current version.
PATCH /workflows/:idPublish a new version (or rename the slug).
DELETE /workflows/:idDelete a workflow (soft; runs and audit are retained).
POST /workflows/:id/disable · /enablePause every trigger, reversibly, then resume.

Runs

Method & pathWhat it does
POST /orgs/:slug/workflows/:id/runsTrigger a run; optional input and environment. Returns 201.
GET /orgs/:slug/workflows/:id/runsList a workflow's runs (filter ?status=, paginated).
GET /orgs/:slug/runsList every run across the org.
GET /runs/:idStatus, timing, token and cost totals, error.
GET /runs/:id/inputThe trigger payload this run was called with.
GET /runs/:id/eventsA snapshot of the run's stored event log.
POST /runs/:id/cancel · /retryStop a queued or in-flight run; re-run with the same input.

Schedules

Method & pathWhat it does
POST /workflows/:id/schedulesCreate a durable schedule: exactly one of cron, rate, or at, with optional timezone and input.
GET /workflows/:id/schedulesList a workflow's durable schedules.
DELETE /workflows/:id/schedules/:scheduleIdCancel a schedule so it stops firing.
GET /orgs/:slug/schedulesThe org's cron triggers plus predicted next fire times (the agenda view).

Schedules created here are the same primitive a program provisions with workflows.schedule(). A cron trigger declared in meta needs nothing here; these endpoints are for schedules created at runtime or from your own tooling.

Webhooks

Method & pathWhat it does
GET /orgs/:slug/workflows/:id/webhookThe inbound URL and auth mode (the secret is never returned on read).
POST /orgs/:slug/workflows/:id/webhook/rotateRotate the signing secret; the new URL is shown once (admin).

Watches

Method & pathWhat it does
GET|PUT|DELETE /workflows/:id/watchYour subscription to a workflow's terminal outcomes.
GET|PUT|DELETE /runs/:id/watchYour subscription to one run's terminal outcome.
GET|PATCH /me/notificationsYour notification preferences and every watch you hold.
DELETE /me/watches/:idDrop a single watch.

Artifacts

Method & pathWhat it does
GET /orgs/:slug/runs/:id/artifactsList the artifacts a run produced.
GET /artifacts/:idOne artifact's metadata (name, content type, size, expiry).
GET /artifacts/:id/download302 redirect to a short-lived signed URL.
GET /artifacts/:id/download-urlThe signed URL as JSON (when you can't follow a redirect with a header).

See Artifacts for what a workflow writes and how the signed URLs work.

Secrets

Method & pathWhat it does
GET /orgs/:slug/secretsList secret names and metadata. Values are never returned.
POST /orgs/:slug/secrets (session only)Stage a secret value into the vault.
GET /secrets/:idOne secret's metadata.
DELETE /secrets/:id · POST /secrets/:id/rotate (session only)Delete or rotate a secret.

Environments

Method & pathWhat it does
POST /orgs/:slug/environments · GETCreate a named environment; list the org's environments.
GET|PATCH|DELETE /environments/:idRead, update, or delete one (delete cascades its secrets and variables).
POST /orgs/:slug/env-variables · GETSet a non-secret variable on an environment or the org base; list them.
GET|PATCH|DELETE /env-variables/:idRead, update, or delete one variable.

An environment scopes secrets and variables; a run picks one by name at trigger time, and an env-level value overrides the org base. See Secrets & environments.

Inference

Method & pathWhat it does
GET /orgs/:slug/inference-providersList BYO providers (name, source, base URL). Keys are never returned.
POST /orgs/:slug/inference-providers (session only)Register a provider and stage its key.
DELETE /orgs/:slug/inference-providers/:name (session only)Remove a provider.
PUT /orgs/:slug/inference-providers/:name/bedrock-roleWire a BYO Bedrock cross-account role (the second step after create).
GET /inference/ratesThe public managed-model price table (no auth).

API keys

Method & pathWhat it does
GET /orgs/:slug/api-keysList keys (prefix, last-4, scopes, spend cap; never the value).
POST /orgs/:slug/api-keys (session only)Mint a key; the bwk_ token is shown once.
POST /orgs/:slug/inference-keysMint an inference-only key with a default spend cap (what boardwalk dev uses).
PATCH /api-keys/:id (session only)Set or clear a monthly spend cap.
DELETE /api-keys/:idRevoke a key.

Billing & usage

Method & pathWhat it does
GET /orgs/:slug/usageRuns, compute, tokens, outcomes, and credit over a window.
GET /orgs/:slug/workflows/:id/usageThe same, scoped to one workflow.
GET /orgs/:slug/billing/balance · /seats · /transactionsCredit balance, seat counts, and the ledger.
POST /orgs/:slug/billing/checkout · /portalOpen a Stripe Checkout session or the customer portal (admin).
GET|PATCH /orgs/:slug/billing/emailRead or set the billing email.

Org, members, audit

Method & pathWhat it does
POST /orgs · GET /orgs/check-slugCreate an org (you become owner); check slug availability.
GET|PATCH|DELETE /orgs/:slugRead, rename, or delete the org (delete is owner-only).
PATCH /orgs/:slug/securityRequire 2FA, allow-list email domains, set run retention (admin).
GET|PATCH|DELETE /orgs/:slug/members/:userIdList, re-role, or remove members.
POST|GET /orgs/:slug/invitations · DELETE .../:idInvite, list, or revoke (invite is session only).
POST /invitations/acceptAccept an invitation by token.
GET /orgs/:slug/auditThe audit log (admins see all; others see their own entries).
POST /orgs/:slug/exports · GET .../exports/:idRequest an org data export and read its status (admin).

You

Method & pathWhat it does
GET /meYour profile and org memberships.
PATCH /me · DELETE /me (session only)Update your display name; delete your account.
POST /me/exportDownload your account data as JSON.

Inbound webhooks

The trigger endpoint above is for code you control. When a third-party system you don't control needs to start a run (a GitHub push, a Stripe event), give it a workflow webhook instead: Boardwalk provisions a per-workflow URL and secret, and verifies the incoming request (a shared token in the URL or an HMAC signature) before firing. Fetch the URL and auth mode with GET /v1/orgs/:slug/workflows/:id/webhook, or rotate its secret with the /rotate route.

The runner API

A running workflow reaches the control plane over a separate /runner/v1/* surface (secrets, artifacts, child runs, telemetry). It is authorized by a short-lived per-run token the platform mints for each run, not by your API key, and is an internal contract between the runner and the broker. It is not part of the public API and not for general use; your programs reach all of it through the SDK instead.