MENU navbar-image

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
    }
}
 

Request      

GET api/v1/audit-logs

Headers

Authorization        

Example: Bearer {ZITADEL_JWT}

Content-Type        

Example: application/json

Accept        

Example: application/json

X-Tenant-Id        

Example: acme-production

Query Parameters

sub   string  optional    

optional Filter by acting user subject. Example: 289347298347

resource_type   string  optional    

optional Filter by resource type (credential, secret, workflow, trigger, workflow_run). Example: workflow

action   string  optional    

optional Filter by action (create, update, delete, run.started, run.finished, run.failed). Example: create

limit   integer  optional    

optional Page size (1–100, default 50). Example: 50

cursor   string  optional    

optional Opaque pagination cursor from a previous response. Example: eyJpZCI6NDJ9

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."
}
 

Request      

GET api/v1/me

Headers

Authorization        

Example: Bearer {ZITADEL_JWT}

Content-Type        

Example: application/json

Accept        

Example: application/json

X-Tenant-Id        

Example: acme-production

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": []
        }
    ]
}
 

Request      

GET api/v1/credential-types

Headers

Authorization        

Example: Bearer {ZITADEL_JWT}

Content-Type        

Example: application/json

Accept        

Example: application/json

X-Tenant-Id        

Example: acme-production

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."
}
 

Request      

GET api/v1/credential-types/{slug}

Headers

Authorization        

Example: Bearer {ZITADEL_JWT}

Content-Type        

Example: application/json

Accept        

Example: application/json

X-Tenant-Id        

Example: acme-production

URL Parameters

slug   string     

Namespaced credential type slug. Example: revenexx:smtp

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."
}
 

Request      

GET api/v1/credentials/oauth/callback

Headers

Content-Type        

Example: application/json

Accept        

Example: application/json

X-Tenant-Id        

Example: acme-production

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."
}
 

Request      

GET api/v1/credentials

Headers

Authorization        

Example: Bearer {ZITADEL_JWT}

Content-Type        

Example: application/json

Accept        

Example: application/json

X-Tenant-Id        

Example: acme-production

Query Parameters

type   string  optional    

Filter by credential type slug. Example: revenexx:smtp

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": [
            "..."
        ]
    }
}
 

Request      

POST api/v1/credentials

Headers

Authorization        

Example: Bearer {ZITADEL_JWT}

Content-Type        

Example: application/json

Accept        

Example: application/json

X-Tenant-Id        

Example: acme-production

Body Parameters

credential_type_slug   string     

Slug of a registered credential type the instance is created for. The slug of an existing record in the credential_types table. Example: revenexx:smtp

name   string     

Human-readable label, unique per tenant. Must not be greater than 191 characters. Example: Mailpit

config   object     

Connection data for the credential type. The accepted fields are defined by the type manifest; stored encrypted and never returned.

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
}
 

Request      

POST api/v1/credentials/test

Headers

Authorization        

Example: Bearer {ZITADEL_JWT}

Content-Type        

Example: application/json

Accept        

Example: application/json

X-Tenant-Id        

Example: acme-production

Body Parameters

credential_type_slug   string     

Slug of the credential type to test the inline config against. The slug of an existing record in the credential_types table. Example: revenexx:smtp

config   object     

Inline connection data to exercise the type's connection test, before any instance is persisted.

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."
}
 

Request      

GET api/v1/credentials/{id}

Headers

Authorization        

Example: Bearer {ZITADEL_JWT}

Content-Type        

Example: application/json

Accept        

Example: application/json

X-Tenant-Id        

Example: acme-production

URL Parameters

id   string     

The ID of the credential. Example: 019f124d-b287-731d-8879-de2bf1fa6924

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": [
            "..."
        ]
    }
}
 

Request      

PATCH api/v1/credentials/{id}

Headers

Authorization        

Example: Bearer {ZITADEL_JWT}

Content-Type        

Example: application/json

Accept        

Example: application/json

X-Tenant-Id        

Example: acme-production

URL Parameters

id   string     

The ID of the credential. Example: 019f124d-b287-731d-8879-de2bf1fa6924

Body Parameters

name   string  optional    

New human-readable label, unique per tenant. Optional. Must not be greater than 191 characters. Example: Mailpit (staging)

