API Reference

Base URL

text
https://your-hyphen.example.com

Most applications call the gateway origin (https://<gateway>) with an API key or publishable key. The gateway serves the runtime routes and adds the /sdk/*, /forms/*, and /process-studio/* browser surfaces. Self-hosted customers can also call the private runtime endpoint supplied with their deployment. The route lists below say which origin serves each group.

Authentication

Hyphen supports two public access patterns:

  • Gateway mode: Authorization: Bearer sk-hyp-* (gateway injects tenant context)
  • SDK mode: publishable key pk_live_* (org resolved server-side, scoped access)

Private runtime integrations follow the access policy supplied with the self-hosted deployment. Requests include X-Org-Id as organization context.

Admin routes are available where platform-level administration is enabled.


Core Engine Endpoints

Health

  • GET /health
  • GET /health/ready
  • GET /builtin-actions

Workflows and Runs

  • POST /workflows
  • GET /workflows
  • GET /workflows/:id
  • PUT /workflows/:id
  • DELETE /workflows/:id
  • POST /workflows/:id/execute (body must be { "input": { ... } }, with the optional batch run fields); answers 202 with the run (id, status, input)

Workflow definitions accept the built-in step kinds matcher, nway_match, loop, PbotApproval, PbotForm, and custom-table; see Primitives.

Batch runs

POST /workflows/:id/execute accepts optional fields that tie a run to one business batch, such as a settlement cycle or a statement number.

Field Type Required Description
input object Yes The run input
source_batch_id string No Business batch id, up to 200 characters. Makes the run idempotent per workflow for that batch
replay_of string No Id of an earlier run of this workflow. Starts a new run of that batch on purpose
replay_reason string With replay_of Why the batch runs again, up to 1,000 characters. Recorded on the new run
idempotency_key string No With replay_of: 8 to 200 characters. A retried replay request with the same key returns the replay it started instead of starting another
json
{
  "input": {
    "ledger": "doc:doc_a1b2c3d4e5f6@3",
    "statement": "doc:doc_f6e5d4c3b2a1@1"
  },
  "source_batch_id": "statement-2026-10-09"
}
  • Same source_batch_id, same input: returns the existing run (same id, with the same fields a new start returns) instead of starting another, whatever that run's status.
  • Same source_batch_id, different input: 409 with code BATCH_SOURCE_CONFLICT. No run starts. error.details.existing_run_id names the run that holds the batch.
  • Unpinned document: with source_batch_id set, every doc: reference in the input must name a version (doc:doc_xxx@N). An unpinned reference returns 422 with code BATCH_REFERENCE_UNPINNED.
  • Replay: replay_of starts a new run even when the batch already has one. Send idempotency_key with it to make retries safe: the same key returns the same replay, a new key starts another, and without a key every call is a new replay. The new run records replay_of (the original run's id, also when you replay a replay), and its context carries __replay with replay_of and reason. An id that is not a run of this workflow returns 404 with code REPLAY_SOURCE_NOT_FOUND.

Approvals and Forms

  • GET /approvals: List all pending approvals for the org
  • POST /approvals/:runId/:stepId
  • GET /approvals/:runId
  • GET /forms/:runId/:stepId: The schema of a paused PbotForm step
  • POST /forms/:runId/:stepId/submit (body: { "data": { ... } })
  • GET /forms/pending
  • POST /forms/generate: Build a form_schema_v1 document from an intent; needs the agent_forms feature

External Forms

  • POST /external-forms: Create an intake form. trigger_workflow_id starts a workflow on submit; trigger_process_id starts a published Process Studio case. Never both
  • GET /external-forms, GET /external-forms/:id, PUT /external-forms/:id, DELETE /external-forms/:id
  • POST /external-forms/:id/submit: Answers 201 with submission_id, triggered_run_id, and triggered_execution_type
  • GET /external-forms/:id/submissions

Runs

  • GET /runs/:runId/status: Includes replay_of for a replay, and parent_run_id, parent_step_index, and parent_item_index for a run started by a child-run loop. Each is null otherwise
  • GET /runs/:runId/evidence: The record: every step, decision, and receipt in order

Agents

  • POST /agents/execute: body accepts optional previous_run_id to inject prior run context, and optional documents: up to 10 document ids or doc: references, each attached at a pinned version and named in the objective so its content reaches the agent
  • GET /agents
  • GET /agents/:id/status: response includes previous_run_id when set
  • GET /agents/:id/trace
  • POST /agents/:id/resume
  • DELETE /agents/:id

Actions

  • POST /actions
  • GET /actions
  • GET /actions/:id
  • PUT /actions/:id

Custom Tables

  • POST /custom-tables
  • GET /custom-tables/:name
  • DELETE /custom-tables/:name
  • POST /custom-tables/:name/insert
  • POST /custom-tables/:name/bulk-insert
  • PUT /custom-tables/:name/update
  • GET /custom-tables/:name/rows: List rows (SDK-compatible)
  • POST /custom-tables/:name/rows: Insert a row (SDK-compatible)
  • PATCH /custom-tables/:name/rows/:rowId: Update a row by ID (SDK-compatible)
  • GET /custom-tables/:name/audit

Documents

  • POST /documents
  • POST /documents/from-url
  • POST /documents/bulk-upload
  • GET /documents
  • GET /documents/:id
  • GET /documents/:id/download
  • PATCH /documents/:id
  • POST /documents/:id/versions
  • DELETE /documents/:id
  • GET /documents/:id/audit
  • GET /documents/storage-usage

Webhooks (Registrations)

  • POST /webhooks: a url to notify, or for document.uploaded and document.version_created, a workflow_id to start with the document as input
  • GET /webhooks
  • GET /webhooks/:id
  • PATCH /webhooks/:id
  • DELETE /webhooks/:id

OAuth

  • GET /oauth/providers
  • POST /oauth/:provider/app-credentials
  • GET /oauth/:provider/app-credentials
  • GET /oauth/:provider/authorize
  • GET /oauth/:provider/callback
  • GET /oauth/connections
  • GET /oauth/connections/:provider/:accountId
  • DELETE /oauth/connections/:provider/:accountId
  • POST /oauth/connections/:provider/:accountId/refresh

AI Generation

  • POST /process-studio/processes/create-from-prompt: One-shot creation for API-only tenants. Creates a project if needed, creates the process, drafts a workflow or agent from the prompt, and publishes by default. See Process Studio below.
  • POST /ai/generate-workflow
  • GET /ai/generate-workflow/:generation_id/status
  • GET /ai/generate-workflow/:generation_id
  • POST /workflows/create-from-ai: Legacy compatibility endpoint; not recommended for new integrations and may be unavailable on some deployments.
  • GET /workflows/create-from-ai/:processId
  • GET /workflows/generation-status/:processId

For new API-only workflow and agent creation, prefer POST /process-studio/processes/create-from-prompt. Use the lower-level Process Studio routes only when you need explicit control over the intermediate steps.

Org Config and Schema

  • POST /org-config
  • GET /org-config
  • POST /schemas
  • GET /schemas/:id
  • POST /utils/generate-dag

Process Studio

Served by the engine under /process-studio/*, and forwarded by the gateway under the same path for SDK sessions. This is what the catalog screen, the hosted page, and the MCP server call.

Catalog

  • GET /process-studio/playbook-library: The catalog, paginated with limit and cursor
  • GET /process-studio/playbook-library/:key: One case with its inputs, approval behavior, and version
  • POST /process-studio/processes: Create a process to hold the organization's copy
  • POST /process-studio/processes/:processId/apply-playbook: Prepare the copy of a case, with the organization's content, connections, and people
  • POST /process-studio/bundles/:bundleId/publish: Publish the prepared copy
  • POST /process-studio/processes/:processId/execute: Run the published copy; body { "input": { ... } }. A sample run sends the case's sample rows as the input

Describe your own

  • POST /process-studio/playbook-requests: Send a description; the reply carries the request id and its first status
  • GET /process-studio/playbook-requests, GET /process-studio/playbook-requests/:id: Follow a request: drafting, checking, listed, returned, awaiting_admin, withdrawn
  • POST /process-studio/playbook-requests/:id/retry: Build it again after editing the words
  • POST /process-studio/playbook-requests/:id/withdraw
  • POST /process-studio/playbook-packages/:id/list, .../return, .../retire: An admin lists a held case, returns it with a note, or retires a listed one
  • GET /process-studio/org-policy/describe-your-own, PUT /process-studio/org-policy/describe-your-own: Whether described cases list on their own or wait for the organization's admin

API-only authoring

  • POST /process-studio/processes/create-from-prompt: Create and publish from a prompt in one call

SDK Endpoints

These endpoints are called by the Hyphen SDK using a publishable key (pk_live_*). They provide scoped access to tasks, tables, documents, and authentication for embedded UI components.

These are gateway routes. The gateway resolves the organization from the key and forwards to the engine.

Sessions

  • POST /sdk/auth/session: Create anonymous session
  • GET /sdk/config: Get SDK configuration

Tasks

  • GET /sdk/tasks: List pending tasks; each carries kind: approval, form, or agent_review
  • POST /sdk/tasks/:taskId/decide: Approve or reject a task

Runs

  • GET /sdk/runs/:runId/status: Status of a workflow run
  • GET /sdk/runs/:runId/evidence: The record of a run

Forms

  • GET /sdk/forms/pending: Forms a running case is waiting on
  • GET /sdk/forms/run/:runId/:stepId: The schema of a paused step
  • POST /sdk/forms/run/:runId/:stepId/submit: Settle a paused step; needs a signed-in session
  • POST /sdk/forms/generate: Build a form from an intent
  • GET /sdk/external-forms/:formId, POST /sdk/external-forms/:formId/submit: Intake forms under an SDK session
  • GET /forms/public/:formId, POST /forms/public/:formId/submit: The public intake routes behind the hosted page, no session, rate-limited by IP; /forms/public/:formId/otp/request and /otp/verify when the form requires sign-in

Tables

  • GET /sdk/tables/:name/rows: List table rows (paginated)
  • POST /sdk/tables/:name/rows: Insert a row
  • PATCH /sdk/tables/:name/rows/:rowId: Update a row (inline editing)

Documents

  • GET /sdk/documents: List documents
  • POST /sdk/documents: Upload a document

Authentication

  • POST /sdk/auth/otp/request: Send OTP code to registered email
  • POST /sdk/auth/otp/verify: Verify OTP and upgrade session

Agents

  • POST /sdk/agents/execute: Launch an agent (async, returns agent_run_id). Accepts optional previous_run_id for cross-run context and optional documents (up to 10 uploaded documents to attach)
  • GET /sdk/agents: List agent runs
  • GET /sdk/agents/:agentId/status: Get agent status with reasoning trace
  • GET /sdk/agents/:agentId/trace: Get the complete recorded agent trace
  • POST /sdk/agents/:agentId/resume: Resume a paused agent with human input
  • DELETE /sdk/agents/:agentId: Cancel a running agent

Discovery

  • GET /sdk/actions: List registered actions (for tool picker)
  • GET /sdk/workflows: List workflows (for tool picker)

Events

  • GET /sdk/events: Server-sent event stream (real-time updates)

Gateway Endpoints

  • GET /health
  • POST /gateway/signup
  • Hosted pages: GET /process-studio/v5.html, GET /forms/:formId, GET /people (account holder, management token), GET /sdk/v1.js
  • People session (management token in): POST /gateway/account/people-session returns a fifteen-minute ps-hyp-… token accepted only on the SDK user routes below and GET /gateway/orgs; DELETE revokes it
  • SDK users (super admin key, the owning account's management token, or a people session): POST and GET /sdk/admin/publishable-keys/:keyId/users, PUT /sdk/admin/users/:userId, POST /sdk/admin/users/:userId/suspend, POST /sdk/admin/users/:userId/reactivate, DELETE /sdk/admin/users/:userId
  • Tenant (management token): /gateway/account, /gateway/orgs, /gateway/orgs/:orgId/keys, /gateway/orgs/:orgId/usage, /gateway/licenses
  • Licensing: POST /licensing/validate, GET /licensing/public-key

Error Shape

Errors raised while handling a request carry an object with a stable code to branch on and a message for people, plus hint and details when the error has them:

json
{
  "error": {
    "code": "BATCH_SOURCE_CONFLICT",
    "message": "This batch was already started with different source data",
    "details": { "existing_run_id": "run-3f2b1c9e-8d4a-4c1e-9b7a-2e6f5d4c3b2a" }
  }
}

A request body refused by request validation, and an error the gateway returns itself (authentication, key scope, rate limits), carry a string instead, sometimes with hint, code, or statusCode beside it:

json
{ "error": "\"input\" is required" }

Read error.code when error is an object, and error itself when it is a string. An unexpected failure answers 500 with { "error": { "code": "internal_error", "message": "..." } }.