Introduction
API for the revenexx Integration Studio — connects Revenue Cloud to external systems (ERP, PIM, CRM) via Temporal workflows.
The Integrations Service API provides endpoints for managing connections to external systems,
workflow definitions, and integration events.
All endpoints require a valid Zitadel JWT token. The active tenant is taken
from the `X-Tenant-Id` request header (a `tenant_id` JWT claim is accepted as
a legacy fallback for development tokens). Tenant isolation is enforced on
every request.
**Base URL:** `/v1`
**Versioning:** URL path prefix per [ADR-0036](https://atlas.revenexx.dev/adr/adr-0036-api-versioning-strategy).
Authenticating requests
To authenticate requests, include an Authorization header with the value "Bearer {ZITADEL_JWT}".
All authenticated endpoints are marked with a requires authentication badge in the documentation below.
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.
Audit Log
Read access to the append-only audit trail (credential / secret / workflow /
trigger create-edit-delete, plus workflow run start/finished/failed). Two
planes: the public feed is auto-scoped to the caller's org + tenant; the
admin feed (registered under v1/admin) filters all three identity fields
optionally. Results are newest-first and cursor-paginated.
List audit entries (public)
requires authentication
Returns the audit entries for the caller's org + tenant, newest first.
Optionally narrowed by sub (actor), resource_type and action.
Example request:
curl --request GET \
--get "https://integrations.revenexx.com/api/v1/audit-logs?sub=289347298347&resource_type=workflow&action=create&limit=50&cursor=eyJpZCI6NDJ9" \
--header "Authorization: Bearer {ZITADEL_JWT}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "X-Tenant-Id: acme-production"const url = new URL(
"https://integrations.revenexx.com/api/v1/audit-logs"
);
const params = {
"sub": "289347298347",
"resource_type": "workflow",
"action": "create",
"limit": "50",
"cursor": "eyJpZCI6NDJ9",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Authorization": "Bearer {ZITADEL_JWT}",
"Content-Type": "application/json",
"Accept": "application/json",
"X-Tenant-Id": "acme-production",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200, Success):
{
"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
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of this API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Response
Response Fields
data
object
actor_sub
string
The acting user subject (sub); null for system-initiated entries (via_system = true).
metadata
object
Action-specific detail recorded with the entry; null when none was captured.
Auth
Endpoints for verifying authentication and tenant context.
Get authenticated user info
requires authentication
Returns full user profile, resolved tenant context, and raw token claims. Useful for debugging authentication and understanding which data Zitadel provides.
Example request:
curl --request GET \
--get "https://integrations.revenexx.com/api/v1/me" \
--header "Authorization: Bearer {ZITADEL_JWT}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "X-Tenant-Id: acme-production"const url = new URL(
"https://integrations.revenexx.com/api/v1/me"
);
const headers = {
"Authorization": "Bearer {ZITADEL_JWT}",
"Content-Type": "application/json",
"Accept": "application/json",
"X-Tenant-Id": "acme-production",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200, Success):
{
"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"
]
}
}
Example response (401, Missing or invalid token):
{
"message": "Unauthenticated."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of this API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Credential Types
Read-only catalogue of the credential types registered via node packages.
Drives the credential form (fields + validation) and the credentials-ref
type picker in the editor. Globally registered, not tenant-scoped.
List credential types
requires authentication
Returns the latest registered version of each credential type.
Example request:
curl --request GET \
--get "https://integrations.revenexx.com/api/v1/credential-types" \
--header "Authorization: Bearer {ZITADEL_JWT}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "X-Tenant-Id: acme-production"const url = new URL(
"https://integrations.revenexx.com/api/v1/credential-types"
);
const headers = {
"Authorization": "Bearer {ZITADEL_JWT}",
"Content-Type": "application/json",
"Accept": "application/json",
"X-Tenant-Id": "acme-production",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200, Success):
{
"data": [
{
"slug": "revenexx:smtp",
"version": "1.0.0",
"name": "SMTP",
"description": "Send mail over SMTP",
"icon": null,
"auth_kind": "secret",
"fields": []
}
]
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of this API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Show a credential type
requires authentication
Returns the latest registered version of the credential type identified by its namespaced slug.
Example request:
curl --request GET \
--get "https://integrations.revenexx.com/api/v1/credential-types/revenexx:smtp" \
--header "Authorization: Bearer {ZITADEL_JWT}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "X-Tenant-Id: acme-production"const url = new URL(
"https://integrations.revenexx.com/api/v1/credential-types/revenexx:smtp"
);
const headers = {
"Authorization": "Bearer {ZITADEL_JWT}",
"Content-Type": "application/json",
"Accept": "application/json",
"X-Tenant-Id": "acme-production",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200, Success):
{
"data": {
"slug": "revenexx:smtp",
"version": "1.0.0",
"name": "SMTP",
"description": "Send mail over SMTP",
"icon": null,
"auth_kind": "secret",
"fields": []
}
}
Example response (404, Not found):
{
"message": "Not found."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of this API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Credentials
Tenant-scoped credential instances of a registered {@see CredentialType}.
The encrypted config / durable_creds blobs are never returned. Runtime
resolution happens in the broker, not here — this controller only stores and
proxies the on-demand connection test.
OAuth redirect callback (public)
The provider redirects the user's browser here with code + state.
Unauthenticated by necessity — the single-use state (looked up in the
cache) is the CSRF protection and carries the tenant + PKCE verifier.
Example request:
curl --request GET \
--get "https://integrations.revenexx.com/api/v1/credentials/oauth/callback" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "X-Tenant-Id: acme-production"const url = new URL(
"https://integrations.revenexx.com/api/v1/credentials/oauth/callback"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"X-Tenant-Id": "acme-production",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200, Connected):
{
"status": "connected",
"credential_id": 1
}
Example response (400, Missing or invalid state):
{
"message": "Invalid or expired OAuth state."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of this API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
List credentials
requires authentication
Returns the current tenant's credential instances, optionally filtered to
a single credential type via ?type={slug}. Secrets are never exposed.
Example request:
curl --request GET \
--get "https://integrations.revenexx.com/api/v1/credentials?type=revenexx%3Asmtp" \
--header "Authorization: Bearer {ZITADEL_JWT}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "X-Tenant-Id: acme-production"const url = new URL(
"https://integrations.revenexx.com/api/v1/credentials"
);
const params = {
"type": "revenexx:smtp",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Authorization": "Bearer {ZITADEL_JWT}",
"Content-Type": "application/json",
"Accept": "application/json",
"X-Tenant-Id": "acme-production",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200, Success):
{
"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"
}
]
}
Example response (401, Missing or invalid token):
{
"message": "Unauthenticated."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of this API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Create a credential
requires authentication
Validates the submitted config against the credential type's declared
fields, then stores it encrypted. Returns 201 with the masked instance.
Example request:
curl --request POST \
"https://integrations.revenexx.com/api/v1/credentials" \
--header "Authorization: Bearer {ZITADEL_JWT}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "X-Tenant-Id: acme-production" \
--data "{
\"credential_type_slug\": \"revenexx:smtp\",
\"name\": \"Mailpit\",
\"config\": {
\"host\": \"smtp.example.com\",
\"port\": 587,
\"username\": \"mailer\",
\"password\": \"sekret\"
}
}"
const url = new URL(
"https://integrations.revenexx.com/api/v1/credentials"
);
const headers = {
"Authorization": "Bearer {ZITADEL_JWT}",
"Content-Type": "application/json",
"Accept": "application/json",
"X-Tenant-Id": "acme-production",
};
let body = {
"credential_type_slug": "revenexx:smtp",
"name": "Mailpit",
"config": {
"host": "smtp.example.com",
"port": 587,
"username": "mailer",
"password": "sekret"
}
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (201, Created):
{
"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"
}
Example response (422, Validation failed):
{
"message": "The given data was invalid.",
"errors": {
"config": [
"..."
]
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of this API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Test an unsaved credential
requires authentication
Runs the broker connection test against an inline type + config, before the instance is persisted. Non-blocking.
Example request:
curl --request POST \
"https://integrations.revenexx.com/api/v1/credentials/test" \
--header "Authorization: Bearer {ZITADEL_JWT}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "X-Tenant-Id: acme-production" \
--data "{
\"credential_type_slug\": \"revenexx:smtp\",
\"config\": {
\"host\": \"smtp.example.com\",
\"port\": 587,
\"username\": \"mailer\",
\"password\": \"sekret\"
}
}"
const url = new URL(
"https://integrations.revenexx.com/api/v1/credentials/test"
);
const headers = {
"Authorization": "Bearer {ZITADEL_JWT}",
"Content-Type": "application/json",
"Accept": "application/json",
"X-Tenant-Id": "acme-production",
};
let body = {
"credential_type_slug": "revenexx:smtp",
"config": {
"host": "smtp.example.com",
"port": 587,
"username": "mailer",
"password": "sekret"
}
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (200, Tested):
{
"ok": true
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of this API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Show a credential
requires authentication
Example request:
curl --request GET \
--get "https://integrations.revenexx.com/api/v1/credentials/019f124d-b287-731d-8879-de2bf1fa6924" \
--header "Authorization: Bearer {ZITADEL_JWT}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "X-Tenant-Id: acme-production"const url = new URL(
"https://integrations.revenexx.com/api/v1/credentials/019f124d-b287-731d-8879-de2bf1fa6924"
);
const headers = {
"Authorization": "Bearer {ZITADEL_JWT}",
"Content-Type": "application/json",
"Accept": "application/json",
"X-Tenant-Id": "acme-production",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200, Success):
{
"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"
}
Example response (404, Not found):
{
"message": "Not found."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of this API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Update a credential
requires authentication
Updates the name and/or config. When config is supplied it is
re-validated against the credential type's declared fields.
Example request:
curl --request PATCH \
"https://integrations.revenexx.com/api/v1/credentials/019f124d-b287-731d-8879-de2bf1fa6924" \
--header "Authorization: Bearer {ZITADEL_JWT}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "X-Tenant-Id: acme-production" \
--data "{
\"name\": \"Mailpit (staging)\",
\"config\": {
\"host\": \"smtp.example.com\",
\"port\": 587,
\"username\": \"mailer\",
\"password\": \"sekret\"
}
}"
const url = new URL(
"https://integrations.revenexx.com/api/v1/credentials/019f124d-b287-731d-8879-de2bf1fa6924"
);
const headers = {
"Authorization": "Bearer {ZITADEL_JWT}",
"Content-Type": "application/json",
"Accept": "application/json",
"X-Tenant-Id": "acme-production",
};
let body = {
"name": "Mailpit (staging)",
"config": {
"host": "smtp.example.com",
"port": 587,
"username": "mailer",
"password": "sekret"
}
};
fetch(url, {
method: "PATCH",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (200, Updated):
{
"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"
}
Example response (404, Not found):
{
"message": "Not found."
}
Example response (422, Validation failed):
{
"message": "The given data was invalid.",
"errors": {
"config": [
"..."
]
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of this API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Delete a credential
requires authentication
Example request:
curl --request DELETE \
"https://integrations.revenexx.com/api/v1/credentials/019f124d-b287-731d-8879-de2bf1fa6924" \
--header "Authorization: Bearer {ZITADEL_JWT}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "X-Tenant-Id: acme-production"const url = new URL(
"https://integrations.revenexx.com/api/v1/credentials/019f124d-b287-731d-8879-de2bf1fa6924"
);
const headers = {
"Authorization": "Bearer {ZITADEL_JWT}",
"Content-Type": "application/json",
"Accept": "application/json",
"X-Tenant-Id": "acme-production",
};
fetch(url, {
method: "DELETE",
headers,
}).then(response => response.json());Example response (204, Deleted):
Empty response
Example response (404, Not found):
{
"message": "Not found."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of this API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Test a saved credential
requires authentication
Runs the credential type's connection test in the broker against the stored config. Non-blocking — does not change the stored instance.
Example request:
curl --request POST \
"https://integrations.revenexx.com/api/v1/credentials/019f124d-b287-731d-8879-de2bf1fa6924/test" \
--header "Authorization: Bearer {ZITADEL_JWT}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "X-Tenant-Id: acme-production"const url = new URL(
"https://integrations.revenexx.com/api/v1/credentials/019f124d-b287-731d-8879-de2bf1fa6924/test"
);
const headers = {
"Authorization": "Bearer {ZITADEL_JWT}",
"Content-Type": "application/json",
"Accept": "application/json",
"X-Tenant-Id": "acme-production",
};
fetch(url, {
method: "POST",
headers,
}).then(response => response.json());Example response (200, Tested):
{
"ok": true
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of this API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Begin 3-legged OAuth setup
requires authentication
Returns the provider authorize URL for the credential. The caller (the cockpit) opens it; the provider redirects back to the public callback.
Node Packages
Stream a node-package image.
requires authentication
Example request:
curl --request GET \
--get "https://integrations.revenexx.com/api/v1/node-packages/images/architecto?expires=16&signature=architecto" \
--header "Authorization: Bearer {ZITADEL_JWT}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "X-Tenant-Id: acme-production"const url = new URL(
"https://integrations.revenexx.com/api/v1/node-packages/images/architecto"
);
const params = {
"expires": "16",
"signature": "architecto",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Authorization": "Bearer {ZITADEL_JWT}",
"Content-Type": "application/json",
"Accept": "application/json",
"X-Tenant-Id": "acme-production",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200, Valid signature):
"<binary image stream>"
Example response (403, Missing, tampered, or expired signature):
{
"message": "Invalid signature."
}
Example response (404, Unknown image, or stored file missing):
{
"message": "Not Found"
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of this API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Nodes
Globally registered node definitions, addressed publicly by
<slug>/<version>. Read endpoints additionally accept the alias
latest in place of an explicit version. The DELETE endpoint refuses
the alias and requires an exact version, so the caller always knows which
row they're touching.
Nodes are created and updated exclusively through the node-package upload
(POST /v1/admin/orgs/{org_id}/node-packages), which extracts the manifests
from the published tarball — there is no standalone create/update endpoint,
since a node always ships with its runtime code.
Authentication is required for every endpoint, but the resource itself is not tenant-scoped — per-tenant entitlement (which tenant may use which node) is the responsibility of a future app-registration flow.
List nodes
requires authentication
Returns the registered nodes ordered by slug ascending, then
semver descending. Optionally filters to a single namespace via the
namespace query parameter.
Example request:
curl --request GET \
--get "https://integrations.revenexx.com/api/v1/nodes?namespace=revenexx" \
--header "Authorization: Bearer {ZITADEL_JWT}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "X-Tenant-Id: acme-production"const url = new URL(
"https://integrations.revenexx.com/api/v1/nodes"
);
const params = {
"namespace": "revenexx",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Authorization": "Bearer {ZITADEL_JWT}",
"Content-Type": "application/json",
"Accept": "application/json",
"X-Tenant-Id": "acme-production",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200, Success):
{
"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"
}
]
}
Example response (401, Missing or invalid token):
{
"message": "Unauthenticated."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of this API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
List versions for a node
requires authentication
Returns the registered versions for a given slug, semver-descending.
The slug must match at least one stored row, otherwise a 404 is
returned — there's no representation for "an empty list of
versions". The response intentionally only contains version
strings; callers that need the full row should follow up with
GET /nodes/{slug}/{version}.
Example request:
curl --request GET \
--get "https://integrations.revenexx.com/api/v1/nodes/revenexx:http-request/versions" \
--header "Authorization: Bearer {ZITADEL_JWT}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "X-Tenant-Id: acme-production"const url = new URL(
"https://integrations.revenexx.com/api/v1/nodes/revenexx:http-request/versions"
);
const headers = {
"Authorization": "Bearer {ZITADEL_JWT}",
"Content-Type": "application/json",
"Accept": "application/json",
"X-Tenant-Id": "acme-production",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200, Success):
{
"data": [
"2.5.0",
"1.10.0",
"1.0.0"
]
}
Example response (404, Unknown slug):
{
"message": "Not found."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of this API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Show a node
requires authentication
Returns a single node by (slug, version). The version may be the
literal string latest, in which case the highest semver registered
for the slug is returned.
Example request:
curl --request GET \
--get "https://integrations.revenexx.com/api/v1/nodes/revenexx:http-request/1.0.0" \
--header "Authorization: Bearer {ZITADEL_JWT}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "X-Tenant-Id: acme-production"const url = new URL(
"https://integrations.revenexx.com/api/v1/nodes/revenexx:http-request/1.0.0"
);
const headers = {
"Authorization": "Bearer {ZITADEL_JWT}",
"Content-Type": "application/json",
"Accept": "application/json",
"X-Tenant-Id": "acme-production",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200, Success):
{
"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"
}
Example response (404, Not found):
{
"message": "Not found."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of this API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Resolve dynamic node config
requires authentication
Example request:
curl --request POST \
"https://integrations.revenexx.com/api/v1/nodes/revenexx:api/1.0.0/config:resolve" \
--header "Authorization: Bearer {ZITADEL_JWT}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "X-Tenant-Id: acme-production" \
--data "{
\"target\": \"*\",
\"config\": [],
\"locale\": \"de\"
}"
const url = new URL(
"https://integrations.revenexx.com/api/v1/nodes/revenexx:api/1.0.0/config:resolve"
);
const headers = {
"Authorization": "Bearer {ZITADEL_JWT}",
"Content-Type": "application/json",
"Accept": "application/json",
"X-Tenant-Id": "acme-production",
};
let body = {
"target": "*",
"config": [],
"locale": "de"
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (200, Resolved):
{
"fields": [
{
"key": "customerId",
"type": "string"
}
],
"outputs": [
{
"name": "success"
}
]
}
Example response (404, Unknown node):
{
"message": "Not found."
}
Example response (409, Bundle not built yet):
{
"message": "Node bundle is not built yet; retry shortly."
}
Example response (502, Node runtime unavailable or failed):
{
"message": "Node runtime resolve failed: ..."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of this API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Delete a node
requires authentication
Removes the node version identified by (slug, version). The
latest alias is rejected to prevent ambiguous deletes.
Example request:
curl --request DELETE \
"https://integrations.revenexx.com/api/v1/nodes/revenexx:http-request/1.0.0" \
--header "Authorization: Bearer {ZITADEL_JWT}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "X-Tenant-Id: acme-production"const url = new URL(
"https://integrations.revenexx.com/api/v1/nodes/revenexx:http-request/1.0.0"
);
const headers = {
"Authorization": "Bearer {ZITADEL_JWT}",
"Content-Type": "application/json",
"Accept": "application/json",
"X-Tenant-Id": "acme-production",
};
fetch(url, {
method: "DELETE",
headers,
}).then(response => response.json());Example response (204, Deleted):
Empty response
Example response (400, Latest alias rejected):
{
"message": "The `latest` alias is not allowed for mutating requests."
}
Example response (404, Not found):
{
"message": "Not found."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of this API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Schemas
Public, read-only access to the JSON-Schema definitions used to validate
versioned payloads (currently the workflow blob and the node manifest).
Schemas are global — they describe the shape of payloads regardless of
tenant — so these endpoints are intentionally unauthenticated.
List schema versions
Returns the identifiers of every registered schema version for the given domain, in registration order (which is also the order in which they are accepted by the validation layer).
Example request:
curl --request GET \
--get "https://integrations.revenexx.com/api/v1/schemas/workflow" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://integrations.revenexx.com/api/v1/schemas/workflow"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200, Success):
{
"domain": "workflow",
"versions": [
"v0-draft"
]
}
Example response (404, Unknown domain):
{
"message": "Unknown schema domain."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of this API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Show a schema version
Returns the serialized JSON-Schema definition for one specific
(domain, version) pair. The payload uses the standard JSON Schema
vocabulary (type, properties, required, …) and is suitable for
client-side validation or form generation.
Example request:
curl --request GET \
--get "https://integrations.revenexx.com/api/v1/schemas/workflow/v0-draft" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://integrations.revenexx.com/api/v1/schemas/workflow/v0-draft"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200, Success):
{
"domain": "workflow",
"version": "v0-draft",
"schema": {
"title": "Workflow Definition (v0-draft)",
"type": "object"
}
}
Example response (404, Unknown version):
{
"message": "Unknown schema version."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of this API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Templates
Catalogue of the workflow templates registered via node packages, plus the "install" actions a UI uses to turn one into a real workflow. Listing/showing is global; instantiation is scoped to the current tenant.
List templates
requires authentication
Returns the latest registered version of each template, without the
(heavy) embedded workflow definition blob — that ships only on show.
Example request:
curl --request GET \
--get "https://integrations.revenexx.com/api/v1/templates" \
--header "Authorization: Bearer {ZITADEL_JWT}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "X-Tenant-Id: acme-production"const url = new URL(
"https://integrations.revenexx.com/api/v1/templates"
);
const headers = {
"Authorization": "Bearer {ZITADEL_JWT}",
"Content-Type": "application/json",
"Accept": "application/json",
"X-Tenant-Id": "acme-production",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200, Success):
{
"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"
]
}
]
}
Example response (401, Missing or invalid token):
{
"message": "Unauthenticated."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of this API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Show a template
requires authentication
Returns the latest registered version of the template identified by its
namespaced slug, including the embedded workflow definition used to
instantiate a new workflow.
Example request:
curl --request GET \
--get "https://integrations.revenexx.com/api/v1/templates/revenexx:slack-to-crm" \
--header "Authorization: Bearer {ZITADEL_JWT}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "X-Tenant-Id: acme-production"const url = new URL(
"https://integrations.revenexx.com/api/v1/templates/revenexx:slack-to-crm"
);
const headers = {
"Authorization": "Bearer {ZITADEL_JWT}",
"Content-Type": "application/json",
"Accept": "application/json",
"X-Tenant-Id": "acme-production",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200, Success):
{
"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 * * *"
}
}
]
}
}
Example response (404, Not found):
{
"message": "Not found."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of this API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Template installation requirements
requires authentication
Lists the credential types and secret keys the template's workflow references, cross-referenced against the current tenant (how many credential instances already exist, whether each secret key is stored) so an install UI can have the user provision what is missing first.
Example request:
curl --request GET \
--get "https://integrations.revenexx.com/api/v1/templates/revenexx:slack-to-crm/requirements" \
--header "Authorization: Bearer {ZITADEL_JWT}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "X-Tenant-Id: acme-production"const url = new URL(
"https://integrations.revenexx.com/api/v1/templates/revenexx:slack-to-crm/requirements"
);
const headers = {
"Authorization": "Bearer {ZITADEL_JWT}",
"Content-Type": "application/json",
"Accept": "application/json",
"X-Tenant-Id": "acme-production",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200, Success):
{
"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": []
}
}
Example response (404, Not found):
{
"message": "Not found."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of this API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Instantiate a template
requires authentication
Creates a new workflow (and its triggers) for the current tenant from the template's blueprint. Trigger handles are regenerated so repeated installs never collide; the workflow and all triggers start inactive. Returns the created workflow.
Example request:
curl --request POST \
"https://integrations.revenexx.com/api/v1/templates/revenexx:slack-to-crm/instantiate" \
--header "Authorization: Bearer {ZITADEL_JWT}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "X-Tenant-Id: acme-production" \
--data "{
\"name\": \"My Slack flow\",
\"credential_bindings\": [
\"6ff8f7f6-1eb3-3525-be4a-3932c805afed\"
]
}"
const url = new URL(
"https://integrations.revenexx.com/api/v1/templates/revenexx:slack-to-crm/instantiate"
);
const headers = {
"Authorization": "Bearer {ZITADEL_JWT}",
"Content-Type": "application/json",
"Accept": "application/json",
"X-Tenant-Id": "acme-production",
};
let body = {
"name": "My Slack flow",
"credential_bindings": [
"6ff8f7f6-1eb3-3525-be4a-3932c805afed"
]
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (201, Created):
{
"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"
}
Example response (404, Not found):
{
"message": "Not found."
}
Example response (422, Validation failed):
{
"message": "The given data was invalid.",
"errors": {
"credential_bindings": [
"The credential_bindings field must be an array."
]
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of this API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Tenant Secrets
Per-tenant encrypted key/value store. Values are AES-256-GCM encrypted at rest using a dedicated SECRETS_ENCRYPTION_KEY (separate from APP_KEY) and are never returned by the API.
List secret keys
requires authentication
Returns the alphabetically sorted list of secret keys for the current tenant. Values are never exposed.
Example request:
curl --request GET \
--get "https://integrations.revenexx.com/api/v1/secrets" \
--header "Authorization: Bearer {ZITADEL_JWT}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "X-Tenant-Id: acme-production"const url = new URL(
"https://integrations.revenexx.com/api/v1/secrets"
);
const headers = {
"Authorization": "Bearer {ZITADEL_JWT}",
"Content-Type": "application/json",
"Accept": "application/json",
"X-Tenant-Id": "acme-production",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200, Success):
{
"keys": [
"SLACK_WEBHOOK_URL",
"STRIPE_API_KEY"
]
}
Example response (401, Missing or invalid token):
{
"message": "Unauthenticated."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of this API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Create or update a secret
requires authentication
Upserts a secret value for the given key within the current tenant. Returns 201 on creation, 200 on update. The value is never echoed back.
Example request:
curl --request POST \
"https://integrations.revenexx.com/api/v1/secrets" \
--header "Authorization: Bearer {ZITADEL_JWT}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "X-Tenant-Id: acme-production" \
--data "{
\"key\": \"STRIPE_API_KEY\",
\"value\": \"sk_live_abc123\"
}"
const url = new URL(
"https://integrations.revenexx.com/api/v1/secrets"
);
const headers = {
"Authorization": "Bearer {ZITADEL_JWT}",
"Content-Type": "application/json",
"Accept": "application/json",
"X-Tenant-Id": "acme-production",
};
let body = {
"key": "STRIPE_API_KEY",
"value": "sk_live_abc123"
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (200, Updated):
{
"key": "STRIPE_API_KEY",
"created_at": "2026-05-04T08:50:00Z",
"updated_at": "2026-05-05T08:50:00Z"
}
Example response (201, Created):
{
"key": "STRIPE_API_KEY",
"created_at": "2026-05-05T08:50:00Z",
"updated_at": "2026-05-05T08:50:00Z"
}
Example response (422, Validation failed):
{
"message": "The key field format is invalid.",
"errors": {
"key": [
"..."
]
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of this API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Update a secret value
requires authentication
Replaces the value of an existing secret. The key is immutable — create a new secret and delete the old one if you need to rename a key. Returns 404 if the key does not exist for the current tenant.
Example request:
curl --request PATCH \
"https://integrations.revenexx.com/api/v1/secrets/bc-client-secret" \
--header "Authorization: Bearer {ZITADEL_JWT}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "X-Tenant-Id: acme-production" \
--data "{
\"value\": \"sk_live_new_value\"
}"
const url = new URL(
"https://integrations.revenexx.com/api/v1/secrets/bc-client-secret"
);
const headers = {
"Authorization": "Bearer {ZITADEL_JWT}",
"Content-Type": "application/json",
"Accept": "application/json",
"X-Tenant-Id": "acme-production",
};
let body = {
"value": "sk_live_new_value"
};
fetch(url, {
method: "PATCH",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (200, Updated):
{
"key": "bc-client-secret",
"created_at": "2026-05-04T08:50:00Z",
"updated_at": "2026-06-12T10:00:00Z"
}
Example response (404, Not found):
{
"message": "Not found."
}
Example response (422, Validation failed):
{
"message": "The value field is required.",
"errors": {
"value": [
"..."
]
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of this API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Delete a secret
requires authentication
Removes the secret identified by {key} for the current tenant. The
lookup is explicitly scoped to the current tenant, so a key belonging
to another tenant — or one that does not exist at all — yields a 404
without leaking existence either way.
Example request:
curl --request DELETE \
"https://integrations.revenexx.com/api/v1/secrets/STRIPE_API_KEY" \
--header "Authorization: Bearer {ZITADEL_JWT}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "X-Tenant-Id: acme-production"const url = new URL(
"https://integrations.revenexx.com/api/v1/secrets/STRIPE_API_KEY"
);
const headers = {
"Authorization": "Bearer {ZITADEL_JWT}",
"Content-Type": "application/json",
"Accept": "application/json",
"X-Tenant-Id": "acme-production",
};
fetch(url, {
method: "DELETE",
headers,
}).then(response => response.json());Example response (204, Deleted):
Empty response
Example response (404, Not found):
{
"message": "Not found."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of this API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Triggers
Manage triggers for a workflow. Triggers are the entry points that can start a workflow execution (manual, schedule, webhook, or event). They live as DB entities rather than inside the workflow blob, and are referenced in blob edges via their stable UUID handle.
List triggers for a workflow
requires authentication
Example request:
curl --request GET \
--get "https://integrations.revenexx.com/api/v1/workflows/1/triggers" \
--header "Authorization: Bearer {ZITADEL_JWT}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "X-Tenant-Id: acme-production"const url = new URL(
"https://integrations.revenexx.com/api/v1/workflows/1/triggers"
);
const headers = {
"Authorization": "Bearer {ZITADEL_JWT}",
"Content-Type": "application/json",
"Accept": "application/json",
"X-Tenant-Id": "acme-production",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200, Success):
{
"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"
}
]
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of this API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Create a trigger
requires authentication
Example request:
curl --request POST \
"https://integrations.revenexx.com/api/v1/workflows/1/triggers" \
--header "Authorization: Bearer {ZITADEL_JWT}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "X-Tenant-Id: acme-production" \
--data "{
\"handle\": \"6ff8f7f6-1eb3-3525-be4a-3932c805afed\",
\"type\": \"webhook\",
\"name\": \"PSP webhook\",
\"active\": true,
\"config\": {
\"method\": \"POST\",
\"public\": true
}
}"
const url = new URL(
"https://integrations.revenexx.com/api/v1/workflows/1/triggers"
);
const headers = {
"Authorization": "Bearer {ZITADEL_JWT}",
"Content-Type": "application/json",
"Accept": "application/json",
"X-Tenant-Id": "acme-production",
};
let body = {
"handle": "6ff8f7f6-1eb3-3525-be4a-3932c805afed",
"type": "webhook",
"name": "PSP webhook",
"active": true,
"config": {
"method": "POST",
"public": true
}
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (201, Public webhook trigger):
{
"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"
}
Example response (422, Validation failed):
{
"message": "The config.method field is required.",
"errors": {
"config.method": [
"The config.method field is required."
]
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of this API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Response
Response Fields
inbound_secret
string
Present ONLY right after a public webhook endpoint is provisioned — the ingress ingest token, returned once and never stored (ADR-0066).
config
object
inbound
object
Server-owned ingress registration (endpoint_id, url) for a public webhook trigger. Clients cannot set or modify it.
Update a trigger
requires authentication
Example request:
curl --request PUT \
"https://integrations.revenexx.com/api/v1/workflows/1/triggers/1" \
--header "Authorization: Bearer {ZITADEL_JWT}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "X-Tenant-Id: acme-production" \
--data "{
\"type\": \"webhook\",
\"name\": \"PSP webhook\",
\"active\": true,
\"config\": {
\"method\": \"POST\",
\"public\": true
}
}"
const url = new URL(
"https://integrations.revenexx.com/api/v1/workflows/1/triggers/1"
);
const headers = {
"Authorization": "Bearer {ZITADEL_JWT}",
"Content-Type": "application/json",
"Accept": "application/json",
"X-Tenant-Id": "acme-production",
};
let body = {
"type": "webhook",
"name": "PSP webhook",
"active": true,
"config": {
"method": "POST",
"public": true
}
};
fetch(url, {
method: "PUT",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (200, Public webhook trigger):
{
"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"
}
Example response (422, Validation failed):
{
"message": "The config.method field is required.",
"errors": {
"config.method": [
"The config.method field is required."
]
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of this API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Response
Response Fields
inbound_secret
string
Present ONLY right after a public webhook endpoint is provisioned — the ingress ingest token, returned once and never stored (ADR-0066).
config
object
inbound
object
Server-owned ingress registration (endpoint_id, url) for a public webhook trigger. Clients cannot set or modify it.
Delete a trigger
requires authentication
Example request:
curl --request DELETE \
"https://integrations.revenexx.com/api/v1/workflows/1/triggers/1" \
--header "Authorization: Bearer {ZITADEL_JWT}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "X-Tenant-Id: acme-production"const url = new URL(
"https://integrations.revenexx.com/api/v1/workflows/1/triggers/1"
);
const headers = {
"Authorization": "Bearer {ZITADEL_JWT}",
"Content-Type": "application/json",
"Accept": "application/json",
"X-Tenant-Id": "acme-production",
};
fetch(url, {
method: "DELETE",
headers,
}).then(response => response.json());Example response (204, Deleted):
Empty response
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of this API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Webhooks
Inbound endpoint that fires a workflow run for a webhook trigger. The
trigger is addressed by its UUID handle in the URL; authentication is the
standard JWT + X-Tenant-Id used by the rest of the API, so the trigger is
resolved within the caller's tenant. The HTTP request (body, query,
headers, method) is delivered to the workflow as the trigger payload,
reachable via ${{ trigger.payload.* }}.
Fire a webhook trigger
requires authentication
Resolves the webhook trigger by handle, enforces the configured HTTP
method, and starts a run. The mode follows the workflow's execution_mode
(async_only → 202; sync_only/caller_decides → wait and return the
result), and can be overridden per request with ?mode=sync|async when
the policy allows it — a conflicting mode is rejected with 422.
Example request:
curl --request GET \
--get "https://integrations.revenexx.com/api/v1/webhooks/0190a9c0-1111-7000-8000-000000000000?mode=async" \
--header "Authorization: Bearer {ZITADEL_JWT}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "X-Tenant-Id: acme-production"const url = new URL(
"https://integrations.revenexx.com/api/v1/webhooks/0190a9c0-1111-7000-8000-000000000000"
);
const params = {
"mode": "async",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Authorization": "Bearer {ZITADEL_JWT}",
"Content-Type": "application/json",
"Accept": "application/json",
"X-Tenant-Id": "acme-production",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200, Completed (sync)):
{
"id": 1,
"workflow_id": 1,
"status": "completed",
"result": {}
}
Example response (202, Accepted (async)):
{
"id": 1,
"workflow_id": 1,
"status": "running"
}
Example response (404, No such webhook trigger):
{
"message": "No active webhook trigger with handle … exists."
}
Example response (405, Method not allowed):
{
"message": "This webhook expects POST."
}
Example response (422, Mode conflicts with policy):
{
"message": "Workflow does not allow sync execution (execution_mode=async_only)."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of this API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Workflow Credentials
Read-only introspection of which typed credentials a workflow's nodes
reference through their credentials-ref config fields. Useful for pre-run
checks, access auditing, and impact analysis when a credential instance is
rotated or deleted. The credential values are never touched here — only
the instance UUIDs and their credential type slugs are reported.
List credential ids used across the tenant's workflows
requires authentication
Returns the distinct credential instance UUIDs referenced by every
workflow of the current tenant. Optionally filtered to a single
credential type slug via ?type={slug} and/or to active workflows only
via ?active=true.
Example request:
curl --request GET \
--get "https://integrations.revenexx.com/api/v1/workflows/used-credentials?type=revenexx%3Asmtp&active=1" \
--header "Authorization: Bearer {ZITADEL_JWT}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "X-Tenant-Id: acme-production"const url = new URL(
"https://integrations.revenexx.com/api/v1/workflows/used-credentials"
);
const params = {
"type": "revenexx:smtp",
"active": "1",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Authorization": "Bearer {ZITADEL_JWT}",
"Content-Type": "application/json",
"Accept": "application/json",
"X-Tenant-Id": "acme-production",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200, Used credentials):
{
"data": [
"9f3e2c1a-0000-4000-8000-000000000001",
"1ab2c3d4-0000-4000-8000-000000000002"
]
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of this API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
List credential type slugs used across the tenant's workflows
requires authentication
Returns the distinct credential type slugs (e.g. revenexx:smtp)
referenced by every workflow of the current tenant. Optionally filtered
to active workflows only via ?active=true.
Example request:
curl --request GET \
--get "https://integrations.revenexx.com/api/v1/workflows/used-credential-types?active=1" \
--header "Authorization: Bearer {ZITADEL_JWT}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "X-Tenant-Id: acme-production"const url = new URL(
"https://integrations.revenexx.com/api/v1/workflows/used-credential-types"
);
const params = {
"active": "1",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Authorization": "Bearer {ZITADEL_JWT}",
"Content-Type": "application/json",
"Accept": "application/json",
"X-Tenant-Id": "acme-production",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200, Used credential types):
{
"data": [
"revenexx:smtp",
"revenexx:deepl"
]
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of this API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
List credential ids used by a workflow
requires authentication
Returns the distinct credential instance UUIDs the workflow's nodes
reference, optionally filtered to a single credential type slug via
?type={slug}.
Example request:
curl --request GET \
--get "https://integrations.revenexx.com/api/v1/workflows/1/credentials?type=revenexx%3Asmtp" \
--header "Authorization: Bearer {ZITADEL_JWT}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "X-Tenant-Id: acme-production"const url = new URL(
"https://integrations.revenexx.com/api/v1/workflows/1/credentials"
);
const params = {
"type": "revenexx:smtp",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Authorization": "Bearer {ZITADEL_JWT}",
"Content-Type": "application/json",
"Accept": "application/json",
"X-Tenant-Id": "acme-production",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200, Used credentials):
{
"data": [
"9f3e2c1a-0000-4000-8000-000000000001",
"1ab2c3d4-0000-4000-8000-000000000002"
]
}
Example response (404, Workflow not found):
{
"message": "Not found."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of this API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
List credential type slugs used by a workflow
requires authentication
Returns the distinct credential type slugs (e.g. revenexx:smtp) the
workflow's nodes reference through their credentials-ref config fields.
Example request:
curl --request GET \
--get "https://integrations.revenexx.com/api/v1/workflows/1/credential-types" \
--header "Authorization: Bearer {ZITADEL_JWT}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "X-Tenant-Id: acme-production"const url = new URL(
"https://integrations.revenexx.com/api/v1/workflows/1/credential-types"
);
const headers = {
"Authorization": "Bearer {ZITADEL_JWT}",
"Content-Type": "application/json",
"Accept": "application/json",
"X-Tenant-Id": "acme-production",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200, Used credential types):
{
"data": [
"revenexx:smtp",
"revenexx:deepl"
]
}
Example response (404, Workflow not found):
{
"message": "Not found."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of this API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Workflow Revisions
Read the archived revision history of a workflow and restore an old
revision. Every blob change to a workflow snapshots the previous revision
into workflow_histories; these endpoints expose that history and let a
client re-apply an old revision as a brand-new one.
All endpoints are scoped to the tenant resolved by the resolve.tenant
middleware. Cross-tenant access returns 404 so the API never leaks the
existence of resources owned by other tenants.
List workflow revisions
requires authentication
Returns the archived revisions of a workflow, newest first, paginated.
List items carry metadata only — use the show endpoint to fetch a
single revision's full blob and triggers.
Example request:
curl --request GET \
--get "https://integrations.revenexx.com/api/v1/workflows/1/revisions?page=1&per_page=25" \
--header "Authorization: Bearer {ZITADEL_JWT}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "X-Tenant-Id: acme-production"const url = new URL(
"https://integrations.revenexx.com/api/v1/workflows/1/revisions"
);
const params = {
"page": "1",
"per_page": "25",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Authorization": "Bearer {ZITADEL_JWT}",
"Content-Type": "application/json",
"Accept": "application/json",
"X-Tenant-Id": "acme-production",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200, Success):
{
"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
}
}
Example response (404, Workflow not found):
{
"message": "Not found."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of this API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Show a workflow revision
requires authentication
Returns a single archived revision in full, including its blob and
triggers snapshot.
Example request:
curl --request GET \
--get "https://integrations.revenexx.com/api/v1/workflows/1/revisions/1" \
--header "Authorization: Bearer {ZITADEL_JWT}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "X-Tenant-Id: acme-production"const url = new URL(
"https://integrations.revenexx.com/api/v1/workflows/1/revisions/1"
);
const headers = {
"Authorization": "Bearer {ZITADEL_JWT}",
"Content-Type": "application/json",
"Accept": "application/json",
"X-Tenant-Id": "acme-production",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200, Success):
{
"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"
}
Example response (404, Revision or workflow not found):
{
"message": "Not found."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of this API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Restore a workflow revision
requires authentication
Re-applies the given archived revision's definition (blob,
blob_definition_version, and triggers) to the workflow as a brand-new
revision. The current state is first snapshotted into the history, the
revision counter is bumped, and a fresh bundle build is dispatched. The
workflow's name, description, active and execution_mode are left
unchanged.
Restoring a revision whose definition is identical to the current one is
a safe no-op for the revision counter (no new history row is written),
though triggers are still re-synced from the snapshot.
Example request:
curl --request POST \
"https://integrations.revenexx.com/api/v1/workflows/1/revisions/1/restore" \
--header "Authorization: Bearer {ZITADEL_JWT}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "X-Tenant-Id: acme-production"const url = new URL(
"https://integrations.revenexx.com/api/v1/workflows/1/revisions/1/restore"
);
const headers = {
"Authorization": "Bearer {ZITADEL_JWT}",
"Content-Type": "application/json",
"Accept": "application/json",
"X-Tenant-Id": "acme-production",
};
fetch(url, {
method: "POST",
headers,
}).then(response => response.json());Example response (200, Restored):
{
"id": 1,
"name": "Sync orders",
"revision": 3,
"build_status": "pending",
"blob": {},
"triggers": []
}
Example response (404, Revision or workflow not found):
{
"message": "Not found."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of this API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Workflow Runs
Trigger and inspect executions of a workflow. Each run is handed off to the workflow's dedicated Temporal worker, which orchestrates node execution and streams status back.
List runs for a workflow
requires authentication
Returns all runs for the workflow, newest first.
Example request:
curl --request GET \
--get "https://integrations.revenexx.com/api/v1/workflows/1/runs?page=1&per_page=25" \
--header "Authorization: Bearer {ZITADEL_JWT}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "X-Tenant-Id: acme-production"const url = new URL(
"https://integrations.revenexx.com/api/v1/workflows/1/runs"
);
const params = {
"page": "1",
"per_page": "25",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Authorization": "Bearer {ZITADEL_JWT}",
"Content-Type": "application/json",
"Accept": "application/json",
"X-Tenant-Id": "acme-production",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200, Success):
{
"data": [],
"meta": {
"current_page": 1,
"per_page": 25,
"total": 0,
"last_page": 1
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of this API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Start a workflow run
requires authentication
Execution behavior depends on workflow execution_mode and optional
request mode:
- Async: starts the run and returns HTTP 202 with status
running. - Sync: waits for worker completion and returns HTTP 200/422/504/503 with the final outcome.
For caller_decides, omitting mode defaults to async execution.
Example request:
curl --request POST \
"https://integrations.revenexx.com/api/v1/workflows/1/runs" \
--header "Authorization: Bearer {ZITADEL_JWT}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "X-Tenant-Id: acme-production" \
--data "{
\"trigger_payload\": {
\"source\": \"api\"
},
\"trigger_handle\": \"6ff8f7f6-1eb3-3525-be4a-3932c805afed\",
\"mode\": \"sync\"
}"
const url = new URL(
"https://integrations.revenexx.com/api/v1/workflows/1/runs"
);
const headers = {
"Authorization": "Bearer {ZITADEL_JWT}",
"Content-Type": "application/json",
"Accept": "application/json",
"X-Tenant-Id": "acme-production",
};
let body = {
"trigger_payload": {
"source": "api"
},
"trigger_handle": "6ff8f7f6-1eb3-3525-be4a-3932c805afed",
"mode": "sync"
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (200, Sync completed):
{
"id": 1,
"workflow_id": 1,
"status": "completed",
"result": {
"node-1": {
"ok": true
}
},
"completed_at": "2026-05-22T10:00:30Z"
}
Example response (202, Accepted):
{
"id": 1,
"workflow_id": 1,
"status": "running",
"temporal_workflow_id": "tenant:1:abc",
"started_at": "2026-05-13T10:00:00Z"
}
Example response (404, Workflow not found):
{
"message": "Not found."
}
Example response (422, Mode not allowed):
{
"message": "Workflow does not allow sync execution (execution_mode=async_only)."
}
Example response (422, Sync failed):
{
"message": "Workflow execution failed.",
"error": "node execution failed",
"run": {
"id": 1,
"status": "failed"
}
}
Example response (501, Sync not supported by starter):
{
"message": "Synchronous workflow execution is not supported by the configured run starter driver."
}
Example response (503, Worker unavailable):
{
"message": "Workflow worker is unavailable."
}
Example response (504, Sync timeout):
{
"message": "Workflow execution timed out.",
"error": "Sync run for workflow 1 exceeded timeout of 30 seconds."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of this API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Get a workflow run
requires authentication
Returns the current state of a workflow run. If the run is still in progress, the worker is polled for the latest Temporal status.
Example request:
curl --request GET \
--get "https://integrations.revenexx.com/api/v1/workflows/1/runs/1" \
--header "Authorization: Bearer {ZITADEL_JWT}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "X-Tenant-Id: acme-production"const url = new URL(
"https://integrations.revenexx.com/api/v1/workflows/1/runs/1"
);
const headers = {
"Authorization": "Bearer {ZITADEL_JWT}",
"Content-Type": "application/json",
"Accept": "application/json",
"X-Tenant-Id": "acme-production",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200, Completed):
{
"id": 1,
"workflow_id": 1,
"status": "completed",
"result": {},
"completed_at": "2026-05-13T10:01:00Z"
}
Example response (404, Not found):
{
"message": "Not found."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of this API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Get execution details for a workflow run
requires authentication
Returns the execution description (status, timing, history length,
parent linkage) via {@see WorkflowExecutionInspector}. The inspector
transparently routes between a live Temporal call and the local
snapshot taken when the run reached a terminal status; the response
carries a source field of "temporal" or "snapshot" so clients
know which view they are seeing.
Example request:
curl --request GET \
--get "https://integrations.revenexx.com/api/v1/workflows/1/runs/1/details" \
--header "Authorization: Bearer {ZITADEL_JWT}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "X-Tenant-Id: acme-production"const url = new URL(
"https://integrations.revenexx.com/api/v1/workflows/1/runs/1/details"
);
const headers = {
"Authorization": "Bearer {ZITADEL_JWT}",
"Content-Type": "application/json",
"Accept": "application/json",
"X-Tenant-Id": "acme-production",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200, Live):
{
"source": "temporal",
"data": {
"workflow_id": "tenant:1:abc",
"run_id": "0190...",
"status": "running"
}
}
Example response (200, Snapshot):
{
"source": "snapshot",
"data": {
"workflow_id": "tenant:1:abc",
"run_id": "0190...",
"status": "completed"
}
}
Example response (404, Run not found):
{
"message": "Not found."
}
Example response (409, Run not handed off to Temporal yet):
{
"message": "Workflow run has no Temporal execution yet."
}
Example response (410, History unavailable):
{
"message": "Workflow execution history is no longer available."
}
Example response (503, Temporal unavailable):
{
"message": "Temporal is currently unavailable."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of this API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Get execution history for a workflow run
requires authentication
Returns one page of history events via {@see WorkflowExecutionInspector}.
Like the details endpoint, the response is hybrid-routed and carries
a source field. The next_page_token is opaque (source-tagged with
tmp: or snp:); pass it verbatim to the next call. Note that
switching sources mid-pagination resets to page 1 (the response's
source will change), which the client should treat as a fresh
pagination.
Example request:
curl --request GET \
--get "https://integrations.revenexx.com/api/v1/workflows/1/runs/1/history?page_size=200" \
--header "Authorization: Bearer {ZITADEL_JWT}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "X-Tenant-Id: acme-production"const url = new URL(
"https://integrations.revenexx.com/api/v1/workflows/1/runs/1/history"
);
const params = {
"page_size": "200",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Authorization": "Bearer {ZITADEL_JWT}",
"Content-Type": "application/json",
"Accept": "application/json",
"X-Tenant-Id": "acme-production",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200, Live page):
{
"source": "temporal",
"data": [
{
"event_id": 1,
"event_type": "workflow_execution_started"
}
],
"next_page_token": null
}
Example response (200, Snapshot page):
{
"source": "snapshot",
"data": [
{
"event_id": 1
}
],
"next_page_token": null
}
Example response (404, Run not found):
{
"message": "Not found."
}
Example response (409, Run not handed off to Temporal yet):
{
"message": "Workflow run has no Temporal execution yet."
}
Example response (410, History unavailable):
{
"message": "Workflow execution history is no longer available."
}
Example response (422, Invalid page token):
{
"message": "Invalid page_token."
}
Example response (503, Temporal unavailable):
{
"message": "Temporal is currently unavailable."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of this API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Get the current call stack of a running workflow
requires authentication
Issues the built-in __stack_trace query against the workflow worker
and returns the formatted stack trace as plain text. Only meaningful
while the run is still executing; terminal runs return 409.
Example request:
curl --request GET \
--get "https://integrations.revenexx.com/api/v1/workflows/1/runs/1/stack-trace" \
--header "Authorization: Bearer {ZITADEL_JWT}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "X-Tenant-Id: acme-production"const url = new URL(
"https://integrations.revenexx.com/api/v1/workflows/1/runs/1/stack-trace"
);
const headers = {
"Authorization": "Bearer {ZITADEL_JWT}",
"Content-Type": "application/json",
"Accept": "application/json",
"X-Tenant-Id": "acme-production",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200, Running):
{
"stack_trace": "coroutine ..."
}
Example response (404, Run not found):
{
"message": "Not found."
}
Example response (409, Run not handed off to Temporal yet):
{
"message": "Workflow run has no Temporal execution yet."
}
Example response (409, Run is no longer running):
{
"message": "Workflow run is no longer running."
}
Example response (410, Execution unknown to Temporal):
{
"message": "Workflow execution history is no longer available."
}
Example response (503, Temporal unavailable):
{
"message": "Temporal is currently unavailable."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of this API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Workflows
Per-tenant workflow definitions. Every endpoint is scoped to the tenant
resolved by the resolve.tenant middleware (from the JWT or
X-Tenant-Id header). Cross-tenant access deliberately returns 404 so
that the API does not leak the existence of resources owned by other
tenants.
List workflows
requires authentication
Returns the workflows owned by the current tenant, ordered by name.
Example request:
curl --request GET \
--get "https://integrations.revenexx.com/api/v1/workflows" \
--header "Authorization: Bearer {ZITADEL_JWT}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "X-Tenant-Id: acme-production"const url = new URL(
"https://integrations.revenexx.com/api/v1/workflows"
);
const headers = {
"Authorization": "Bearer {ZITADEL_JWT}",
"Content-Type": "application/json",
"Accept": "application/json",
"X-Tenant-Id": "acme-production",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200, Success):
{
"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"
}
]
}
Example response (401, Missing or invalid token):
{
"message": "Unauthenticated."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of this API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Create a workflow
requires authentication
Persists a new workflow under the current tenant. The name must be
unique within the tenant. The blob is validated against the schema
registered for the supplied blob_definition_version.
Example request:
curl --request POST \
"https://integrations.revenexx.com/api/v1/workflows" \
--header "Authorization: Bearer {ZITADEL_JWT}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "X-Tenant-Id: acme-production" \
--data "{
\"name\": \"Sync orders nightly\",
\"description\": \"Pulls orders from the upstream API every night at 02:00 UTC.\",
\"blob_definition_version\": \"v0-draft\",
\"blob\": {
\"nodes\": [],
\"edges\": []
},
\"active\": true,
\"execution_mode\": \"async_only\",
\"triggers\": [
{
\"handle\": \"6ff8f7f6-1eb3-3525-be4a-3932c805afed\",
\"type\": \"architecto\",
\"name\": \"architecto\",
\"active\": true
}
]
}"
const url = new URL(
"https://integrations.revenexx.com/api/v1/workflows"
);
const headers = {
"Authorization": "Bearer {ZITADEL_JWT}",
"Content-Type": "application/json",
"Accept": "application/json",
"X-Tenant-Id": "acme-production",
};
let body = {
"name": "Sync orders nightly",
"description": "Pulls orders from the upstream API every night at 02:00 UTC.",
"blob_definition_version": "v0-draft",
"blob": {
"nodes": [],
"edges": []
},
"active": true,
"execution_mode": "async_only",
"triggers": [
{
"handle": "6ff8f7f6-1eb3-3525-be4a-3932c805afed",
"type": "architecto",
"name": "architecto",
"active": true
}
]
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (201, Created):
{
"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"
}
Example response (422, Validation failed):
{
"message": "The given data was invalid.",
"errors": {
"blob_definition_version": [
"..."
]
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of this API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Show a workflow
requires authentication
Returns a single workflow by id within the current tenant.
Example request:
curl --request GET \
--get "https://integrations.revenexx.com/api/v1/workflows/1" \
--header "Authorization: Bearer {ZITADEL_JWT}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "X-Tenant-Id: acme-production"const url = new URL(
"https://integrations.revenexx.com/api/v1/workflows/1"
);
const headers = {
"Authorization": "Bearer {ZITADEL_JWT}",
"Content-Type": "application/json",
"Accept": "application/json",
"X-Tenant-Id": "acme-production",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200, Success):
{
"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"
}
Example response (404, Not found):
{
"message": "Not found."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of this API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Replace a workflow
requires authentication
Performs a full-replace update of the workflow with the given id. All
domain fields are required. The revision counter is incremented
exactly when the supplied blob differs from the stored one, in which
case the previous revision is snapshotted into the workflow history.
Example request:
curl --request PUT \
"https://integrations.revenexx.com/api/v1/workflows/1" \
--header "Authorization: Bearer {ZITADEL_JWT}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "X-Tenant-Id: acme-production" \
--data "{
\"name\": \"Sync orders nightly\",
\"description\": \"Pulls orders from the upstream API every night at 02:00 UTC.\",
\"blob_definition_version\": \"v0-draft\",
\"blob\": {
\"nodes\": [],
\"edges\": []
},
\"active\": true,
\"execution_mode\": \"async_only\",
\"triggers\": [
{
\"handle\": \"6ff8f7f6-1eb3-3525-be4a-3932c805afed\",
\"type\": \"architecto\",
\"name\": \"architecto\",
\"active\": false
}
]
}"
const url = new URL(
"https://integrations.revenexx.com/api/v1/workflows/1"
);
const headers = {
"Authorization": "Bearer {ZITADEL_JWT}",
"Content-Type": "application/json",
"Accept": "application/json",
"X-Tenant-Id": "acme-production",
};
let body = {
"name": "Sync orders nightly",
"description": "Pulls orders from the upstream API every night at 02:00 UTC.",
"blob_definition_version": "v0-draft",
"blob": {
"nodes": [],
"edges": []
},
"active": true,
"execution_mode": "async_only",
"triggers": [
{
"handle": "6ff8f7f6-1eb3-3525-be4a-3932c805afed",
"type": "architecto",
"name": "architecto",
"active": false
}
]
};
fetch(url, {
method: "PUT",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (200, Updated):
{
"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"
}
Example response (404, Not found):
{
"message": "Not found."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of this API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Delete a workflow
requires authentication
Removes the workflow identified by {id} for the current tenant.
Associated history rows are removed via cascade.
Example request:
curl --request DELETE \
"https://integrations.revenexx.com/api/v1/workflows/1" \
--header "Authorization: Bearer {ZITADEL_JWT}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "X-Tenant-Id: acme-production"const url = new URL(
"https://integrations.revenexx.com/api/v1/workflows/1"
);
const headers = {
"Authorization": "Bearer {ZITADEL_JWT}",
"Content-Type": "application/json",
"Accept": "application/json",
"X-Tenant-Id": "acme-production",
};
fetch(url, {
method: "DELETE",
headers,
}).then(response => response.json());Example response (204, Deleted):
Empty response
Example response (404, Not found):
{
"message": "Not found."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of this API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.