config   object  optional    

Replacement connection data, re-validated against the credential type manifest. Optional; stored encrypted and never returned.

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."
}
 

Request      

DELETE api/v1/credentials/{id}

Headers

Authorization        

Example: Bearer {ZITADEL_JWT}

Content-Type        

Example: application/json

Accept        

Example: application/json

X-Tenant-Id        

Example: acme-production

URL Parameters

id   string     

The ID of the credential. Example: 019f124d-b287-731d-8879-de2bf1fa6924

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
}
 

Request      

POST api/v1/credentials/{id}/test

Headers

Authorization        

Example: Bearer {ZITADEL_JWT}

Content-Type        

Example: application/json

Accept        

Example: application/json

X-Tenant-Id        

Example: acme-production

URL Parameters

id   string     

The ID of the credential. Example: 019f124d-b287-731d-8879-de2bf1fa6924

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.

Example request:
curl --request POST \
    "https://integrations.revenexx.com/api/v1/credentials/019f124d-b287-731d-8879-de2bf1fa6924/oauth/authorize-url" \
    --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/oauth/authorize-url"
);

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, Authorize URL):


{
    "authorize_url": "https://login.example.com/authorize?client_id=...&state=..."
}
 

Example response (422, Not a 3-legged OAuth type):


{
    "message": "Credential type does not use 3-legged OAuth."
}
 

Request      

POST api/v1/credentials/{id}/oauth/authorize-url

Headers

Authorization        

Example: Bearer {ZITADEL_JWT}

Content-Type        

Example: application/json

Accept        

Example: application/json

X-Tenant-Id        

Example: acme-production

URL Parameters

id   string     

The ID of the credential. Example: 019f124d-b287-731d-8879-de2bf1fa6924

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"
}
 

Request      

GET api/v1/node-packages/images/{id}

Headers

Authorization        

Example: Bearer {ZITADEL_JWT}

Content-Type        

Example: application/json

Accept        

Example: application/json

X-Tenant-Id        

Example: acme-production

URL Parameters

id   string     

The ID of the image. Example: architecto

image   string     

The image UUID. Example: 9b2e6b1e-6d0a-5f3a-8c1b-2b7f6a1c9d4e

Query Parameters

expires   integer     

Signed-URL expiry (added by the signer). Example: 16

signature   string     

URL signature (added by the signer). Example: architecto

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."
}
 

Request      

GET api/v1/nodes

Headers

Authorization        

Example: Bearer {ZITADEL_JWT}

Content-Type        

Example: application/json

Accept        

Example: application/json

X-Tenant-Id        

Example: acme-production

Query Parameters

namespace   string  optional    

Filter by the slug-derived namespace (e.g. revenexx). Example: revenexx

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."
}
 

Request      

GET api/v1/nodes/{slug}/versions

Headers

Authorization        

Example: Bearer {ZITADEL_JWT}

Content-Type        

Example: application/json

Accept        

Example: application/json

X-Tenant-Id        

Example: acme-production

URL Parameters

slug   string     

Full node slug. Example: revenexx:http-request

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."
}
 

Request      

GET api/v1/nodes/{slug}/{version}

Headers

Authorization        

Example: Bearer {ZITADEL_JWT}

Content-Type        

Example: application/json

Accept        

Example: application/json

X-Tenant-Id        

Example: acme-production

URL Parameters

slug   string     

Full node slug. Example: revenexx:http-request

version   string     

Semver, or the alias latest. Example: 1.0.0

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: ..."
}
 

Request      

POST api/v1/nodes/{slug}/{version}/config:resolve

Headers

Authorization        

Example: Bearer {ZITADEL_JWT}

Content-Type        

Example: application/json

Accept        

Example: application/json

X-Tenant-Id        

Example: acme-production

URL Parameters

slug   string     

Full node slug. Example: revenexx:api

version   string     

Semver, or the alias latest. Example: 1.0.0

Body Parameters

target   string     

"outputs", "" (all), or a config field key. Example: ``

config   object  optional    

The user's current partial config values.

locale   string  optional    

Preferred locale for resolved labels. Example: de

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."
}
 

Request      

DELETE api/v1/nodes/{slug}/{version}

Headers

Authorization        

Example: Bearer {ZITADEL_JWT}

