openapi: 3.1.0 info: title: 'Integrations Service API' description: 'API for the revenexx Integration Studio — connects Revenue Cloud to external systems (ERP, PIM, CRM) via Temporal workflows.' version: 1.0.0 servers: - url: 'https://integrations.revenexx.com' tags: - name: 'Audit Log' description: "\nRead access to the append-only audit trail (credential / secret / workflow /\ntrigger create-edit-delete, plus workflow run start/finished/failed). Two\nplanes: the public feed is auto-scoped to the caller's org + tenant; the\nadmin feed (registered under `v1/admin`) filters all three identity fields\noptionally. Results are newest-first and cursor-paginated." - name: Auth description: "\nEndpoints for verifying authentication and tenant context." - name: 'Credential Types' description: "\nRead-only catalogue of the credential types registered via node packages.\nDrives the credential form (fields + validation) and the `credentials-ref`\ntype picker in the editor. Globally registered, not tenant-scoped." - name: Credentials description: "\nTenant-scoped credential instances of a registered {@see CredentialType}.\nThe encrypted `config` / `durable_creds` blobs are never returned. Runtime\nresolution happens in the broker, not here — this controller only stores and\nproxies the on-demand connection test." - name: 'Node Packages' description: '' - name: Nodes description: "\nGlobally registered node definitions, addressed publicly by\n`/`. Read endpoints additionally accept the alias\n`latest` in place of an explicit version. The `DELETE` endpoint refuses\nthe alias and requires an exact version, so the caller always knows which\nrow they're touching.\n\nNodes are created and updated exclusively through the node-package upload\n(`POST /v1/admin/orgs/{org_id}/node-packages`), which extracts the manifests\nfrom the published tarball — there is no standalone create/update endpoint,\nsince a node always ships with its runtime code.\n\nAuthentication is required for every endpoint, but the resource itself\nis *not* tenant-scoped — per-tenant entitlement (which tenant may use\nwhich node) is the responsibility of a future app-registration flow." - name: Schemas description: "\nPublic, read-only access to the JSON-Schema definitions used to validate\nversioned payloads (currently the workflow `blob` and the node manifest).\nSchemas are global — they describe the shape of payloads regardless of\ntenant — so these endpoints are intentionally unauthenticated." - name: Templates description: "\nCatalogue of the workflow templates registered via node packages, plus the\n\"install\" actions a UI uses to turn one into a real workflow. Listing/showing\nis global; instantiation is scoped to the current tenant." - name: 'Tenant Secrets' description: "\nPer-tenant encrypted key/value store. Values are AES-256-GCM encrypted at\nrest using a dedicated SECRETS_ENCRYPTION_KEY (separate from APP_KEY) and\nare never returned by the API." - name: Triggers description: "\nManage triggers for a workflow. Triggers are the entry points that can start\na workflow execution (manual, schedule, webhook, or event). They live as DB entities\nrather than inside the workflow blob, and are referenced in blob edges via\ntheir stable UUID handle." - name: Webhooks description: "\nInbound endpoint that fires a workflow run for a webhook trigger. The\ntrigger is addressed by its UUID handle in the URL; authentication is the\nstandard JWT + `X-Tenant-Id` used by the rest of the API, so the trigger is\nresolved within the caller's tenant. The HTTP request (body, query,\nheaders, method) is delivered to the workflow as the trigger payload,\nreachable via `${{ trigger.payload.* }}`." - name: 'Workflow Credentials' description: "\nRead-only introspection of which typed credentials a workflow's nodes\nreference through their `credentials-ref` config fields. Useful for pre-run\nchecks, access auditing, and impact analysis when a credential instance is\nrotated or deleted. The credential *values* are never touched here — only\nthe instance UUIDs and their credential type slugs are reported." - name: 'Workflow Revisions' description: "\nRead the archived revision history of a workflow and restore an old\nrevision. Every blob change to a workflow snapshots the previous revision\ninto `workflow_histories`; these endpoints expose that history and let a\nclient re-apply an old revision as a brand-new one.\n\nAll endpoints are scoped to the tenant resolved by the `resolve.tenant`\nmiddleware. Cross-tenant access returns 404 so the API never leaks the\nexistence of resources owned by other tenants." - name: 'Workflow Runs' description: "\nTrigger and inspect executions of a workflow. Each run is handed off to\nthe workflow's dedicated Temporal worker, which orchestrates node\nexecution and streams status back." - name: Workflows description: "\nPer-tenant workflow definitions. Every endpoint is scoped to the tenant\nresolved by the `resolve.tenant` middleware (from the JWT or\n`X-Tenant-Id` header). Cross-tenant access deliberately returns 404 so\nthat the API does not leak the existence of resources owned by other\ntenants." components: securitySchemes: default: type: http scheme: bearer description: 'Authenticate via a Zitadel-issued OIDC JWT. Tenant context is taken from the `X-Tenant-Id` request header; the `tenant_id` JWT claim is accepted as a legacy fallback for development tokens.' responses: TooManyRequests: description: 'Too many requests — the rate limit has been exceeded. Wait for the period in the Retry-After header before retrying. The authenticated API allows 300 requests/minute (30/second burst) per user.' headers: Retry-After: description: 'Seconds to wait before retrying.' schema: type: integer content: application/json: schema: type: object properties: message: type: string example: message: 'Too Many Attempts.' security: - default: [] paths: /api/v1/audit-logs: get: summary: 'List audit entries (public)' operationId: listAuditEntriespublic description: "Returns the audit entries for the caller's org + tenant, newest first.\nOptionally narrowed by `sub` (actor), `resource_type` and `action`." parameters: - in: query name: sub description: 'optional Filter by acting user subject.' required: false schema: type: string description: 'optional Filter by acting user subject.' examples: - '289347298347' - in: query name: resource_type description: 'optional Filter by resource type (credential, secret, workflow, trigger, workflow_run).' required: false schema: type: string description: 'optional Filter by resource type (credential, secret, workflow, trigger, workflow_run).' examples: - workflow - in: query name: action description: 'optional Filter by action (create, update, delete, run.started, run.finished, run.failed).' required: false schema: type: string description: 'optional Filter by action (create, update, delete, run.started, run.finished, run.failed).' examples: - create - in: query name: limit description: 'optional Page size (1–100, default 50).' required: false schema: type: integer description: 'optional Page size (1–100, default 50).' examples: - 50 - in: query name: cursor description: 'optional Opaque pagination cursor from a previous response.' required: false schema: type: string description: 'optional Opaque pagination cursor from a previous response.' examples: - eyJpZCI6NDJ9 - in: header name: X-Tenant-Id description: '' schema: type: string examples: - acme-production responses: 200: description: Success content: application/json: schema: type: object properties: data: type: array items: type: object properties: id: type: integer examples: - 42 org_id: type: string examples: - acme-org tenant_id: type: string examples: - acme-production actor_sub: type: - string - 'null' description: 'The acting user subject (`sub`); null for system-initiated entries (`via_system` = true).' examples: - '289347298347' via_system: type: boolean examples: - false channel: type: string examples: - api action: type: string examples: - create resource_type: type: string examples: - workflow resource_id: type: string examples: - '1' metadata: type: - object - 'null' properties: name: type: string examples: - 'Sync orders' description: 'Action-specific detail recorded with the entry; null when none was captured.' created_at: type: string examples: - '2026-06-18T10:00:00Z' examples: - - id: 42 org_id: acme-org tenant_id: acme-production actor_sub: '289347298347' via_system: false channel: api action: create resource_type: workflow resource_id: '1' metadata: name: 'Sync orders' created_at: '2026-06-18T10:00:00Z' meta: type: object properties: per_page: type: integer examples: - 50 next_cursor: type: - string - 'null' examples: - null prev_cursor: type: - string - 'null' examples: - null examples: - data: - id: 42 org_id: acme-org tenant_id: acme-production actor_sub: '289347298347' via_system: false channel: api action: create resource_type: workflow resource_id: '1' metadata: name: 'Sync orders' created_at: '2026-06-18T10:00:00Z' meta: per_page: 50 next_cursor: null prev_cursor: null 429: $ref: '#/components/responses/TooManyRequests' tags: - 'Audit Log' /api/v1/me: get: summary: 'Get authenticated user info' operationId: getAuthenticatedUserInfo description: "Returns full user profile, resolved tenant context, and raw token claims.\nUseful for debugging authentication and understanding which data Zitadel provides." parameters: - in: header name: X-Tenant-Id description: '' schema: type: string examples: - acme-production responses: 200: description: Success content: application/json: schema: type: object properties: user: type: object properties: id: type: integer examples: - 1 zitadel_id: type: string examples: - '289347298347' email: type: string examples: - user@acme.com name: type: string examples: - 'Jane Doe' context: type: object properties: tenant_id: type: string examples: - acme-production active_plane: type: string examples: - public roles: type: array items: type: string examples: - - admin - user claims: type: object properties: iss: type: string examples: - 'https://id.revenexx.com' sub: type: string examples: - '289347298347' aud: type: array items: type: string examples: - - project-id examples: - user: id: 1 zitadel_id: '289347298347' email: user@acme.com name: 'Jane Doe' context: tenant_id: acme-production active_plane: public roles: - admin - user claims: iss: 'https://id.revenexx.com' sub: '289347298347' aud: - project-id 401: description: 'Missing or invalid token' content: application/json: schema: type: object properties: message: type: string examples: - Unauthenticated. examples: - message: Unauthenticated. 429: $ref: '#/components/responses/TooManyRequests' tags: - Auth /api/v1/credential-types: get: summary: 'List credential types' operationId: listCredentialTypes description: 'Returns the latest registered version of each credential type.' parameters: - in: header name: X-Tenant-Id description: '' schema: type: string examples: - acme-production responses: 200: description: Success content: application/json: schema: type: object properties: data: type: array items: type: object properties: slug: type: string examples: - 'revenexx:smtp' version: type: string examples: - 1.0.0 name: type: string examples: - SMTP description: type: string examples: - 'Send mail over SMTP' icon: type: - string - 'null' examples: - null auth_kind: type: string examples: - secret fields: type: array examples: - [] examples: - - slug: 'revenexx:smtp' version: 1.0.0 name: SMTP description: 'Send mail over SMTP' icon: null auth_kind: secret fields: [] examples: - data: - slug: 'revenexx:smtp' version: 1.0.0 name: SMTP description: 'Send mail over SMTP' icon: null auth_kind: secret fields: [] 429: $ref: '#/components/responses/TooManyRequests' tags: - 'Credential Types' '/api/v1/credential-types/{slug}': get: summary: 'Show a credential type' operationId: showACredentialType description: "Returns the latest registered version of the credential type identified\nby its namespaced slug." parameters: - in: header name: X-Tenant-Id description: '' schema: type: string examples: - acme-production responses: 200: description: Success content: application/json: schema: type: object properties: data: type: object properties: slug: type: string examples: - 'revenexx:smtp' version: type: string examples: - 1.0.0 name: type: string examples: - SMTP description: type: string examples: - 'Send mail over SMTP' icon: type: - string - 'null' examples: - null auth_kind: type: string examples: - secret fields: type: array examples: - [] examples: - data: slug: 'revenexx:smtp' version: 1.0.0 name: SMTP description: 'Send mail over SMTP' icon: null auth_kind: secret fields: [] 404: description: 'Not found' content: application/json: schema: type: object properties: message: type: string examples: - 'Not found.' examples: - message: 'Not found.' 429: $ref: '#/components/responses/TooManyRequests' tags: - 'Credential Types' parameters: - in: path name: slug description: 'Namespaced credential type slug.' required: true schema: type: string examples: - 'revenexx:smtp' /api/v1/credentials/oauth/callback: get: summary: 'OAuth redirect callback (public)' operationId: oAuthRedirectCallbackpublic description: "The provider redirects the user's browser here with `code` + `state`.\nUnauthenticated by necessity — the single-use `state` (looked up in the\ncache) is the CSRF protection and carries the tenant + PKCE verifier." parameters: - in: header name: X-Tenant-Id description: '' schema: type: string examples: - acme-production responses: 200: description: Connected content: application/json: schema: type: object properties: status: type: string examples: - connected credential_id: type: integer examples: - 1 examples: - status: connected credential_id: 1 400: description: 'Missing or invalid state' content: application/json: schema: type: object properties: message: type: string examples: - 'Invalid or expired OAuth state.' examples: - message: 'Invalid or expired OAuth state.' tags: - Credentials security: [] /api/v1/credentials: get: summary: 'List credentials' operationId: listCredentials description: "Returns the current tenant's credential instances, optionally filtered to\na single credential type via `?type={slug}`. Secrets are never exposed." parameters: - in: query name: type description: 'Filter by credential type slug.' required: false schema: type: string description: 'Filter by credential type slug.' examples: - 'revenexx:smtp' - in: header name: X-Tenant-Id description: '' schema: type: string examples: - acme-production responses: 200: description: Success content: application/json: schema: type: object properties: data: type: array items: type: object properties: id: type: integer examples: - 1 tenant_id: type: string examples: - acme-production credential_type_slug: type: string examples: - 'revenexx:smtp' name: type: string examples: - 'Production SMTP' status: type: string examples: - active public_config: type: object properties: { } created_at: type: string examples: - '2026-05-06T10:00:00Z' updated_at: type: string examples: - '2026-05-06T10:00:00Z' examples: - - id: 1 tenant_id: acme-production credential_type_slug: 'revenexx:smtp' name: 'Production SMTP' status: active public_config: [] created_at: '2026-05-06T10:00:00Z' updated_at: '2026-05-06T10:00:00Z' examples: - data: - id: 1 tenant_id: acme-production credential_type_slug: 'revenexx:smtp' name: 'Production SMTP' status: active public_config: { } created_at: '2026-05-06T10:00:00Z' updated_at: '2026-05-06T10:00:00Z' 401: description: 'Missing or invalid token' content: application/json: schema: type: object properties: message: type: string examples: - Unauthenticated. examples: - message: Unauthenticated. 429: $ref: '#/components/responses/TooManyRequests' tags: - Credentials post: summary: 'Create a credential' operationId: createACredential description: "Validates the submitted `config` against the credential type's declared\nfields, then stores it encrypted. Returns 201 with the masked instance." parameters: - in: header name: X-Tenant-Id description: '' schema: type: string examples: - acme-production responses: 201: description: Created content: application/json: schema: type: object properties: id: type: integer examples: - 1 tenant_id: type: string examples: - acme-production credential_type_slug: type: string examples: - 'revenexx:smtp' name: type: string examples: - 'Production SMTP' status: type: string examples: - active public_config: type: object properties: { } created_at: type: string examples: - '2026-05-06T10:00:00Z' updated_at: type: string examples: - '2026-05-06T10:00:00Z' examples: - id: 1 tenant_id: acme-production credential_type_slug: 'revenexx:smtp' name: 'Production SMTP' status: active public_config: { } created_at: '2026-05-06T10:00:00Z' updated_at: '2026-05-06T10:00:00Z' 422: description: 'Validation failed' content: application/json: schema: type: object properties: message: type: string examples: - 'The given data was invalid.' errors: type: object properties: config: type: array items: type: string examples: - - ... examples: - message: 'The given data was invalid.' errors: config: - ... 429: $ref: '#/components/responses/TooManyRequests' tags: - Credentials requestBody: required: true content: application/json: schema: type: object properties: credential_type_slug: type: string description: 'Slug of a registered credential type the instance is created for. The slug of an existing record in the credential_types table.' examples: - 'revenexx:smtp' name: type: string description: 'Human-readable label, unique per tenant. Must not be greater than 191 characters.' examples: - Mailpit config: type: object description: 'Connection data for the credential type. The accepted fields are defined by the type manifest; stored encrypted and never returned.' properties: { } examples: - host: smtp.example.com port: 587 username: mailer password: sekret required: - credential_type_slug - name - config /api/v1/credentials/test: post: summary: 'Test an unsaved credential' operationId: testAnUnsavedCredential description: "Runs the broker connection test against an inline type + config, before\nthe instance is persisted. Non-blocking." parameters: - in: header name: X-Tenant-Id description: '' schema: type: string examples: - acme-production responses: 200: description: Tested content: application/json: schema: type: object properties: ok: type: boolean examples: - true examples: - ok: true 429: $ref: '#/components/responses/TooManyRequests' tags: - Credentials requestBody: required: true content: application/json: schema: type: object properties: credential_type_slug: type: string description: 'Slug of the credential type to test the inline config against. The slug of an existing record in the credential_types table.' examples: - 'revenexx:smtp' config: type: object description: "Inline connection data to exercise the type's connection test, before any instance is persisted." properties: { } examples: - host: smtp.example.com port: 587 username: mailer password: sekret required: - credential_type_slug - config '/api/v1/credentials/{id}': get: summary: 'Show a credential' operationId: showACredential description: '' parameters: - in: header name: X-Tenant-Id description: '' schema: type: string examples: - acme-production responses: 200: description: Success content: application/json: schema: type: object properties: id: type: integer examples: - 1 tenant_id: type: string examples: - acme-production credential_type_slug: type: string examples: - 'revenexx:smtp' name: type: string examples: - 'Production SMTP' status: type: string examples: - active public_config: type: object properties: { } created_at: type: string examples: - '2026-05-06T10:00:00Z' updated_at: type: string examples: - '2026-05-06T10:00:00Z' examples: - id: 1 tenant_id: acme-production credential_type_slug: 'revenexx:smtp' name: 'Production SMTP' status: active public_config: { } created_at: '2026-05-06T10:00:00Z' updated_at: '2026-05-06T10:00:00Z' 404: description: 'Not found' content: application/json: schema: type: object properties: message: type: string examples: - 'Not found.' examples: - message: 'Not found.' 429: $ref: '#/components/responses/TooManyRequests' tags: - Credentials patch: summary: 'Update a credential' operationId: updateACredential description: "Updates the name and/or `config`. When `config` is supplied it is\nre-validated against the credential type's declared fields." parameters: - in: header name: X-Tenant-Id description: '' schema: type: string examples: - acme-production responses: 200: description: Updated content: application/json: schema: type: object properties: id: type: integer examples: - 1 tenant_id: type: string examples: - acme-production credential_type_slug: type: string examples: - 'revenexx:smtp' name: type: string examples: - 'Production SMTP' status: type: string examples: - active public_config: type: object properties: { } created_at: type: string examples: - '2026-05-06T10:00:00Z' updated_at: type: string examples: - '2026-05-06T11:00:00Z' examples: - id: 1 tenant_id: acme-production credential_type_slug: 'revenexx:smtp' name: 'Production SMTP' status: active public_config: { } created_at: '2026-05-06T10:00:00Z' updated_at: '2026-05-06T11:00:00Z' 404: description: 'Not found' content: application/json: schema: type: object properties: message: type: string examples: - 'Not found.' examples: - message: 'Not found.' 422: description: 'Validation failed' content: application/json: schema: type: object properties: message: type: string examples: - 'The given data was invalid.' errors: type: object properties: config: type: array items: type: string examples: - - ... examples: - message: 'The given data was invalid.' errors: config: - ... 429: $ref: '#/components/responses/TooManyRequests' tags: - Credentials requestBody: required: false content: application/json: schema: type: object properties: name: type: string description: 'New human-readable label, unique per tenant. Optional. Must not be greater than 191 characters.' examples: - 'Mailpit (staging)' config: type: object description: 'Replacement connection data, re-validated against the credential type manifest. Optional; stored encrypted and never returned.' properties: { } examples: - host: smtp.example.com port: 587 username: mailer password: sekret delete: summary: 'Delete a credential' operationId: deleteACredential description: '' parameters: - in: header name: X-Tenant-Id description: '' schema: type: string examples: - acme-production responses: 204: description: Deleted content: text/plain: schema: type: string examples: - '' 404: description: 'Not found' content: application/json: schema: type: object properties: message: type: string examples: - 'Not found.' examples: - message: 'Not found.' 429: $ref: '#/components/responses/TooManyRequests' tags: - Credentials parameters: - in: path name: id description: 'The ID of the credential.' required: true schema: type: string examples: - 019f124d-b287-731d-8879-de2bf1fa6924 '/api/v1/credentials/{id}/test': post: summary: 'Test a saved credential' operationId: testASavedCredential description: "Runs the credential type's connection test in the broker against the\nstored config. Non-blocking — does not change the stored instance." parameters: - in: header name: X-Tenant-Id description: '' schema: type: string examples: - acme-production responses: 200: description: Tested content: application/json: schema: type: object properties: ok: type: boolean examples: - true examples: - ok: true 429: $ref: '#/components/responses/TooManyRequests' tags: - Credentials parameters: - in: path name: id description: 'The ID of the credential.' required: true schema: type: string examples: - 019f124d-b287-731d-8879-de2bf1fa6924 '/api/v1/credentials/{id}/oauth/authorize-url': post: summary: 'Begin 3-legged OAuth setup' operationId: begin3LeggedOAuthSetup description: "Returns the provider authorize URL for the credential. The caller (the\ncockpit) opens it; the provider redirects back to the public callback." parameters: - in: header name: X-Tenant-Id description: '' schema: type: string examples: - acme-production responses: 200: description: 'Authorize URL' content: application/json: schema: type: object properties: authorize_url: type: string examples: - 'https://login.example.com/authorize?client_id=...&state=...' examples: - authorize_url: 'https://login.example.com/authorize?client_id=...&state=...' 422: description: 'Not a 3-legged OAuth type' content: application/json: schema: type: object properties: message: type: string examples: - 'Credential type does not use 3-legged OAuth.' examples: - message: 'Credential type does not use 3-legged OAuth.' 429: $ref: '#/components/responses/TooManyRequests' tags: - Credentials parameters: - in: path name: id description: 'The ID of the credential.' required: true schema: type: string examples: - 019f124d-b287-731d-8879-de2bf1fa6924 '/api/v1/node-packages/images/{id}': get: summary: 'Stream a node-package image.' operationId: streamANodePackageImage description: '' parameters: - in: query name: expires description: 'Signed-URL expiry (added by the signer).' required: true schema: type: integer description: 'Signed-URL expiry (added by the signer).' examples: - 16 - in: query name: signature description: 'URL signature (added by the signer).' required: true schema: type: string description: 'URL signature (added by the signer).' examples: - architecto - in: header name: X-Tenant-Id description: '' schema: type: string examples: - acme-production responses: 200: description: 'Valid signature' content: application/json: schema: type: string examples: - '' 403: description: 'Missing, tampered, or expired signature' content: application/json: schema: type: object properties: message: type: string examples: - 'Invalid signature.' examples: - message: 'Invalid signature.' 404: description: 'Unknown image, or stored file missing' content: application/json: schema: type: object properties: message: type: string examples: - 'Not Found' examples: - message: 'Not Found' 429: $ref: '#/components/responses/TooManyRequests' tags: - 'Node Packages' parameters: - in: path name: id description: 'The ID of the image.' required: true schema: type: string examples: - architecto - in: path name: image description: 'The image UUID.' required: true schema: type: string examples: - 9b2e6b1e-6d0a-5f3a-8c1b-2b7f6a1c9d4e /api/v1/nodes: get: summary: 'List nodes' operationId: listNodes description: "Returns the registered nodes ordered by `slug` ascending, then\nsemver descending. Optionally filters to a single namespace via the\n`namespace` query parameter." parameters: - in: query name: namespace description: 'Filter by the slug-derived namespace (e.g. `revenexx`).' required: false schema: type: string description: 'Filter by the slug-derived namespace (e.g. `revenexx`).' examples: - revenexx - in: header name: X-Tenant-Id description: '' schema: type: string examples: - acme-production responses: 200: description: Success content: application/json: schema: type: object properties: data: type: array items: type: object properties: name: type: string examples: - 'HTTP request' namespace: type: string examples: - revenexx slug: type: string examples: - 'revenexx:http-request' version: type: string examples: - 1.0.0 package: type: object properties: name: type: string examples: - '@revenexx/integrations-nodes-core' version: type: string examples: - 0.2.0 label: type: string examples: - Core manifest_version: type: string examples: - v0-draft manifest: type: object properties: { } created_at: type: string examples: - '2026-05-06T10:00:00Z' updated_at: type: string examples: - '2026-05-06T10:00:00Z' examples: - - name: 'HTTP request' namespace: revenexx slug: 'revenexx:http-request' version: 1.0.0 package: name: '@revenexx/integrations-nodes-core' version: 0.2.0 label: Core manifest_version: v0-draft manifest: [] created_at: '2026-05-06T10:00:00Z' updated_at: '2026-05-06T10:00:00Z' examples: - data: - name: 'HTTP request' namespace: revenexx slug: 'revenexx:http-request' version: 1.0.0 package: name: '@revenexx/integrations-nodes-core' version: 0.2.0 label: Core manifest_version: v0-draft manifest: { } created_at: '2026-05-06T10:00:00Z' updated_at: '2026-05-06T10:00:00Z' 401: description: 'Missing or invalid token' content: application/json: schema: type: object properties: message: type: string examples: - Unauthenticated. examples: - message: Unauthenticated. 429: $ref: '#/components/responses/TooManyRequests' tags: - Nodes '/api/v1/nodes/{slug}/versions': get: summary: 'List versions for a node' operationId: listVersionsForANode description: "Returns the registered versions for a given slug, semver-descending.\nThe slug must match at least one stored row, otherwise a 404 is\nreturned — there's no representation for \"an empty list of\nversions\". The response intentionally only contains version\nstrings; callers that need the full row should follow up with\n`GET /nodes/{slug}/{version}`." parameters: - in: header name: X-Tenant-Id description: '' schema: type: string examples: - acme-production responses: 200: description: Success content: application/json: schema: type: object properties: data: type: array items: type: string examples: - - 2.5.0 - 1.10.0 - 1.0.0 examples: - data: - 2.5.0 - 1.10.0 - 1.0.0 404: description: 'Unknown slug' content: application/json: schema: type: object properties: message: type: string examples: - 'Not found.' examples: - message: 'Not found.' 429: $ref: '#/components/responses/TooManyRequests' tags: - Nodes parameters: - in: path name: slug description: 'Full node slug.' required: true schema: type: string examples: - 'revenexx:http-request' '/api/v1/nodes/{slug}/{version}': get: summary: 'Show a node' operationId: showANode description: "Returns a single node by `(slug, version)`. The version may be the\nliteral string `latest`, in which case the highest semver registered\nfor the slug is returned." parameters: - in: header name: X-Tenant-Id description: '' schema: type: string examples: - acme-production responses: 200: description: Success content: application/json: schema: type: object properties: name: type: string examples: - 'HTTP request' namespace: type: string examples: - revenexx slug: type: string examples: - 'revenexx:http-request' version: type: string examples: - 1.0.0 package: type: object properties: name: type: string examples: - '@revenexx/integrations-nodes-core' version: type: string examples: - 0.2.0 label: type: string examples: - Core manifest_version: type: string examples: - v0-draft manifest: type: object properties: { } created_at: type: string examples: - '2026-05-06T10:00:00Z' updated_at: type: string examples: - '2026-05-06T10:00:00Z' examples: - name: 'HTTP request' namespace: revenexx slug: 'revenexx:http-request' version: 1.0.0 package: name: '@revenexx/integrations-nodes-core' version: 0.2.0 label: Core manifest_version: v0-draft manifest: { } created_at: '2026-05-06T10:00:00Z' updated_at: '2026-05-06T10:00:00Z' 404: description: 'Not found' content: application/json: schema: type: object properties: message: type: string examples: - 'Not found.' examples: - message: 'Not found.' 429: $ref: '#/components/responses/TooManyRequests' tags: - Nodes delete: summary: 'Delete a node' operationId: deleteANode description: "Removes the node version identified by `(slug, version)`. The\n`latest` alias is rejected to prevent ambiguous deletes." parameters: - in: header name: X-Tenant-Id description: '' schema: type: string examples: - acme-production responses: 204: description: Deleted content: text/plain: schema: type: string examples: - '' 400: description: 'Latest alias rejected' content: application/json: schema: type: object properties: message: type: string examples: - 'The `latest` alias is not allowed for mutating requests.' examples: - message: 'The `latest` alias is not allowed for mutating requests.' 404: description: 'Not found' content: application/json: schema: type: object properties: message: type: string examples: - 'Not found.' examples: - message: 'Not found.' 429: $ref: '#/components/responses/TooManyRequests' tags: - Nodes parameters: - in: path name: slug description: 'Full node slug.' required: true schema: type: string examples: - 'revenexx:http-request' - in: path name: version description: 'Semver, or the alias `latest`.' required: true schema: type: string examples: - 1.0.0 '/api/v1/nodes/{slug}/{version}/config:resolve': post: summary: 'Resolve dynamic node config' operationId: resolveDynamicNodeConfig description: '' parameters: - in: header name: X-Tenant-Id description: '' schema: type: string examples: - acme-production responses: 200: description: Resolved content: application/json: schema: type: object properties: fields: type: array items: type: object properties: key: type: string examples: - customerId type: type: string examples: - string examples: - - key: customerId type: string outputs: type: array items: type: object properties: name: type: string examples: - success examples: - - name: success examples: - fields: - key: customerId type: string outputs: - name: success 404: description: 'Unknown node' content: application/json: schema: type: object properties: message: type: string examples: - 'Not found.' examples: - message: 'Not found.' 409: description: 'Bundle not built yet' content: application/json: schema: type: object properties: message: type: string examples: - 'Node bundle is not built yet; retry shortly.' examples: - message: 'Node bundle is not built yet; retry shortly.' 502: description: 'Node runtime unavailable or failed' content: application/json: schema: type: object properties: message: type: string examples: - 'Node runtime resolve failed: ...' examples: - message: 'Node runtime resolve failed: ...' 429: $ref: '#/components/responses/TooManyRequests' tags: - Nodes requestBody: required: true content: application/json: schema: type: object properties: target: type: string description: '"outputs", "*" (all), or a config field key.' examples: - '*' config: type: object description: "The user's current partial config values." properties: { } examples: - [] locale: type: - string - 'null' description: 'Preferred locale for resolved labels.' examples: - de required: - target parameters: - in: path name: slug description: 'Full node slug.' required: true schema: type: string examples: - 'revenexx:api' - in: path name: version description: 'Semver, or the alias `latest`.' required: true schema: type: string examples: - 1.0.0 '/api/v1/schemas/{domain}': get: summary: 'List schema versions' operationId: listSchemaVersions description: "Returns the identifiers of every registered schema version for the given\ndomain, in registration order (which is also the order in which they\nare accepted by the validation layer)." parameters: [] responses: 200: description: Success content: application/json: schema: type: object properties: domain: type: string examples: - workflow versions: type: array items: type: string examples: - - v0-draft examples: - domain: workflow versions: - v0-draft 404: description: 'Unknown domain' content: application/json: schema: type: object properties: message: type: string examples: - 'Unknown schema domain.' examples: - message: 'Unknown schema domain.' tags: - Schemas security: [] parameters: - in: path name: domain description: 'The schema domain. Supported domains: `workflow`, `node`.' required: true schema: type: string examples: - workflow '/api/v1/schemas/{domain}/{version}': get: summary: 'Show a schema version' operationId: showASchemaVersion description: "Returns the serialized JSON-Schema definition for one specific\n`(domain, version)` pair. The payload uses the standard JSON Schema\nvocabulary (`type`, `properties`, `required`, …) and is suitable for\nclient-side validation or form generation." parameters: [] responses: 200: description: Success content: application/json: schema: type: object properties: domain: type: string examples: - workflow version: type: string examples: - v0-draft schema: type: object properties: title: type: string examples: - 'Workflow Definition (v0-draft)' type: type: string examples: - object examples: - domain: workflow version: v0-draft schema: title: 'Workflow Definition (v0-draft)' type: object 404: description: 'Unknown version' content: application/json: schema: type: object properties: message: type: string examples: - 'Unknown schema version.' examples: - message: 'Unknown schema version.' tags: - Schemas security: [] parameters: - in: path name: domain description: 'The schema domain.' required: true schema: type: string examples: - workflow - in: path name: version description: 'The schema version identifier.' required: true schema: type: string examples: - v0-draft /api/v1/templates: get: summary: 'List templates' operationId: listTemplates description: "Returns the latest registered version of each template, without the\n(heavy) embedded workflow `definition` blob — that ships only on `show`." parameters: - in: header name: X-Tenant-Id description: '' schema: type: string examples: - acme-production responses: 200: description: Success content: application/json: schema: type: object properties: data: type: array items: type: object properties: slug: type: string examples: - 'revenexx:bc-sales-order-digest' version: type: string examples: - 1.0.0 category: type: string examples: - sales level: type: string examples: - beginner name: type: string examples: - 'Daily Sales-Order Digest' shortDescription: type: string examples: - 'Email a daily summary of Business Central sales orders.' description: type: - string - 'null' examples: - null icon: type: string examples: - 'mdi:email-newsletter' industries: type: array items: type: string examples: - - any vendors: type: array items: type: string examples: - - microsoft - business-central triggerTypes: type: array items: type: string examples: - - schedule examples: - - slug: 'revenexx:bc-sales-order-digest' version: 1.0.0 category: sales level: beginner name: 'Daily Sales-Order Digest' shortDescription: 'Email a daily summary of Business Central sales orders.' description: null icon: 'mdi:email-newsletter' industries: - any vendors: - microsoft - business-central triggerTypes: - schedule examples: - data: - slug: 'revenexx:bc-sales-order-digest' version: 1.0.0 category: sales level: beginner name: 'Daily Sales-Order Digest' shortDescription: 'Email a daily summary of Business Central sales orders.' description: null icon: 'mdi:email-newsletter' industries: - any vendors: - microsoft - business-central triggerTypes: - schedule 401: description: 'Missing or invalid token' content: application/json: schema: type: object properties: message: type: string examples: - Unauthenticated. examples: - message: Unauthenticated. 429: $ref: '#/components/responses/TooManyRequests' tags: - Templates '/api/v1/templates/{slug}': get: summary: 'Show a template' operationId: showATemplate description: "Returns the latest registered version of the template identified by its\nnamespaced slug, including the embedded workflow `definition` used to\ninstantiate a new workflow." parameters: - in: header name: X-Tenant-Id description: '' schema: type: string examples: - acme-production responses: 200: description: Success content: application/json: schema: type: object properties: data: type: object properties: slug: type: string examples: - 'revenexx:bc-sales-order-digest' version: type: string examples: - 1.0.0 category: type: string examples: - sales level: type: string examples: - beginner name: type: string examples: - 'Daily Sales-Order Digest' shortDescription: type: string examples: - 'Email a daily summary of Business Central sales orders.' description: type: - string - 'null' examples: - null icon: type: string examples: - 'mdi:email-newsletter' industries: type: array items: type: string examples: - - any vendors: type: array items: type: string examples: - - microsoft - business-central triggerTypes: type: array items: type: string examples: - - schedule blob_version: type: string examples: - v0-draft definition: type: object properties: nodeManifestVersion: type: string examples: - v0-draft name: type: string examples: - 'Daily Sales-Order Digest' nodes: type: array examples: - [] edges: type: array examples: - [] triggers: type: array items: type: object properties: handle: type: string examples: - a1c0ffee-0001-4001-8001-000000000001 type: type: string examples: - schedule config: type: object properties: cron: type: string examples: - '0 7 * * *' examples: - - handle: a1c0ffee-0001-4001-8001-000000000001 type: schedule config: cron: '0 7 * * *' examples: - data: slug: 'revenexx:bc-sales-order-digest' version: 1.0.0 category: sales level: beginner name: 'Daily Sales-Order Digest' shortDescription: 'Email a daily summary of Business Central sales orders.' description: null icon: 'mdi:email-newsletter' industries: - any vendors: - microsoft - business-central triggerTypes: - schedule blob_version: v0-draft definition: nodeManifestVersion: v0-draft name: 'Daily Sales-Order Digest' nodes: [] edges: [] triggers: - handle: a1c0ffee-0001-4001-8001-000000000001 type: schedule config: cron: '0 7 * * *' 404: description: 'Not found' content: application/json: schema: type: object properties: message: type: string examples: - 'Not found.' examples: - message: 'Not found.' 429: $ref: '#/components/responses/TooManyRequests' tags: - Templates parameters: - in: path name: slug description: 'Namespaced template slug.' required: true schema: type: string examples: - 'revenexx:slack-to-crm' '/api/v1/templates/{slug}/requirements': get: summary: 'Template installation requirements' operationId: templateInstallationRequirements description: "Lists the credential types and secret keys the template's workflow\nreferences, cross-referenced against the current tenant (how many\ncredential instances already exist, whether each secret key is stored) so\nan install UI can have the user provision what is missing first." parameters: - in: header name: X-Tenant-Id description: '' schema: type: string examples: - acme-production responses: 200: description: Success content: application/json: schema: type: object properties: data: type: object properties: credentialTypes: type: array items: type: object properties: slug: type: string examples: - 'revenexx:business-central' registered: type: boolean examples: - true existingInstances: type: integer examples: - 1 usedBy: type: array items: type: object properties: nodeId: type: string examples: - list_orders configKey: type: string examples: - credentials examples: - - nodeId: list_orders configKey: credentials version: type: string examples: - 1.0.0 name: type: string examples: - 'Business Central' authKind: type: string examples: - oauth2-client-credentials fields: type: array examples: - [] examples: - - slug: 'revenexx:business-central' registered: true existingInstances: 1 usedBy: - nodeId: list_orders configKey: credentials version: 1.0.0 name: 'Business Central' authKind: oauth2-client-credentials fields: [] secrets: type: array examples: - [] examples: - data: credentialTypes: - slug: 'revenexx:business-central' registered: true existingInstances: 1 usedBy: - nodeId: list_orders configKey: credentials version: 1.0.0 name: 'Business Central' authKind: oauth2-client-credentials fields: [] secrets: [] 404: description: 'Not found' content: application/json: schema: type: object properties: message: type: string examples: - 'Not found.' examples: - message: 'Not found.' 429: $ref: '#/components/responses/TooManyRequests' tags: - Templates parameters: - in: path name: slug description: 'Namespaced template slug.' required: true schema: type: string examples: - 'revenexx:slack-to-crm' '/api/v1/templates/{slug}/instantiate': post: summary: 'Instantiate a template' operationId: instantiateATemplate description: "Creates a new workflow (and its triggers) for the current tenant from the\ntemplate's blueprint. Trigger handles are regenerated so repeated installs\nnever collide; the workflow and all triggers start inactive. Returns the\ncreated workflow." parameters: - in: header name: X-Tenant-Id description: '' schema: type: string examples: - acme-production responses: 201: description: Created content: application/json: schema: type: object properties: id: type: integer examples: - 1 name: type: string examples: - 'Daily Sales-Order Digest' description: type: - string - 'null' examples: - null blob_definition_version: type: string examples: - v0-draft blob: type: object properties: { } active: type: boolean examples: - false revision: type: integer examples: - 1 created_at: type: string examples: - '2026-05-06T10:00:00Z' updated_at: type: string examples: - '2026-05-06T10:00:00Z' examples: - id: 1 name: 'Daily Sales-Order Digest' description: null blob_definition_version: v0-draft blob: { } active: false revision: 1 created_at: '2026-05-06T10:00:00Z' updated_at: '2026-05-06T10:00:00Z' 404: description: 'Not found' content: application/json: schema: type: object properties: message: type: string examples: - 'Not found.' examples: - message: 'Not found.' 422: description: 'Validation failed' content: application/json: schema: type: object properties: message: type: string examples: - 'The given data was invalid.' errors: type: object properties: credential_bindings: type: array items: type: string examples: - - 'The credential_bindings field must be an array.' examples: - message: 'The given data was invalid.' errors: credential_bindings: - 'The credential_bindings field must be an array.' 429: $ref: '#/components/responses/TooManyRequests' tags: - Templates requestBody: required: false content: application/json: schema: type: object properties: name: type: string description: 'Optional workflow name override; defaults to the template name. Must not be greater than 255 characters.' examples: - 'My Slack flow' credential_bindings: type: array description: 'Must be a valid UUID.' items: type: string examples: - - 6ff8f7f6-1eb3-3525-be4a-3932c805afed parameters: - in: path name: slug description: 'Namespaced template slug.' required: true schema: type: string examples: - 'revenexx:slack-to-crm' /api/v1/secrets: get: summary: 'List secret keys' operationId: listSecretKeys description: "Returns the alphabetically sorted list of secret keys for the current\ntenant. Values are never exposed." parameters: - in: header name: X-Tenant-Id description: '' schema: type: string examples: - acme-production responses: 200: description: Success content: application/json: schema: type: object properties: keys: type: array items: type: string examples: - - SLACK_WEBHOOK_URL - STRIPE_API_KEY examples: - keys: - SLACK_WEBHOOK_URL - STRIPE_API_KEY 401: description: 'Missing or invalid token' content: application/json: schema: type: object properties: message: type: string examples: - Unauthenticated. examples: - message: Unauthenticated. 429: $ref: '#/components/responses/TooManyRequests' tags: - 'Tenant Secrets' post: summary: 'Create or update a secret' operationId: createOrUpdateASecret description: "Upserts a secret value for the given key within the current tenant.\nReturns 201 on creation, 200 on update. The value is never echoed back." parameters: - in: header name: X-Tenant-Id description: '' schema: type: string examples: - acme-production responses: 200: description: Updated content: application/json: schema: type: object properties: key: type: string examples: - STRIPE_API_KEY created_at: type: string examples: - '2026-05-04T08:50:00Z' updated_at: type: string examples: - '2026-05-05T08:50:00Z' examples: - key: STRIPE_API_KEY created_at: '2026-05-04T08:50:00Z' updated_at: '2026-05-05T08:50:00Z' 201: description: Created content: application/json: schema: type: object properties: key: type: string examples: - STRIPE_API_KEY created_at: type: string examples: - '2026-05-05T08:50:00Z' updated_at: type: string examples: - '2026-05-05T08:50:00Z' examples: - key: STRIPE_API_KEY created_at: '2026-05-05T08:50:00Z' updated_at: '2026-05-05T08:50:00Z' 422: description: 'Validation failed' content: application/json: schema: type: object properties: message: type: string examples: - 'The key field format is invalid.' errors: type: object properties: key: type: array items: type: string examples: - - ... examples: - message: 'The key field format is invalid.' errors: key: - ... 429: $ref: '#/components/responses/TooManyRequests' tags: - 'Tenant Secrets' requestBody: required: true content: application/json: schema: type: object properties: key: type: string description: 'Env-style key, must match `^[A-Z0-9_]+$`.' examples: - STRIPE_API_KEY value: type: string description: 'The secret value.' examples: - sk_live_abc123 required: - key - value '/api/v1/secrets/{key}': patch: summary: 'Update a secret value' operationId: updateASecretValue description: "Replaces the value of an existing secret. The key is immutable — create\na new secret and delete the old one if you need to rename a key. Returns\n404 if the key does not exist for the current tenant." parameters: - in: header name: X-Tenant-Id description: '' schema: type: string examples: - acme-production responses: 200: description: Updated content: application/json: schema: type: object properties: key: type: string examples: - bc-client-secret created_at: type: string examples: - '2026-05-04T08:50:00Z' updated_at: type: string examples: - '2026-06-12T10:00:00Z' examples: - key: bc-client-secret created_at: '2026-05-04T08:50:00Z' updated_at: '2026-06-12T10:00:00Z' 404: description: 'Not found' content: application/json: schema: type: object properties: message: type: string examples: - 'Not found.' examples: - message: 'Not found.' 422: description: 'Validation failed' content: application/json: schema: type: object properties: message: type: string examples: - 'The value field is required.' errors: type: object properties: value: type: array items: type: string examples: - - ... examples: - message: 'The value field is required.' errors: value: - ... 429: $ref: '#/components/responses/TooManyRequests' tags: - 'Tenant Secrets' requestBody: required: true content: application/json: schema: type: object properties: value: type: string description: 'The new secret value.' examples: - sk_live_new_value required: - value delete: summary: 'Delete a secret' operationId: deleteASecret description: "Removes the secret identified by `{key}` for the current tenant. The\nlookup is explicitly scoped to the current tenant, so a key belonging\nto another tenant — or one that does not exist at all — yields a 404\nwithout leaking existence either way." parameters: - in: header name: X-Tenant-Id description: '' schema: type: string examples: - acme-production responses: 204: description: Deleted content: text/plain: schema: type: string examples: - '' 404: description: 'Not found' content: application/json: schema: type: object properties: message: type: string examples: - 'Not found.' examples: - message: 'Not found.' 429: $ref: '#/components/responses/TooManyRequests' tags: - 'Tenant Secrets' parameters: - in: path name: key description: 'The secret key to update.' required: true schema: type: string examples: - bc-client-secret '/api/v1/workflows/{workflowId}/triggers': get: summary: 'List triggers for a workflow' operationId: listTriggersForAWorkflow description: '' parameters: - in: header name: X-Tenant-Id description: '' schema: type: string examples: - acme-production responses: 200: description: Success content: application/json: schema: type: object properties: data: type: array items: type: object properties: id: type: integer examples: - 12 workflow_id: type: integer examples: - 1 handle: type: string examples: - 6ff8f7f6-1eb3-3525-be4a-3932c805afed type: type: string examples: - webhook name: type: string examples: - 'PSP webhook' config: type: object properties: method: type: string examples: - POST public: type: boolean examples: - true inbound: type: object properties: endpoint_id: type: string examples: - inb_abc123 url: type: string examples: - 'https://webhooks.revenexx.com/in/inb_abc123' active: type: boolean examples: - true created_at: type: string examples: - '2026-06-15T10:00:00Z' updated_at: type: string examples: - '2026-06-15T10:00:00Z' examples: - - id: 12 workflow_id: 1 handle: 6ff8f7f6-1eb3-3525-be4a-3932c805afed type: webhook name: 'PSP webhook' config: method: POST public: true inbound: endpoint_id: inb_abc123 url: 'https://webhooks.revenexx.com/in/inb_abc123' active: true created_at: '2026-06-15T10:00:00Z' updated_at: '2026-06-15T10:00:00Z' examples: - data: - id: 12 workflow_id: 1 handle: 6ff8f7f6-1eb3-3525-be4a-3932c805afed type: webhook name: 'PSP webhook' config: method: POST public: true inbound: endpoint_id: inb_abc123 url: 'https://webhooks.revenexx.com/in/inb_abc123' active: true created_at: '2026-06-15T10:00:00Z' updated_at: '2026-06-15T10:00:00Z' 429: $ref: '#/components/responses/TooManyRequests' tags: - Triggers post: summary: 'Create a trigger' operationId: createATrigger description: '' parameters: - in: header name: X-Tenant-Id description: '' schema: type: string examples: - acme-production responses: 201: description: 'Public webhook trigger' content: application/json: schema: type: object properties: id: type: integer examples: - 12 workflow_id: type: integer examples: - 1 handle: type: string examples: - 6ff8f7f6-1eb3-3525-be4a-3932c805afed type: type: string examples: - webhook name: type: string examples: - 'PSP webhook' config: type: object properties: method: type: string examples: - POST public: type: boolean examples: - true inbound: type: object properties: endpoint_id: type: string examples: - inb_abc123 url: type: string examples: - 'https://webhooks.revenexx.com/in/inb_abc123' description: 'Server-owned ingress registration (`endpoint_id`, `url`) for a public webhook trigger. Clients cannot set or modify it.' active: type: boolean examples: - true created_at: type: string examples: - '2026-06-15T10:00:00Z' updated_at: type: string examples: - '2026-06-15T10:00:00Z' inbound_secret: type: string description: 'Present ONLY right after a public webhook endpoint is provisioned — the ingress ingest token, returned once and never stored (ADR-0066).' examples: - whsec_ing_onetime examples: - id: 12 workflow_id: 1 handle: 6ff8f7f6-1eb3-3525-be4a-3932c805afed type: webhook name: 'PSP webhook' config: method: POST public: true inbound: endpoint_id: inb_abc123 url: 'https://webhooks.revenexx.com/in/inb_abc123' active: true created_at: '2026-06-15T10:00:00Z' updated_at: '2026-06-15T10:00:00Z' inbound_secret: whsec_ing_onetime 422: description: 'Validation failed' content: application/json: schema: type: object properties: message: type: string examples: - 'The config.method field is required.' errors: type: object properties: config.method: type: array items: type: string examples: - - 'The config.method field is required.' examples: - message: 'The config.method field is required.' errors: config.method: - 'The config.method field is required.' 429: $ref: '#/components/responses/TooManyRequests' tags: - Triggers requestBody: required: true content: application/json: schema: type: object properties: handle: type: string description: 'Stable UUID referenced by the workflow blob edges. Must be unique per tenant. Must be a valid UUID.' examples: - 6ff8f7f6-1eb3-3525-be4a-3932c805afed type: type: string description: 'Trigger entry-point type.' enum: - manual - schedule - webhook - event examples: - webhook name: type: - string - 'null' description: 'Optional human-readable label.' examples: - 'PSP webhook' active: type: boolean description: 'Whether the trigger is enabled. Defaults to true.' examples: - true config: type: - object - 'null' description: 'Per-type trigger configuration. Fields depend on `type`: webhook → `method` (required HTTP method), optional `secretRef` (secret key verifying the inbound request) and `public` (expose via the inbound ingress, ADR-0066 — provisioning returns `inbound_secret` once); schedule → `cron` (required) and optional `timezone` (IANA); manual → none.' properties: { } examples: - method: POST public: true required: - handle - type parameters: - in: path name: workflowId description: 'The workflow id.' required: true schema: type: integer examples: - 1 '/api/v1/workflows/{workflowId}/triggers/{triggerId}': put: summary: 'Update a trigger' operationId: updateATrigger description: '' parameters: - in: header name: X-Tenant-Id description: '' schema: type: string examples: - acme-production responses: 200: description: 'Public webhook trigger' content: application/json: schema: type: object properties: id: type: integer examples: - 12 workflow_id: type: integer examples: - 1 handle: type: string examples: - 6ff8f7f6-1eb3-3525-be4a-3932c805afed type: type: string examples: - webhook name: type: string examples: - 'PSP webhook' config: type: object properties: method: type: string examples: - POST public: type: boolean examples: - true inbound: type: object properties: endpoint_id: type: string examples: - inb_abc123 url: type: string examples: - 'https://webhooks.revenexx.com/in/inb_abc123' description: 'Server-owned ingress registration (`endpoint_id`, `url`) for a public webhook trigger. Clients cannot set or modify it.' active: type: boolean examples: - true created_at: type: string examples: - '2026-06-15T10:00:00Z' updated_at: type: string examples: - '2026-06-15T10:05:00Z' inbound_secret: type: string description: 'Present ONLY right after a public webhook endpoint is provisioned — the ingress ingest token, returned once and never stored (ADR-0066).' examples: - whsec_ing_onetime examples: - id: 12 workflow_id: 1 handle: 6ff8f7f6-1eb3-3525-be4a-3932c805afed type: webhook name: 'PSP webhook' config: method: POST public: true inbound: endpoint_id: inb_abc123 url: 'https://webhooks.revenexx.com/in/inb_abc123' active: true created_at: '2026-06-15T10:00:00Z' updated_at: '2026-06-15T10:05:00Z' inbound_secret: whsec_ing_onetime 422: description: 'Validation failed' content: application/json: schema: type: object properties: message: type: string examples: - 'The config.method field is required.' errors: type: object properties: config.method: type: array items: type: string examples: - - 'The config.method field is required.' examples: - message: 'The config.method field is required.' errors: config.method: - 'The config.method field is required.' 429: $ref: '#/components/responses/TooManyRequests' tags: - Triggers requestBody: required: true content: application/json: schema: type: object properties: type: type: string description: 'Trigger entry-point type.' enum: - manual - schedule - webhook - event examples: - webhook name: type: - string - 'null' description: 'Optional human-readable label.' examples: - 'PSP webhook' active: type: boolean description: 'Whether the trigger is enabled.' examples: - true config: type: - object - 'null' description: 'Per-type trigger configuration. Fields depend on `type`: webhook → `method` (required HTTP method), optional `secretRef` (secret key verifying the inbound request) and `public` (expose via the inbound ingress, ADR-0066 — provisioning returns `inbound_secret` once); schedule → `cron` (required) and optional `timezone` (IANA); manual → none.' properties: { } examples: - method: POST public: true required: - type - active delete: summary: 'Delete a trigger' operationId: deleteATrigger description: '' parameters: - in: header name: X-Tenant-Id description: '' schema: type: string examples: - acme-production responses: 204: description: Deleted content: text/plain: schema: type: string examples: - '' 429: $ref: '#/components/responses/TooManyRequests' tags: - Triggers parameters: - in: path name: workflowId description: 'The workflow id.' required: true schema: type: integer examples: - 1 - in: path name: triggerId description: 'The trigger id.' required: true schema: type: integer examples: - 1 '/api/v1/webhooks/{handle}': get: summary: 'Fire a webhook trigger' operationId: fireAWebhookTrigger description: "Resolves the webhook trigger by handle, enforces the configured HTTP\nmethod, and starts a run. The mode follows the workflow's `execution_mode`\n(`async_only` → 202; `sync_only`/`caller_decides` → wait and return the\nresult), and can be overridden per request with `?mode=sync|async` when\nthe policy allows it — a conflicting `mode` is rejected with 422." parameters: - in: query name: mode description: 'optional Force `sync` or `async`. Honored for `caller_decides` workflows; conflicting with `async_only`/`sync_only` yields 422.' required: false schema: type: string description: 'optional Force `sync` or `async`. Honored for `caller_decides` workflows; conflicting with `async_only`/`sync_only` yields 422.' examples: - async - in: header name: X-Tenant-Id description: '' schema: type: string examples: - acme-production responses: 200: description: 'Completed (sync)' content: application/json: schema: type: object properties: id: type: integer examples: - 1 workflow_id: type: integer examples: - 1 status: type: string examples: - completed result: type: object properties: { } examples: - id: 1 workflow_id: 1 status: completed result: { } 202: description: 'Accepted (async)' content: application/json: schema: type: object properties: id: type: integer examples: - 1 workflow_id: type: integer examples: - 1 status: type: string examples: - running examples: - id: 1 workflow_id: 1 status: running 404: description: 'No such webhook trigger' content: application/json: schema: type: object properties: message: type: string examples: - 'No active webhook trigger with handle … exists.' examples: - message: 'No active webhook trigger with handle … exists.' 405: description: 'Method not allowed' content: application/json: schema: type: object properties: message: type: string examples: - 'This webhook expects POST.' examples: - message: 'This webhook expects POST.' 422: description: 'Mode conflicts with policy' content: application/json: schema: type: object properties: message: type: string examples: - 'Workflow does not allow sync execution (execution_mode=async_only).' examples: - message: 'Workflow does not allow sync execution (execution_mode=async_only).' 429: $ref: '#/components/responses/TooManyRequests' tags: - Webhooks parameters: - in: path name: handle description: 'The webhook trigger handle (UUID).' required: true schema: type: string examples: - 0190a9c0-1111-7000-8000-000000000000 /api/v1/workflows/used-credentials: get: summary: "List credential ids used across the tenant's workflows" operationId: listCredentialIdsUsedAcrossTheTenantsWorkflows description: "Returns the distinct credential *instance* UUIDs referenced by every\nworkflow of the current tenant. Optionally filtered to a single\ncredential type slug via `?type={slug}` and/or to active workflows only\nvia `?active=true`." parameters: - in: query name: type description: 'Filter to a single credential type slug.' required: false schema: type: string description: 'Filter to a single credential type slug.' examples: - 'revenexx:smtp' - in: query name: active description: 'Only consider active workflows.' required: false schema: type: boolean description: 'Only consider active workflows.' examples: - true - in: header name: X-Tenant-Id description: '' schema: type: string examples: - acme-production responses: 200: description: 'Used credentials' content: application/json: schema: type: object properties: data: type: array items: type: string examples: - - 9f3e2c1a-0000-4000-8000-000000000001 - 1ab2c3d4-0000-4000-8000-000000000002 examples: - data: - 9f3e2c1a-0000-4000-8000-000000000001 - 1ab2c3d4-0000-4000-8000-000000000002 429: $ref: '#/components/responses/TooManyRequests' tags: - 'Workflow Credentials' /api/v1/workflows/used-credential-types: get: summary: "List credential type slugs used across the tenant's workflows" operationId: listCredentialTypeSlugsUsedAcrossTheTenantsWorkflows description: "Returns the distinct credential *type* slugs (e.g. `revenexx:smtp`)\nreferenced by every workflow of the current tenant. Optionally filtered\nto active workflows only via `?active=true`." parameters: - in: query name: active description: 'Only consider active workflows.' required: false schema: type: boolean description: 'Only consider active workflows.' examples: - true - in: header name: X-Tenant-Id description: '' schema: type: string examples: - acme-production responses: 200: description: 'Used credential types' content: application/json: schema: type: object properties: data: type: array items: type: string examples: - - 'revenexx:smtp' - 'revenexx:deepl' examples: - data: - 'revenexx:smtp' - 'revenexx:deepl' 429: $ref: '#/components/responses/TooManyRequests' tags: - 'Workflow Credentials' '/api/v1/workflows/{workflowId}/credentials': get: summary: 'List credential ids used by a workflow' operationId: listCredentialIdsUsedByAWorkflow description: "Returns the distinct credential *instance* UUIDs the workflow's nodes\nreference, optionally filtered to a single credential type slug via\n`?type={slug}`." parameters: - in: query name: type description: 'Filter to a single credential type slug.' required: false schema: type: string description: 'Filter to a single credential type slug.' examples: - 'revenexx:smtp' - in: header name: X-Tenant-Id description: '' schema: type: string examples: - acme-production responses: 200: description: 'Used credentials' content: application/json: schema: type: object properties: data: type: array items: type: string examples: - - 9f3e2c1a-0000-4000-8000-000000000001 - 1ab2c3d4-0000-4000-8000-000000000002 examples: - data: - 9f3e2c1a-0000-4000-8000-000000000001 - 1ab2c3d4-0000-4000-8000-000000000002 404: description: 'Workflow not found' content: application/json: schema: type: object properties: message: type: string examples: - 'Not found.' examples: - message: 'Not found.' 429: $ref: '#/components/responses/TooManyRequests' tags: - 'Workflow Credentials' parameters: - in: path name: workflowId description: 'The workflow id.' required: true schema: type: integer examples: - 1 '/api/v1/workflows/{workflowId}/credential-types': get: summary: 'List credential type slugs used by a workflow' operationId: listCredentialTypeSlugsUsedByAWorkflow description: "Returns the distinct credential *type* slugs (e.g. `revenexx:smtp`) the\nworkflow's nodes reference through their `credentials-ref` config fields." parameters: - in: header name: X-Tenant-Id description: '' schema: type: string examples: - acme-production responses: 200: description: 'Used credential types' content: application/json: schema: type: object properties: data: type: array items: type: string examples: - - 'revenexx:smtp' - 'revenexx:deepl' examples: - data: - 'revenexx:smtp' - 'revenexx:deepl' 404: description: 'Workflow not found' content: application/json: schema: type: object properties: message: type: string examples: - 'Not found.' examples: - message: 'Not found.' 429: $ref: '#/components/responses/TooManyRequests' tags: - 'Workflow Credentials' parameters: - in: path name: workflowId description: 'The workflow id.' required: true schema: type: integer examples: - 1 '/api/v1/workflows/{workflowId}/revisions': get: summary: 'List workflow revisions' operationId: listWorkflowRevisions description: "Returns the archived revisions of a workflow, newest first, paginated.\nList items carry metadata only — use the show endpoint to fetch a\nsingle revision's full `blob` and `triggers`." parameters: - in: query name: page description: 'Page number to retrieve (1-based). Defaults to 1. Must be at least 1.' required: false schema: type: - integer - 'null' description: 'Page number to retrieve (1-based). Defaults to 1. Must be at least 1.' examples: - 1 - in: query name: per_page description: 'Number of revisions per page (1–100). Defaults to 25. Must be at least 1. Must not be greater than 100.' required: false schema: type: - integer - 'null' description: 'Number of revisions per page (1–100). Defaults to 25. Must be at least 1. Must not be greater than 100.' examples: - 25 - in: header name: X-Tenant-Id description: '' schema: type: string examples: - acme-production responses: 200: description: Success content: application/json: schema: type: object properties: data: type: array items: type: object properties: id: type: integer examples: - 7 revision: type: integer examples: - 2 name: type: string examples: - 'Sync orders' description: type: - string - 'null' examples: - null active: type: boolean examples: - true blob_definition_version: type: string examples: - v0-draft created_at: type: string examples: - '2026-05-06T10:00:00Z' updated_at: type: string examples: - '2026-05-06T11:00:00Z' archived_at: type: string examples: - '2026-05-06T12:00:00Z' examples: - - id: 7 revision: 2 name: 'Sync orders' description: null active: true blob_definition_version: v0-draft created_at: '2026-05-06T10:00:00Z' updated_at: '2026-05-06T11:00:00Z' archived_at: '2026-05-06T12:00:00Z' meta: type: object properties: current_page: type: integer examples: - 1 per_page: type: integer examples: - 25 total: type: integer examples: - 1 last_page: type: integer examples: - 1 examples: - data: - id: 7 revision: 2 name: 'Sync orders' description: null active: true blob_definition_version: v0-draft created_at: '2026-05-06T10:00:00Z' updated_at: '2026-05-06T11:00:00Z' archived_at: '2026-05-06T12:00:00Z' meta: current_page: 1 per_page: 25 total: 1 last_page: 1 404: description: 'Workflow not found' content: application/json: schema: type: object properties: message: type: string examples: - 'Not found.' examples: - message: 'Not found.' 429: $ref: '#/components/responses/TooManyRequests' tags: - 'Workflow Revisions' parameters: - in: path name: workflowId description: 'The workflow id.' required: true schema: type: integer examples: - 1 '/api/v1/workflows/{workflowId}/revisions/{revision}': get: summary: 'Show a workflow revision' operationId: showAWorkflowRevision description: "Returns a single archived revision in full, including its `blob` and\n`triggers` snapshot." parameters: - in: header name: X-Tenant-Id description: '' schema: type: string examples: - acme-production responses: 200: description: Success content: application/json: schema: type: object properties: id: type: integer examples: - 7 revision: type: integer examples: - 1 name: type: string examples: - 'Sync orders' description: type: - string - 'null' examples: - null active: type: boolean examples: - true blob_definition_version: type: string examples: - v0-draft blob: type: object properties: { } triggers: type: array examples: - [] created_at: type: string examples: - '2026-05-06T10:00:00Z' updated_at: type: string examples: - '2026-05-06T11:00:00Z' archived_at: type: string examples: - '2026-05-06T12:00:00Z' examples: - id: 7 revision: 1 name: 'Sync orders' description: null active: true blob_definition_version: v0-draft blob: { } triggers: [] created_at: '2026-05-06T10:00:00Z' updated_at: '2026-05-06T11:00:00Z' archived_at: '2026-05-06T12:00:00Z' 404: description: 'Revision or workflow not found' content: application/json: schema: type: object properties: message: type: string examples: - 'Not found.' examples: - message: 'Not found.' 429: $ref: '#/components/responses/TooManyRequests' tags: - 'Workflow Revisions' parameters: - in: path name: workflowId description: 'The workflow id.' required: true schema: type: integer examples: - 1 - in: path name: revision description: 'The archived revision number.' required: true schema: type: integer examples: - 1 '/api/v1/workflows/{workflowId}/revisions/{revision}/restore': post: summary: 'Restore a workflow revision' operationId: restoreAWorkflowRevision description: "Re-applies the given archived revision's definition (`blob`,\n`blob_definition_version`, and `triggers`) to the workflow as a brand-new\nrevision. The current state is first snapshotted into the history, the\n`revision` counter is bumped, and a fresh bundle build is dispatched. The\nworkflow's `name`, `description`, `active` and `execution_mode` are left\nunchanged.\n\nRestoring a revision whose definition is identical to the current one is\na safe no-op for the `revision` counter (no new history row is written),\nthough triggers are still re-synced from the snapshot." parameters: - in: header name: X-Tenant-Id description: '' schema: type: string examples: - acme-production responses: 200: description: Restored content: application/json: schema: type: object properties: id: type: integer examples: - 1 name: type: string examples: - 'Sync orders' revision: type: integer examples: - 3 build_status: type: string examples: - pending blob: type: object properties: { } triggers: type: array examples: - [] examples: - id: 1 name: 'Sync orders' revision: 3 build_status: pending blob: { } triggers: [] 404: description: 'Revision or workflow not found' content: application/json: schema: type: object properties: message: type: string examples: - 'Not found.' examples: - message: 'Not found.' 429: $ref: '#/components/responses/TooManyRequests' tags: - 'Workflow Revisions' parameters: - in: path name: workflowId description: 'The workflow id.' required: true schema: type: integer examples: - 1 - in: path name: revision description: 'The archived revision number to restore.' required: true schema: type: integer examples: - 1 '/api/v1/workflows/{workflowId}/runs': get: summary: 'List runs for a workflow' operationId: listRunsForAWorkflow description: 'Returns all runs for the workflow, newest first.' parameters: - in: query name: page description: 'Page number to retrieve (1-based). Defaults to 1. Must be at least 1.' required: false schema: type: - integer - 'null' description: 'Page number to retrieve (1-based). Defaults to 1. Must be at least 1.' examples: - 1 - in: query name: per_page description: 'Number of runs per page (1–100). Defaults to 25. Must be at least 1. Must not be greater than 100.' required: false schema: type: - integer - 'null' description: 'Number of runs per page (1–100). Defaults to 25. Must be at least 1. Must not be greater than 100.' examples: - 25 - in: header name: X-Tenant-Id description: '' schema: type: string examples: - acme-production responses: 200: description: Success content: application/json: schema: type: object properties: data: type: array examples: - [] meta: type: object properties: current_page: type: integer examples: - 1 per_page: type: integer examples: - 25 total: type: integer examples: - 0 last_page: type: integer examples: - 1 examples: - data: [] meta: current_page: 1 per_page: 25 total: 0 last_page: 1 429: $ref: '#/components/responses/TooManyRequests' tags: - 'Workflow Runs' post: summary: 'Start a workflow run' operationId: startAWorkflowRun description: "Execution behavior depends on workflow `execution_mode` and optional\nrequest `mode`:\n\n- Async: starts the run and returns HTTP 202 with status `running`.\n- Sync: waits for worker completion and returns HTTP 200/422/504/503\n with the final outcome.\n\nFor `caller_decides`, omitting `mode` defaults to async execution." parameters: - in: header name: X-Tenant-Id description: '' schema: type: string examples: - acme-production responses: 200: description: 'Sync completed' content: application/json: schema: type: object properties: id: type: integer examples: - 1 workflow_id: type: integer examples: - 1 status: type: string examples: - completed result: type: object properties: node-1: type: object properties: ok: type: boolean examples: - true completed_at: type: string examples: - '2026-05-22T10:00:30Z' examples: - id: 1 workflow_id: 1 status: completed result: node-1: ok: true completed_at: '2026-05-22T10:00:30Z' 202: description: Accepted content: application/json: schema: type: object properties: id: type: integer examples: - 1 workflow_id: type: integer examples: - 1 status: type: string examples: - running temporal_workflow_id: type: string examples: - 'tenant:1:abc' started_at: type: string examples: - '2026-05-13T10:00:00Z' examples: - id: 1 workflow_id: 1 status: running temporal_workflow_id: 'tenant:1:abc' started_at: '2026-05-13T10:00:00Z' 404: description: 'Workflow not found' content: application/json: schema: type: object properties: message: type: string examples: - 'Not found.' examples: - message: 'Not found.' 422: description: '' content: application/json: schema: oneOf: - description: 'Mode not allowed' type: object properties: message: type: string examples: - 'Workflow does not allow sync execution (execution_mode=async_only).' examples: - message: 'Workflow does not allow sync execution (execution_mode=async_only).' - description: 'Sync failed' type: object properties: message: type: string examples: - 'Workflow execution failed.' error: type: string examples: - 'node execution failed' run: type: object properties: id: type: integer examples: - 1 status: type: string examples: - failed examples: - message: 'Workflow execution failed.' error: 'node execution failed' run: id: 1 status: failed 501: description: 'Sync not supported by starter' content: application/json: schema: type: object properties: message: type: string examples: - 'Synchronous workflow execution is not supported by the configured run starter driver.' examples: - message: 'Synchronous workflow execution is not supported by the configured run starter driver.' 503: description: 'Worker unavailable' content: application/json: schema: type: object properties: message: type: string examples: - 'Workflow worker is unavailable.' examples: - message: 'Workflow worker is unavailable.' 504: description: 'Sync timeout' content: application/json: schema: type: object properties: message: type: string examples: - 'Workflow execution timed out.' error: type: string examples: - 'Sync run for workflow 1 exceeded timeout of 30 seconds.' examples: - message: 'Workflow execution timed out.' error: 'Sync run for workflow 1 exceeded timeout of 30 seconds.' 429: $ref: '#/components/responses/TooManyRequests' tags: - 'Workflow Runs' requestBody: required: false content: application/json: schema: type: object properties: trigger_payload: type: object description: 'optional Arbitrary trigger payload forwarded to the workflow.' properties: { } examples: - source: api trigger_handle: type: string description: "UUID handle of the trigger to run as. Optional; defaults to the workflow's manual trigger. Must be a valid UUID." examples: - 6ff8f7f6-1eb3-3525-be4a-3932c805afed mode: type: string description: 'optional Requested run mode. Allowed: `sync`, `async`. Resolution depends on workflow execution_mode policy.' examples: - sync parameters: - in: path name: workflowId description: 'The workflow id.' required: true schema: type: integer examples: - 1 '/api/v1/workflows/{workflowId}/runs/{runId}': get: summary: 'Get a workflow run' operationId: getAWorkflowRun description: "Returns the current state of a workflow run. If the run is still\nin progress, the worker is polled for the latest Temporal status." parameters: - in: header name: X-Tenant-Id description: '' schema: type: string examples: - acme-production responses: 200: description: Completed content: application/json: schema: type: object properties: id: type: integer examples: - 1 workflow_id: type: integer examples: - 1 status: type: string examples: - completed result: type: object properties: { } completed_at: type: string examples: - '2026-05-13T10:01:00Z' examples: - id: 1 workflow_id: 1 status: completed result: { } completed_at: '2026-05-13T10:01:00Z' 404: description: 'Not found' content: application/json: schema: type: object properties: message: type: string examples: - 'Not found.' examples: - message: 'Not found.' 429: $ref: '#/components/responses/TooManyRequests' tags: - 'Workflow Runs' parameters: - in: path name: workflowId description: 'The workflow id.' required: true schema: type: integer examples: - 1 - in: path name: runId description: 'The run id.' required: true schema: type: integer examples: - 1 '/api/v1/workflows/{workflowId}/runs/{runId}/details': get: summary: 'Get execution details for a workflow run' operationId: getExecutionDetailsForAWorkflowRun description: "Returns the execution description (status, timing, history length,\nparent linkage) via {@see WorkflowExecutionInspector}. The inspector\ntransparently routes between a live Temporal call and the local\nsnapshot taken when the run reached a terminal status; the response\ncarries a `source` field of `\"temporal\"` or `\"snapshot\"` so clients\nknow which view they are seeing." parameters: - in: header name: X-Tenant-Id description: '' schema: type: string examples: - acme-production responses: 200: description: '' content: application/json: schema: oneOf: - description: Live type: object properties: source: type: string examples: - temporal data: type: object properties: workflow_id: type: string examples: - 'tenant:1:abc' run_id: type: string examples: - 0190... status: type: string examples: - running examples: - source: temporal data: workflow_id: 'tenant:1:abc' run_id: 0190... status: running - description: Snapshot type: object properties: source: type: string examples: - snapshot data: type: object properties: workflow_id: type: string examples: - 'tenant:1:abc' run_id: type: string examples: - 0190... status: type: string examples: - completed examples: - source: snapshot data: workflow_id: 'tenant:1:abc' run_id: 0190... status: completed 404: description: 'Run not found' content: application/json: schema: type: object properties: message: type: string examples: - 'Not found.' examples: - message: 'Not found.' 409: description: 'Run not handed off to Temporal yet' content: application/json: schema: type: object properties: message: type: string examples: - 'Workflow run has no Temporal execution yet.' examples: - message: 'Workflow run has no Temporal execution yet.' 410: description: 'History unavailable' content: application/json: schema: type: object properties: message: type: string examples: - 'Workflow execution history is no longer available.' examples: - message: 'Workflow execution history is no longer available.' 503: description: 'Temporal unavailable' content: application/json: schema: type: object properties: message: type: string examples: - 'Temporal is currently unavailable.' examples: - message: 'Temporal is currently unavailable.' 429: $ref: '#/components/responses/TooManyRequests' tags: - 'Workflow Runs' parameters: - in: path name: workflowId description: 'The workflow id.' required: true schema: type: integer examples: - 1 - in: path name: runId description: 'The run id.' required: true schema: type: integer examples: - 1 '/api/v1/workflows/{workflowId}/runs/{runId}/history': get: summary: 'Get execution history for a workflow run' operationId: getExecutionHistoryForAWorkflowRun description: "Returns one page of history events via {@see WorkflowExecutionInspector}.\nLike the details endpoint, the response is hybrid-routed and carries\na `source` field. The `next_page_token` is opaque (source-tagged with\n`tmp:` or `snp:`); pass it verbatim to the next call. Note that\nswitching sources mid-pagination resets to page 1 (the response's\n`source` will change), which the client should treat as a fresh\npagination." parameters: - in: query name: page_token description: 'Opaque continuation token returned by the previous page. Omit for the first page. Must not be greater than 8192 characters.' example: null required: false schema: type: - string - 'null' description: 'Opaque continuation token returned by the previous page. Omit for the first page. Must not be greater than 8192 characters.' examples: - null - in: query name: page_size description: 'Maximum number of history events per page (1–1000). Defaults to the server-configured value. Must be at least 1. Must not be greater than 1000.' required: false schema: type: - integer - 'null' description: 'Maximum number of history events per page (1–1000). Defaults to the server-configured value. Must be at least 1. Must not be greater than 1000.' examples: - 200 - in: header name: X-Tenant-Id description: '' schema: type: string examples: - acme-production responses: 200: description: '' content: application/json: schema: oneOf: - description: 'Live page' type: object properties: source: type: string examples: - temporal data: type: array items: type: object properties: event_id: type: integer examples: - 1 event_type: type: string examples: - workflow_execution_started examples: - - event_id: 1 event_type: workflow_execution_started next_page_token: type: - string - 'null' examples: - null examples: - source: temporal data: - event_id: 1 event_type: workflow_execution_started next_page_token: null - description: 'Snapshot page' type: object properties: source: type: string examples: - snapshot data: type: array items: type: object properties: event_id: type: integer examples: - 1 examples: - - event_id: 1 next_page_token: type: - string - 'null' examples: - null examples: - source: snapshot data: - event_id: 1 next_page_token: null 404: description: 'Run not found' content: application/json: schema: type: object properties: message: type: string examples: - 'Not found.' examples: - message: 'Not found.' 409: description: 'Run not handed off to Temporal yet' content: application/json: schema: type: object properties: message: type: string examples: - 'Workflow run has no Temporal execution yet.' examples: - message: 'Workflow run has no Temporal execution yet.' 410: description: 'History unavailable' content: application/json: schema: type: object properties: message: type: string examples: - 'Workflow execution history is no longer available.' examples: - message: 'Workflow execution history is no longer available.' 422: description: 'Invalid page token' content: application/json: schema: type: object properties: message: type: string examples: - 'Invalid page_token.' examples: - message: 'Invalid page_token.' 503: description: 'Temporal unavailable' content: application/json: schema: type: object properties: message: type: string examples: - 'Temporal is currently unavailable.' examples: - message: 'Temporal is currently unavailable.' 429: $ref: '#/components/responses/TooManyRequests' tags: - 'Workflow Runs' parameters: - in: path name: workflowId description: 'The workflow id.' required: true schema: type: integer examples: - 1 - in: path name: runId description: 'The run id.' required: true schema: type: integer examples: - 1 '/api/v1/workflows/{workflowId}/runs/{runId}/stack-trace': get: summary: 'Get the current call stack of a running workflow' operationId: getTheCurrentCallStackOfARunningWorkflow description: "Issues the built-in `__stack_trace` query against the workflow worker\nand returns the formatted stack trace as plain text. Only meaningful\nwhile the run is still executing; terminal runs return 409." parameters: - in: header name: X-Tenant-Id description: '' schema: type: string examples: - acme-production responses: 200: description: Running content: application/json: schema: type: object properties: stack_trace: type: string examples: - 'coroutine ...' examples: - stack_trace: 'coroutine ...' 404: description: 'Run not found' content: application/json: schema: type: object properties: message: type: string examples: - 'Not found.' examples: - message: 'Not found.' 409: description: '' content: application/json: schema: oneOf: - description: 'Run not handed off to Temporal yet' type: object properties: message: type: string examples: - 'Workflow run has no Temporal execution yet.' examples: - message: 'Workflow run has no Temporal execution yet.' - description: 'Run is no longer running' type: object properties: message: type: string examples: - 'Workflow run is no longer running.' examples: - message: 'Workflow run is no longer running.' 410: description: 'Execution unknown to Temporal' content: application/json: schema: type: object properties: message: type: string examples: - 'Workflow execution history is no longer available.' examples: - message: 'Workflow execution history is no longer available.' 503: description: 'Temporal unavailable' content: application/json: schema: type: object properties: message: type: string examples: - 'Temporal is currently unavailable.' examples: - message: 'Temporal is currently unavailable.' 429: $ref: '#/components/responses/TooManyRequests' tags: - 'Workflow Runs' parameters: - in: path name: workflowId description: 'The workflow id.' required: true schema: type: integer examples: - 1 - in: path name: runId description: 'The run id.' required: true schema: type: integer examples: - 1 /api/v1/workflows: get: summary: 'List workflows' operationId: listWorkflows description: 'Returns the workflows owned by the current tenant, ordered by name.' parameters: - in: header name: X-Tenant-Id description: '' schema: type: string examples: - acme-production responses: 200: description: Success content: application/json: schema: type: object properties: data: type: array items: type: object properties: id: type: integer examples: - 1 name: type: string examples: - 'Sync orders' description: type: - string - 'null' examples: - null blob_definition_version: type: string examples: - v0-draft blob: type: object properties: { } active: type: boolean examples: - true revision: type: integer examples: - 1 created_at: type: string examples: - '2026-05-06T10:00:00Z' updated_at: type: string examples: - '2026-05-06T10:00:00Z' examples: - - id: 1 name: 'Sync orders' description: null blob_definition_version: v0-draft blob: [] active: true revision: 1 created_at: '2026-05-06T10:00:00Z' updated_at: '2026-05-06T10:00:00Z' examples: - data: - id: 1 name: 'Sync orders' description: null blob_definition_version: v0-draft blob: { } active: true revision: 1 created_at: '2026-05-06T10:00:00Z' updated_at: '2026-05-06T10:00:00Z' 401: description: 'Missing or invalid token' content: application/json: schema: type: object properties: message: type: string examples: - Unauthenticated. examples: - message: Unauthenticated. 429: $ref: '#/components/responses/TooManyRequests' tags: - Workflows post: summary: 'Create a workflow' operationId: createAWorkflow description: "Persists a new workflow under the current tenant. The `name` must be\nunique within the tenant. The `blob` is validated against the schema\nregistered for the supplied `blob_definition_version`." parameters: - in: header name: X-Tenant-Id description: '' schema: type: string examples: - acme-production responses: 201: description: Created content: application/json: schema: type: object properties: id: type: integer examples: - 1 name: type: string examples: - 'Sync orders' description: type: - string - 'null' examples: - null blob_definition_version: type: string examples: - v0-draft blob: type: object properties: { } active: type: boolean examples: - true revision: type: integer examples: - 1 created_at: type: string examples: - '2026-05-06T10:00:00Z' updated_at: type: string examples: - '2026-05-06T10:00:00Z' examples: - id: 1 name: 'Sync orders' description: null blob_definition_version: v0-draft blob: { } active: true revision: 1 created_at: '2026-05-06T10:00:00Z' updated_at: '2026-05-06T10:00:00Z' 422: description: 'Validation failed' content: application/json: schema: type: object properties: message: type: string examples: - 'The given data was invalid.' errors: type: object properties: blob_definition_version: type: array items: type: string examples: - - ... examples: - message: 'The given data was invalid.' errors: blob_definition_version: - ... 429: $ref: '#/components/responses/TooManyRequests' tags: - Workflows requestBody: required: true content: application/json: schema: type: object properties: name: type: string description: 'Human-readable workflow name (unique per tenant). Must not be greater than 255 characters.' examples: - 'Sync orders nightly' description: type: - string - 'null' description: 'Optional free-text description.' examples: - 'Pulls orders from the upstream API every night at 02:00 UTC.' blob_definition_version: type: string description: 'Identifier of the blob schema version. See `GET /v1/schemas/workflow`.' enum: - v0-draft examples: - v0-draft blob: type: object description: 'The workflow definition payload. Must match the schema for the supplied version.' properties: { } examples: - nodes: [] edges: [] active: type: boolean description: 'Whether the workflow is active. Defaults to true when omitted.' examples: - true execution_mode: type: string description: 'Execution policy for run mode resolution. One of: async_only, sync_only, caller_decides. Defaults to async_only.' enum: - async_only - sync_only - caller_decides examples: - async_only triggers: type: array description: '' items: type: object properties: handle: type: string description: 'This field is required when triggers is present. Must be a valid UUID.' examples: - 6ff8f7f6-1eb3-3525-be4a-3932c805afed type: type: string description: 'This field is required when triggers is present.' enum: - manual - schedule - webhook - event examples: - architecto name: type: - string - 'null' description: '' examples: - architecto config: type: - object - 'null' description: '' properties: { } examples: - null active: type: boolean description: '' examples: - true examples: - null required: - name - blob_definition_version '/api/v1/workflows/{id}': get: summary: 'Show a workflow' operationId: showAWorkflow description: 'Returns a single workflow by id within the current tenant.' parameters: - in: header name: X-Tenant-Id description: '' schema: type: string examples: - acme-production responses: 200: description: Success content: application/json: schema: type: object properties: id: type: integer examples: - 1 name: type: string examples: - 'Sync orders' description: type: - string - 'null' examples: - null blob_definition_version: type: string examples: - v0-draft blob: type: object properties: { } active: type: boolean examples: - true revision: type: integer examples: - 1 created_at: type: string examples: - '2026-05-06T10:00:00Z' updated_at: type: string examples: - '2026-05-06T10:00:00Z' examples: - id: 1 name: 'Sync orders' description: null blob_definition_version: v0-draft blob: { } active: true revision: 1 created_at: '2026-05-06T10:00:00Z' updated_at: '2026-05-06T10:00:00Z' 404: description: 'Not found' content: application/json: schema: type: object properties: message: type: string examples: - 'Not found.' examples: - message: 'Not found.' 429: $ref: '#/components/responses/TooManyRequests' tags: - Workflows put: summary: 'Replace a workflow' operationId: replaceAWorkflow description: "Performs a full-replace update of the workflow with the given id. All\ndomain fields are required. The `revision` counter is incremented\nexactly when the supplied `blob` differs from the stored one, in which\ncase the previous revision is snapshotted into the workflow history." parameters: - in: header name: X-Tenant-Id description: '' schema: type: string examples: - acme-production responses: 200: description: Updated content: application/json: schema: type: object properties: id: type: integer examples: - 1 name: type: string examples: - 'Sync orders' description: type: - string - 'null' examples: - null blob_definition_version: type: string examples: - v0-draft blob: type: object properties: { } active: type: boolean examples: - true revision: type: integer examples: - 2 created_at: type: string examples: - '2026-05-06T10:00:00Z' updated_at: type: string examples: - '2026-05-06T11:00:00Z' examples: - id: 1 name: 'Sync orders' description: null blob_definition_version: v0-draft blob: { } active: true revision: 2 created_at: '2026-05-06T10:00:00Z' updated_at: '2026-05-06T11:00:00Z' 404: description: 'Not found' content: application/json: schema: type: object properties: message: type: string examples: - 'Not found.' examples: - message: 'Not found.' 429: $ref: '#/components/responses/TooManyRequests' tags: - Workflows requestBody: required: true content: application/json: schema: type: object properties: name: type: string description: 'Human-readable workflow name (unique per tenant). Must not be greater than 255 characters.' examples: - 'Sync orders nightly' description: type: - string - 'null' description: 'Optional free-text description.' examples: - 'Pulls orders from the upstream API every night at 02:00 UTC.' blob_definition_version: type: string description: 'Identifier of the blob schema version. See `GET /v1/schemas/workflow`.' enum: - v0-draft examples: - v0-draft blob: type: object description: 'The workflow definition payload. Must match the schema for the supplied version.' properties: { } examples: - nodes: [] edges: [] active: type: boolean description: 'Whether the workflow is active.' examples: - true execution_mode: type: string description: 'Execution policy for run mode resolution. One of: async_only, sync_only, caller_decides.' enum: - async_only - sync_only - caller_decides examples: - async_only triggers: type: array description: '' items: type: object properties: handle: type: string description: 'This field is required when triggers is present. Must be a valid UUID.' examples: - 6ff8f7f6-1eb3-3525-be4a-3932c805afed type: type: string description: 'This field is required when triggers is present.' enum: - manual - schedule - webhook - event examples: - architecto name: type: - string - 'null' description: '' examples: - architecto config: type: - object - 'null' description: '' properties: { } examples: - null active: type: boolean description: '' examples: - false examples: - null required: - name - blob_definition_version - active - execution_mode delete: summary: 'Delete a workflow' operationId: deleteAWorkflow description: "Removes the workflow identified by `{id}` for the current tenant.\nAssociated history rows are removed via cascade." parameters: - in: header name: X-Tenant-Id description: '' schema: type: string examples: - acme-production responses: 204: description: Deleted content: text/plain: schema: type: string examples: - '' 404: description: 'Not found' content: application/json: schema: type: object properties: message: type: string examples: - 'Not found.' examples: - message: 'Not found.' 429: $ref: '#/components/responses/TooManyRequests' tags: - Workflows parameters: - in: path name: id description: 'The workflow id.' required: true schema: type: integer examples: - 1