REST API reference

Version v1 · Base URL https://www.whatstheprocessfor.com/api/v1

Raw .md

Paste-into-Claude friendly

The "Copy as Markdown" button copies the full reference. Paste it into any Claude conversation with your API key and ask for what you want — Claude will construct the HTTP calls.

What’s the Process For — API reference

Base URL: https://www.whatstheprocessfor.com/api/v1

This document is designed to be pasted directly into a Claude (or any LLM) conversation alongside your API key. When prompted for a task — “create a process called X”, “find all my processes about Y”, “publish the one about Z” — Claude can read this reference and construct the correct HTTP calls.

How to use this reference with Claude

  1. Copy the full contents of this page (there’s a “Copy as Markdown” button at /developers/api, or curl https://www.whatstheprocessfor.com/developers/api.md).
  2. Paste it into a Claude conversation as context.
  3. Tell Claude what you want to do, and give it your API key. It will translate natural-language intent into HTTP calls.

For a deeper integration — tool calls instead of paste-in context — install the MCP server: see /developers/mcp.

Authentication

All requests require an API key. You can pass it either way:

Authorization: Bearer wtpf_<your-key>

or

X-API-Key: wtpf_<your-key>

Key scopes

Every key has one of two scopes:

  • user — personal key, acts on the owner’s personal processes (no org)
  • organization — org key, acts in the org with the role of whoever minted it. A key minted by a “member” cannot do things only owners/admins can do, even if the key itself has the processes:write permission.

Minting keys:

  • Any signed-in user can mint a personal key at /account/api-keys.
  • Owners/admins mint org keys at /org/<slug>/api-keys.
  • Members submit a request there; an owner/admin approves, and the plaintext is shown once to the approver to share via a secure channel.

Permission scopes

Each key also carries one or more permission scopes:

ScopeLets the key…
processes:readList processes, fetch a process + steps
processes:writeCreate, update, publish, upload images via /uploads
processes:deletePermanently delete a process
workflows:readList workflows, fetch a workflow + ordered processes, list per-user permissions
workflows:writeCreate / edit / reorder workflows, add or remove processes, grant or revoke per-user permissions, mark or unmark training progress
workflows:deletePermanently delete a workflow (cascades to its links + progress)
members:readList org members and pending invites
members:writeUpdate member roles, send invites
members:deleteRemove members, revoke invites

Default on creation: processes:read + processes:write. delete, workflows:*, and members:* are opt-in. Pass them in the scopes array when creating the key (or when filing a member request for admin approval).

Workflows + members require an organization-scoped key. Personal keys (scope: user) cannot manage workflows or org membership and will get 403 This endpoint requires an organization-scoped API key.

A 403 Missing required scope: <scope> response means the key you’re using doesn’t carry that scope — ask the key’s owner to mint a new one (or file a request for admin approval) with the scope you need.

Rate limits

API access is open to every plan. Throttled per plan:

PlanPer minutePer day
Free10200
Trial20500
Starter302,000
Team6010,000
Business30050,000
Enterprise1,000unlimited

Both windows apply. On overflow you get 429 Too Many Requests with:

{
  "error": "Rate limit exceeded",
  "window": "minute",
  "limit": 10,
  "reset_at": "2026-04-23T18:41:00.000Z",
  "retry_after_seconds": 32
}

…and headers:

Retry-After: 32
X-RateLimit-Limit: 10
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1745433660

Claude, when you see a 429: wait retry_after_seconds (or the Retry-After header) before retrying. Don’t burst-retry — you’ll just keep getting 429s.

Endpoints

GET /me

Required scope: any (authenticated).

Confirms the key is valid and returns who it’s acting as. Great first call from a new client to verify connectivity.

Response 200:

{
  "key_id": "9f2e…",
  "scope": "organization",
  "user_id": "51a7…",
  "organization_id": "c0d1…",
  "organization_name": "Acme Inc",
  "organization_slug": "acme",
  "scopes": ["processes:read", "processes:write"]
}

For personal keys, organization_* fields are null.

GET /processes

Required scope: processes:read.

Lists processes visible to the actor, paginated.

Query parameters:

ParamTypeDefaultNotes
limitinteger251–100
cursorISO 8601nullPass next_cursor from the previous page
visibilitystringnullFilter: public / organization / private / unlisted
qstringnullTitle search (ILIKE)

Response 200:

{
  "items": [
    {
      "id": "proc-abc…",
      "slug": "how-to-onboard-a-new-client",
      "short_id": "a1b2c3",
      "title": "How to onboard a new client",
      "visibility": "organization",
      "organization_id": "c0d1…",
      "created_by": "51a7…",
      "step_count": 8,
      "featured_image": "https://…",
      "category": "onboarding",
      "created_at": "2026-04-10T14:22:18Z",
      "updated_at": "2026-04-22T09:05:40Z",
      "url": "https://www.whatstheprocessfor.com/process/a1b2c3"
    }
  ],
  "next_cursor": "2026-04-10T14:22:18Z"
}

next_cursor is null when there are no more pages.

GET /processes/:id

Required scope: processes:read.

Full process document with its steps. Returns 404 if the process doesn’t exist or 403 if the key’s actor doesn’t have view permission.

Response 200:

{
  "id": "proc-abc…",
  "slug": "how-to-onboard-a-new-client",
  "short_id": "a1b2c3",
  "title": "How to onboard a new client",
  "content": "Detailed intro text…",
  "visibility": "organization",
  "organization_id": "c0d1…",
  "created_by": "51a7…",
  "step_count": 8,
  "featured_image": "https://…",
  "category": "onboarding",
  "created_at": "2026-04-10T14:22:18Z",
  "updated_at": "2026-04-22T09:05:40Z",
  "url": "https://www.whatstheprocessfor.com/process/a1b2c3",
  "steps": [
    {
      "step_number": 1,
      "step_title": "Send welcome email",
      "step_description": "Use the template at…",
      "step_image": "https://…",
      "step_video": "https://youtube.com/watch?v=…"
    }
  ]
}

POST /uploads

Required scope: processes:write.

Upload an image and receive a public URL you can pass as featured_image or step_image when creating or updating a process. This is the recommended way to attach images you don’t already host somewhere — the process create/update endpoints only accept reachable URLs, so without this endpoint you’d need your own image host first.

Request: multipart/form-data with a file field.

FieldTypeNotes
filefileRequired. JPEG, PNG, GIF, or WebP. Max 10 MB.

Response 201:

{
  "url": "https://…supabase.co/storage/v1/object/public/process-images/…",
  "path": "user-id/api/1745433660-screenshot.png",
  "content_type": "image/png",
  "size_bytes": 184320
}

Errors:

  • 400 — missing file, wrong content-type, unsupported MIME type, or > 10 MB
  • 401 — missing/invalid key
  • 403 — key lacks processes:write
  • 429 — rate limit hit (uploads count against the same per-minute / per-day quota)

The returned url is permanent and public; safe to embed anywhere. The upload counts against the actor’s plan storage the same way an in-app upload does.

POST /processes

Required scope: processes:write.

Create a process. For org keys, the process belongs to the org and defaults to organization visibility. For personal keys, it defaults to public visibility and has no org. Override with explicit visibility.

Request body:

{
  "title": "How to onboard a new client",
  "description": "Short summary shown in listings",
  "content": "Optional long-form intro text",
  "category": "onboarding",
  "visibility": "organization",
  "featured_image": "https://…",
  "steps": [
    {
      "step_title": "Send welcome email",
      "step_description": "Use the template at…",
      "step_image": "https://…",
      "step_video": "https://youtube.com/watch?v=…"
    }
  ]
}

Required: title, steps (1–50 items). Each step needs a step_title. Any image or video URL you pass must be reachable (2xx on a HEAD request) or the request is rejected with 400.

Response 201:

{
  "id": "proc-new…",
  "slug": "how-to-onboard-a-new-client",
  "short_id": "x9y8z7",
  "title": "How to onboard a new client",
  "visibility": "organization",
  "organization_id": "c0d1…",
  "step_count": 1,
  "featured_image": "https://…",
  "created_at": "2026-04-23T19:00:00Z",
  "url": "https://www.whatstheprocessfor.com/process/x9y8z7"
}

PUT /processes/:id

Required scope: processes:write.

Update any of: title, content, description, category, visibility, step_count, featured_image. Omitted fields are left unchanged. Requires edit permission on the process (owner, org admin, or the process’s created_by — same rules as the web UI).

Each update creates a version snapshot, so previous states are recoverable.

Response 200:

{ "id": "proc-new…", "updated_at": "2026-04-23T19:05:12Z" }

DELETE /processes/:id

Required scope: processes:delete.

Permanent delete. Requires full permission on the process. There is no undo via the API — recovery requires admin intervention. Prefer setting visibility: "private" via PUT if you just want to hide something.

Response 200:

{ "id": "proc-new…", "deleted": true }

POST /processes/:id/publish

Required scope: processes:write.

Sets the process’s visibility. Defaults to public when no body is sent. Use this when you want a single explicit “publish” call instead of a PUT with a visibility field. Processes are reachable at their URL the moment they’re created, so this endpoint is really just a visibility flip.

{ "visibility": "public" }

Response 200:

{ "id": "proc-new…", "visibility": "public", "published": true }

Workflows

A workflow is an ordered group of processes used for training and onboarding. Each workflow lives inside one organization, has a name + description, holds an ordered list of processes (workflow_processes with a position integer), and tracks per-user completion (workflow_progress).

All workflow endpoints require an organization-scoped key. Role gates are the same as the dashboard:

  • Owner / admin — create, edit, delete workflows; grant or revoke per-user permissions; invite + remove members.
  • Owner / admin / manager — add, remove, reorder processes inside a workflow; mark or unmark progress for any user.
  • Any active member — list workflows, fetch a workflow’s contents, mark or unmark their own progress.

GET /workflows

Required scope: workflows:read.

Lists workflows in the calling key’s organization, paginated.

Query parameters:

ParamTypeDefaultNotes
limitinteger251–100
cursorISO 8601nullPass next_cursor from previous page
qstringnullName search (ILIKE)
include_inactivebooleanfalseInclude archived (is_active = false)

Response 200:

{
  "items": [
    {
      "id": "wf-abc…",
      "organization_id": "c0d1…",
      "name": "New hire onboarding",
      "description": "Day-1 through week-2 checklist",
      "is_active": true,
      "created_by": "51a7…",
      "created_at": "2026-04-10T14:22:18Z",
      "updated_at": "2026-04-22T09:05:40Z"
    }
  ],
  "next_cursor": "2026-04-10T14:22:18Z"
}

POST /workflows

Required scope: workflows:write. Owner / admin only.

{
  "name": "New hire onboarding",
  "description": "Day-1 through week-2 checklist",
  "is_active": true
}

URLs in name or description are rejected. is_active defaults to true.

GET /workflows/:id

Required scope: workflows:read. Returns the workflow + its ordered processes (with a snapshot of each linked process):

{
  "workflow": { "id": "wf-abc…", "name": "New hire onboarding", "...": "..." },
  "processes": [
    {
      "id": "wp-1…",
      "workflow_id": "wf-abc…",
      "process_id": "proc-1…",
      "position": 0,
      "is_required": true,
      "estimated_duration_minutes": 15,
      "added_at": "2026-04-10T14:25:00Z",
      "processes": {
        "id": "proc-1…",
        "slug": "send-welcome-email",
        "short_id": "a1b2c3",
        "title": "Send welcome email",
        "visibility": "organization",
        "status": "published",
        "step_count": 4,
        "featured_image": "https://…"
      }
    }
  ]
}

PUT /workflows/:id

Required scope: workflows:write. Owner / admin only. Body accepts any of name, description, is_active. Omitted fields are left unchanged.

DELETE /workflows/:id

Required scope: workflows:delete. Owner / admin only. Cascades to workflow_processes and workflow_progress. There is no undo.

POST /workflows/:id/processes

Required scope: workflows:write. Owner / admin / manager. Adds a process to the workflow. Inserts at end-of-list unless position is provided.

{
  "process_id": "proc-1…",
  "position": 0,
  "is_required": true,
  "estimated_duration_minutes": 15
}

A process can only appear once in a given workflow (409 on duplicate). Private processes that don’t belong to the org cannot be added.

PUT /workflows/:id/processes/reorder

Required scope: workflows:write. Owner / admin / manager. Pass the full ordered list of process_id values; the API sets position to each item’s array index.

{ "process_ids": ["proc-1…", "proc-3…", "proc-2…"] }

DELETE /workflows/:id/processes/:processId

Required scope: workflows:write. Owner / admin / manager. Removes the link only — the underlying process is untouched.

GET /workflows/:id/permissions

Required scope: workflows:read. Owner / admin only.

Lists per-user permission grants on this workflow (separate from the catch-all org-role gate, which always applies). Useful when you want to give a member access to a specific workflow without elevating their org role.

PUT /workflows/:id/permissions

Required scope: workflows:write. Owner / admin only. Idempotent — if the user already has a grant on this workflow it is updated.

{ "user_id": "51a7…", "permission_level": "edit" }

permission_level is one of view, execute, edit, full.

DELETE /workflows/:id/permissions/:userId

Required scope: workflows:write. Owner / admin only.

POST /workflows/:id/progress

Required scope: workflows:write.

Marks a process_id complete for user_id inside this workflow. Members can mark their own progress; owner / admin / manager can mark for any user in the org. The process must already be linked to the workflow.

{
  "user_id": "51a7…",
  "process_id": "proc-1…",
  "notes": "Completed during week-1 walkthrough"
}

Duplicate marks return 409.

DELETE /workflows/:id/progress

Required scope: workflows:write. Same role rules as marking. Pass the target in the body so callers can unmark idempotently:

{ "user_id": "51a7…", "process_id": "proc-1…" }

Members

All member endpoints require an organization-scoped key.

GET /members

Required scope: members:read. Any active member can list.

{
  "items": [
    {
      "id": "uo-1…",
      "user_id": "51a7…",
      "role": "admin",
      "status": "active",
      "joined_at": "2026-01-12T09:00:00Z",
      "full_name": "Alex Doe",
      "avatar_url": "https://…"
    }
  ]
}

PUT /members/:userId

Required scope: members:write. Owner / admin only.

{ "role": "manager" }

Allowed roles: admin, manager, member. Ownership transfer is not supported via the API. Admins cannot mutate other admins or the owner. You cannot change your own role.

DELETE /members/:userId

Required scope: members:delete. Owner / admin only.

Removes the member from the org. Cannot remove the owner or yourself. Admins cannot remove other admins.

GET /invites

Required scope: members:read. Owner / admin only. Lists pending invites (unaccepted, not yet expired or otherwise).

POST /invites

Required scope: members:write. Owner / admin only. Creates an invite, sends a branded invite email, and returns the invite row plus invite_link so you can share it manually if delivery fails.

{ "email": "new.hire@example.com", "role": "member" }

Returns 403 if the org’s plan user-cap is already reached, 409 if a non-expired invite already exists for that email.

DELETE /invites/:id

Required scope: members:delete. Owner / admin only. Revokes a pending invite by ID.

Errors

All error responses share a consistent envelope:

{ "error": "Human-readable message", "details": "…optional context…" }
StatusMeaning
400Bad request (missing field, invalid URL, >50 steps, etc.)
401Missing/invalid/revoked API key
403Missing scope, or actor lacks permission on the resource
404Resource not found
409Conflict (duplicate pending request, already-approved, etc.)
429Rate limit exceeded — see the Retry-After header
500Server error (please report if persistent)

Versioning

The current version is v1, served at /api/v1/*. Breaking changes would land under /api/v2 and leave v1 working for at least 12 months after announcement. Follow the API changelog at /developers#changelog.

Quick examples

whoami

curl -H "Authorization: Bearer wtpf_..." \
  https://www.whatstheprocessfor.com/api/v1/me

Create a process

curl -X POST \
  -H "Authorization: Bearer wtpf_..." \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Morning standup checklist",
    "steps": [
      { "step_title": "Open Jira board" },
      { "step_title": "Each team member gives a 30-sec update" },
      { "step_title": "Flag blockers in #standup" }
    ]
  }' \
  https://www.whatstheprocessfor.com/api/v1/processes

Upload an image, then attach it to a new process

# 1. Upload the image — the response gives you a public URL
UPLOAD=$(curl -s -X POST \
  -H "Authorization: Bearer wtpf_..." \
  -F "file=@/path/to/screenshot.png" \
  https://www.whatstheprocessfor.com/api/v1/uploads)

IMAGE_URL=$(echo "$UPLOAD" | jq -r .url)

# 2. Use that URL as featured_image when creating a process
curl -X POST \
  -H "Authorization: Bearer wtpf_..." \
  -H "Content-Type: application/json" \
  -d "{
    \"title\": \"Onboarding flow\",
    \"featured_image\": \"$IMAGE_URL\",
    \"steps\": [{ \"step_title\": \"Send welcome email\", \"step_image\": \"$IMAGE_URL\" }]
  }" \
  https://www.whatstheprocessfor.com/api/v1/processes

Claude, when a user gives you a local file path or a screenshot to attach: upload it via POST /uploads first, then pass the returned url into featured_image or step_image. Don’t try to embed base64 — the process endpoints only accept HTTP(S) URLs.

Find and publish a draft

# List drafts
curl -H "Authorization: Bearer wtpf_..." \
  "https://www.whatstheprocessfor.com/api/v1/processes?visibility=private&q=standup"

# Publish by ID
curl -X POST \
  -H "Authorization: Bearer wtpf_..." \
  -H "Content-Type: application/json" \
  -d '{ "visibility": "public" }' \
  https://www.whatstheprocessfor.com/api/v1/processes/proc-abc/publish