Content-Type        

Example: application/json

Accept        

Example: application/json

X-Tenant-Id        

Example: acme-production

URL Parameters

slug   string     

Full node slug. Example: revenexx:http-request

version   string     

Exact semver of the node version to delete; the alias latest is rejected. Example: 1.0.0

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."
}
 

Request      

GET api/v1/schemas/{domain}

Headers

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

domain   string     

The schema domain. Supported domains: workflow, node. Example: workflow

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."
}
 

Request      

GET api/v1/schemas/{domain}/{version}

Headers

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

domain   string     

The schema domain. Example: workflow

version   string     

The schema version identifier. Example: v0-draft

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."
}
 

Request      

GET api/v1/templates

Headers

Authorization        

Example: Bearer {ZITADEL_JWT}

Content-Type        

Example: application/json

Accept        

Example: application/json

X-Tenant-Id        

Example: acme-production

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."
}
 

Request      

GET api/v1/templates/{slug}

Headers

Authorization        

Example: Bearer {ZITADEL_JWT}

Content-Type        

Example: application/json

Accept        

Example: application/json

X-Tenant-Id        

Example: acme-production

URL Parameters

slug   string     

Namespaced template slug. Example: revenexx:slack-to-crm

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."
}
 

Request      

GET api/v1/templates/{slug}/requirements

Headers

Authorization        

Example: Bearer {ZITADEL_JWT}

Content-Type        

Example: application/json

Accept        

Example: application/json

X-Tenant-Id        

Example: acme-production

URL Parameters

slug   string     

Namespaced template slug. Example: revenexx:slack-to-crm

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."
        ]
    }
}
 

Request      

POST api/v1/templates/{slug}/instantiate

Headers

Authorization        

Example: Bearer {ZITADEL_JWT}

Content-Type        

Example: application/json

Accept        

Example: application/json

X-Tenant-Id        

Example: acme-production

URL Parameters

slug   string     

Namespaced template slug. Example: revenexx:slack-to-crm

Body Parameters

name   string  optional    

Optional workflow name override; defaults to the template name. Must not be greater than 255 characters. Example: My Slack flow

credential_bindings   string[]  optional    

Must be a valid UUID.

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."
}
 

Request      

GET api/v1/secrets

Headers

Authorization        

Example: Bearer {ZITADEL_JWT}

Content-Type        

Example: application/json

Accept        

Example: application/json

X-Tenant-Id        

Example: acme-production

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": [
            "..."
        ]
    }
}
 

Request      

POST api/v1/secrets

Headers

Authorization        

Example: Bearer {ZITADEL_JWT}

Content-Type        

Example: application/json

Accept        

Example: application/json

X-Tenant-Id        

Example: acme-production

Body Parameters

key   string     

Env-style key, must match ^[A-Z0-9_]+$. Example: STRIPE_API_KEY

value   string     

The secret value. Example: sk_live_abc123

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": [
            "..."
        ]
    }
}
 

Request      

PATCH api/v1/secrets/{key}

Headers

Authorization        

Example: Bearer {ZITADEL_JWT}

Content-Type        

Example: application/json

Accept        

Example: application/json

X-Tenant-Id        

Example: acme-production

URL Parameters

key   string     

The secret key to update. Example: bc-client-secret

Body Parameters

value   string     

The new secret value. Example: sk_live_new_value

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."
}
 

Request      

DELETE api/v1/secrets/{key}

Headers

Authorization        

Example: Bearer {ZITADEL_JWT}

Content-Type        

Example: application/json

Accept        

Example: application/json

X-Tenant-Id        

Example: acme-production

URL Parameters

key   string     

The secret key to delete. Example: STRIPE_API_KEY

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"
        }
    ]
}
 

Request      

GET api/v1/workflows/{workflowId}/triggers

Headers

Authorization        

Example: Bearer {ZITADEL_JWT}

Content-Type        

Example: application/json

Accept        

Example: application/json

X-Tenant-Id        

Example: acme-production

URL Parameters

workflowId   integer     

The workflow id. Example: 1

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."
        ]
    }
}
 

Request      

POST api/v1/workflows/{workflowId}/triggers

Headers

Authorization        

Example: Bearer {ZITADEL_JWT}

Content-Type        

Example: application/json

Accept        

Example: application/json

X-Tenant-Id        

Example: acme-production

URL Parameters

workflowId   integer     

The workflow id. Example: 1

Body Parameters

handle   string     

Stable UUID referenced by the workflow blob edges. Must be unique per tenant. Must be a valid UUID. Example: 6ff8f7f6-1eb3-3525-be4a-3932c805afed

type   string     

Trigger entry-point type. Example: webhook

Must be one of:
  • manual
  • schedule
  • webhook
  • event
name   string  optional    

Optional human-readable label. Example: PSP webhook

active   boolean  optional    

Whether the trigger is enabled. Defaults to true. Example: true

config   object  optional    

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.

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."
        ]
    }
}
 

Request      

PUT api/v1/workflows/{workflowId}/triggers/{triggerId}

Headers

Authorization        

Example: Bearer {ZITADEL_JWT}

Content-Type        

Example: application/json

Accept        

Example: application/json

X-Tenant-Id        

Example: acme-production

URL Parameters

workflowId   integer     

The workflow id. Example: 1

triggerId   integer     

The trigger id. Example: 1

Body Parameters

type   string     

Trigger entry-point type. Example: webhook

Must be one of:
  • manual
  • schedule
  • webhook
  • event
name   string  optional    

Optional human-readable label. Example: PSP webhook

active   boolean     

Whether the trigger is enabled. Example: true

config   object  optional    

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.

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
 

Request      

DELETE api/v1/workflows/{workflowId}/triggers/{triggerId}

Headers

Authorization        

Example: Bearer {ZITADEL_JWT}

Content-Type        

Example: application/json

Accept        

Example: application/json

X-Tenant-Id        

Example: acme-production

URL Parameters

workflowId   integer     

The workflow id. Example: 1

triggerId   integer     

The trigger id. Example: 1

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)."
}
 

Request      

GET api/v1/webhooks/{handle}

POST api/v1/webhooks/{handle}

PUT api/v1/webhooks/{handle}

PATCH api/v1/webhooks/{handle}

DELETE api/v1/webhooks/{handle}

Headers

Authorization        

Example: Bearer {ZITADEL_JWT}

Content-Type        

Example: application/json

Accept        

Example: application/json

X-Tenant-Id        

Example: acme-production

URL Parameters

handle   string     

The webhook trigger handle (UUID). Example: 0190a9c0-1111-7000-8000-000000000000

Query Parameters

mode   string  optional    

optional Force sync or async. Honored for caller_decides workflows; conflicting with async_only/sync_only yields 422. Example: async

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"
    ]
}
 

Request      

GET api/v1/workflows/used-credentials

Headers

Authorization        

Example: Bearer {ZITADEL_JWT}

Content-Type        

Example: application/json

Accept        

Example: application/json

X-Tenant-Id        

Example: acme-production

Query Parameters

type   string  optional    

Filter to a single credential type slug. Example: revenexx:smtp

active   boolean  optional    

Only consider active workflows. Example: true

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"
    ]
}
 

Request      

GET api/v1/workflows/used-credential-types

Headers

Authorization        

Example: Bearer {ZITADEL_JWT}

Content-Type        

Example: application/json

Accept        

Example: application/json

X-Tenant-Id        

Example: acme-production

Query Parameters

active   boolean  optional    

Only consider active workflows. Example: true

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."
}
 

Request      

GET api/v1/workflows/{workflowId}/credentials

Headers

Authorization        

Example: Bearer {ZITADEL_JWT}

Content-Type        

Example: application/json

Accept        

Example: application/json

X-Tenant-Id        

Example: acme-production

URL Parameters

workflowId   integer     

The workflow id. Example: 1

Query Parameters

type   string  optional    

Filter to a single credential type slug. Example: revenexx:smtp

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."
}
 

Request      

GET api/v1/workflows/{workflowId}/credential-types

Headers

Authorization        

Example: Bearer {ZITADEL_JWT}

Content-Type        

Example: application/json

Accept        

Example: application/json

X-Tenant-Id        

Example: acme-production

URL Parameters

workflowId   integer     

The workflow id. Example: 1

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."
}
 

Request      

GET api/v1/workflows/{workflowId}/revisions

Headers

Authorization        

Example: Bearer {ZITADEL_JWT}

Content-Type        

Example: application/json

Accept        

Example: application/json

X-Tenant-Id        

Example: acme-production

URL Parameters

workflowId   integer     

The workflow id. Example: 1

Query Parameters

page   integer  optional    

Page number to retrieve (1-based). Defaults to 1. Must be at least 1. Example: 1

per_page   integer  optional    

Number of revisions per page (1–100). Defaults to 25. Must be at least 1. Must not be greater than 100. Example: 25

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."
}
 

Request      

GET api/v1/workflows/{workflowId}/revisions/{revision}

Headers

Authorization        

Example: Bearer {ZITADEL_JWT}

Content-Type        

Example: application/json

Accept        

Example: application/json

X-Tenant-Id        

Example: acme-production

URL Parameters

workflowId   integer     

The workflow id. Example: 1

revision   integer     

The archived revision number. Example: 1

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."
}
 

Request      

POST api/v1/workflows/{workflowId}/revisions/{revision}/restore

Headers

Authorization        

Example: Bearer {ZITADEL_JWT}

Content-Type        

Example: application/json

Accept        

Example: application/json

X-Tenant-Id        

Example: acme-production

URL Parameters

workflowId   integer     

The workflow id. Example: 1

revision   integer     

The archived revision number to restore. Example: 1

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
    }
}
 

Request      

GET api/v1/workflows/{workflowId}/runs

Headers

Authorization        

Example: Bearer {ZITADEL_JWT}

Content-Type        

Example: application/json

Accept        

Example: application/json

X-Tenant-Id        

Example: acme-production

URL Parameters

workflowId   integer     

The workflow id. Example: 1

Query Parameters

page   integer  optional    

Page number to retrieve (1-based). Defaults to 1. Must be at least 1. Example: 1

per_page   integer  optional    

Number of runs per page (1–100). Defaults to 25. Must be at least 1. Must not be greater than 100. Example: 25

Start a workflow run

requires authentication

Execution behavior depends on workflow execution_mode and optional request mode:

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."
}
 

Request      

POST api/v1/workflows/{workflowId}/runs

Headers

Authorization        

Example: Bearer {ZITADEL_JWT}

Content-Type        

Example: application/json

Accept        

Example: application/json

X-Tenant-Id        

Example: acme-production

URL Parameters

workflowId   integer     

The workflow id. Example: 1

Body Parameters

trigger_payload   object  optional    

optional Arbitrary trigger payload forwarded to the workflow.

trigger_handle   string  optional    

UUID handle of the trigger to run as. Optional; defaults to the workflow's manual trigger. Must be a valid UUID. Example: 6ff8f7f6-1eb3-3525-be4a-3932c805afed

mode   string  optional    

optional Requested run mode. Allowed: sync, async. Resolution depends on workflow execution_mode policy. Example: sync

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."
}
 

Request      

GET api/v1/workflows/{workflowId}/runs/{runId}

Headers

Authorization        

Example: Bearer {ZITADEL_JWT}

Content-Type        

Example: application/json

Accept        

Example: application/json

X-Tenant-Id        

Example: acme-production

URL Parameters

workflowId   integer     

The workflow id. Example: 1

runId   integer     

The run id. Example: 1

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."
}
 

Request      

GET api/v1/workflows/{workflowId}/runs/{runId}/details

Headers

Authorization        

Example: Bearer {ZITADEL_JWT}

Content-Type        

Example: application/json

Accept        

Example: application/json

X-Tenant-Id        

Example: acme-production

URL Parameters

workflowId   integer     

The workflow id. Example: 1

runId   integer     

The run id. Example: 1

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."
}
 

Request      

GET api/v1/workflows/{workflowId}/runs/{runId}/history

Headers

Authorization        

Example: Bearer {ZITADEL_JWT}

Content-Type        

Example: application/json

Accept        

Example: application/json

X-Tenant-Id        

Example: acme-production

URL Parameters

workflowId   integer     

The workflow id. Example: 1

runId   integer     

The run id. Example: 1

Query Parameters

page_token   string  optional    

Opaque continuation token returned by the previous page. Omit for the first page. Must not be greater than 8192 characters.

page_size   integer  optional    

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. Example: 200

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."
}
 

Request      

GET api/v1/workflows/{workflowId}/runs/{runId}/stack-trace

Headers

Authorization        

Example: Bearer {ZITADEL_JWT}

Content-Type        

Example: application/json

Accept        

Example: application/json

X-Tenant-Id        

Example: acme-production

URL Parameters

workflowId   integer     

The workflow id. Example: 1

runId   integer     

The run id. Example: 1

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."
}
 

Request      

GET api/v1/workflows

Headers

Authorization        

Example: Bearer {ZITADEL_JWT}

Content-Type        

Example: application/json

Accept        

Example: application/json

X-Tenant-Id        

Example: acme-production

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": [
            "..."
        ]
    }
}
 

Request      

POST api/v1/workflows

Headers

Authorization        

Example: Bearer {ZITADEL_JWT}

Content-Type        

Example: application/json

Accept        

Example: application/json

X-Tenant-Id        

Example: acme-production

Body Parameters

name   string     

Human-readable workflow name (unique per tenant). Must not be greater than 255 characters. Example: Sync orders nightly

description   string  optional    

Optional free-text description. Example: Pulls orders from the upstream API every night at 02:00 UTC.

blob_definition_version   string     

Identifier of the blob schema version. See GET /v1/schemas/workflow. Example: v0-draft

Must be one of:
  • v0-draft
blob   object  optional    

The workflow definition payload. Must match the schema for the supplied version.

active   boolean  optional    

Whether the workflow is active. Defaults to true when omitted. Example: true

execution_mode   string  optional    

Execution policy for run mode resolution. One of: async_only, sync_only, caller_decides. Defaults to async_only. Example: async_only

Must be one of:
  • async_only
  • sync_only
  • caller_decides
triggers   object[]  optional    
handle   string  optional    

This field is required when triggers is present. Must be a valid UUID. Example: 6ff8f7f6-1eb3-3525-be4a-3932c805afed

type   string  optional    

This field is required when triggers is present. Example: architecto

Must be one of:
  • manual
  • schedule
  • webhook
  • event
name   string  optional    

Example: architecto

config   object  optional    
active   boolean  optional    

Example: true

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."
}
 

Request      

GET api/v1/workflows/{id}

Headers

Authorization        

Example: Bearer {ZITADEL_JWT}

Content-Type        

Example: application/json

Accept        

Example: application/json

X-Tenant-Id        

Example: acme-production

URL Parameters

id   integer     

The workflow id. Example: 1

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."
}
 

Request      

PUT api/v1/workflows/{id}

Headers

Authorization        

Example: Bearer {ZITADEL_JWT}

Content-Type        

Example: application/json

Accept        

Example: application/json

X-Tenant-Id        

Example: acme-production

URL Parameters

id   integer     

The workflow id. Example: 1

Body Parameters

name   string     

Human-readable workflow name (unique per tenant). Must not be greater than 255 characters. Example: Sync orders nightly

description   string  optional    

Optional free-text description. Example: Pulls orders from the upstream API every night at 02:00 UTC.

blob_definition_version   string     

Identifier of the blob schema version. See GET /v1/schemas/workflow. Example: v0-draft

Must be one of:
  • v0-draft
blob   object  optional    

The workflow definition payload. Must match the schema for the supplied version.

active   boolean     

Whether the workflow is active. Example: true

execution_mode   string     

Execution policy for run mode resolution. One of: async_only, sync_only, caller_decides. Example: async_only

Must be one of:
  • async_only
  • sync_only
  • caller_decides
triggers   object[]  optional    
handle   string  optional    

This field is required when triggers is present. Must be a valid UUID. Example: 6ff8f7f6-1eb3-3525-be4a-3932c805afed

type   string  optional    

This field is required when triggers is present. Example: architecto

Must be one of:
  • manual
  • schedule
  • webhook
  • event
name   string  optional    

Example: architecto

config   object  optional    
active   boolean  optional    

Example: false

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."
}
 

Request      

DELETE api/v1/workflows/{id}

Headers

Authorization        

Example: Bearer {ZITADEL_JWT}

Content-Type        

Example: application/json

Accept        

Example: application/json

X-Tenant-Id        

Example: acme-production

URL Parameters

id   integer     

The workflow id. Example: 1