{ "openapi": "3.1.0", "info": { "title": "Boom API", "version": "1.0.0", "description": "Boom's public REST API — one uniform surface over every platform capability. CDP: upsert people and custom objects, define object and relationship types, link and unlink relationships, and record behavioral events — one record per request or up to 1000 per request via the `/batch` endpoints. Segments: read (list, read, membership) and full authoring — discover the filterable catalog, validate a filter, create and update segments, preview match counts, and trigger evaluation. Initiatives: create and configure outreach initiatives, link WhatsApp templates, drive the lifecycle (launch, cancel, archive), and read collected-data summaries. Participants: enroll people into an active initiative, track their status, read conversation transcripts, and stop outreach. Journeys: read-only access to always-on message flows and their metrics. WhatsApp templates: list your WhatsApp numbers and list, read, and create message templates. The same capabilities are exposed as MCP tools with identical schemas." }, "servers": [ { "url": "https://www.useboom.ai", "description": "Production" }, { "url": "https://dev.useboom.ai", "description": "Development (sandbox — use a development organization API key)" } ], "security": [ { "bearerAuth": [] } ], "paths": { "/api/v1/cdp/custom-objects": { "get": { "operationId": "cdp_custom_objects_list", "summary": "List objects", "description": "List custom objects of one type, newest first.", "tags": [ "CDP Custom Objects" ], "parameters": [ { "name": "type", "in": "query", "required": true, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "minLength": 1, "maxLength": 255, "description": "The custom object type name to list." } }, { "name": "limit", "in": "query", "required": false, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "description": "Max items to return, 1-1000 (default 100).", "type": "integer", "minimum": 1, "maximum": 1000 } }, { "name": "cursor", "in": "query", "required": false, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "description": "Opaque pagination token from a previous response's `next_cursor`. Omit for the first page.", "type": "string" } } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "data": { "type": "array", "items": { "type": "object", "properties": { "type": { "type": "string", "description": "The custom object type name." }, "externalId": { "type": "string", "description": "Your stable identifier for this object within its type." }, "displayName": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "attributes": { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": {}, "description": "Free-form custom traits." }, "createdAt": { "type": "string", "description": "ISO 8601 timestamp." }, "updatedAt": { "type": "string", "description": "ISO 8601 timestamp." } }, "required": [ "type", "externalId", "displayName", "attributes", "createdAt", "updatedAt" ], "additionalProperties": false } }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "required": [ "data", "next_cursor" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } }, "post": { "operationId": "cdp_custom_objects_upsert", "summary": "Upsert object", "description": "Create or update a custom object by type and external id. The type must already exist; free-form attributes are fully replaced.", "tags": [ "CDP Custom Objects" ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "type": { "type": "string", "minLength": 1, "maxLength": 255, "description": "The custom object type name. Must already exist (create it with the types endpoint) — unknown types are rejected." }, "externalId": { "type": "string", "minLength": 1, "maxLength": 255, "description": "Your stable identifier for this object within its type (idempotency key)." }, "displayName": { "description": "Human-readable label for the object.", "type": "string", "minLength": 1, "maxLength": 255 }, "attributes": { "description": "Free-form custom traits (full-replace on upsert).", "type": "object", "propertyNames": { "type": "string", "maxLength": 255 }, "additionalProperties": {} } }, "required": [ "type", "externalId" ] } } } }, "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "type": { "type": "string" }, "externalId": { "type": "string" }, "created": { "type": "boolean" } }, "required": [ "type", "externalId", "created" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } } }, "/api/v1/cdp/custom-objects/{type}/{externalId}": { "delete": { "operationId": "cdp_custom_objects_delete", "summary": "Delete object", "description": "Soft-delete a custom object and its links. Idempotent.", "tags": [ "CDP Custom Objects" ], "parameters": [ { "name": "type", "in": "path", "required": true, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "minLength": 1, "maxLength": 255, "description": "The custom object type name." } }, { "name": "externalId", "in": "path", "required": true, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "minLength": 1, "maxLength": 255, "description": "The object externalId within its type." } } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "removed": { "type": "boolean" } }, "required": [ "removed" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } }, "get": { "operationId": "cdp_custom_objects_get", "summary": "Get object", "description": "Read one custom object by type and external id.", "tags": [ "CDP Custom Objects" ], "parameters": [ { "name": "type", "in": "path", "required": true, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "minLength": 1, "maxLength": 255, "description": "The custom object type name." } }, { "name": "externalId", "in": "path", "required": true, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "minLength": 1, "maxLength": 255, "description": "The object externalId within its type." } } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "type": { "type": "string", "description": "The custom object type name." }, "externalId": { "type": "string", "description": "Your stable identifier for this object within its type." }, "displayName": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "attributes": { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": {}, "description": "Free-form custom traits." }, "createdAt": { "type": "string", "description": "ISO 8601 timestamp." }, "updatedAt": { "type": "string", "description": "ISO 8601 timestamp." } }, "required": [ "type", "externalId", "displayName", "attributes", "createdAt", "updatedAt" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } } }, "/api/v1/cdp/custom-objects/batch": { "post": { "operationId": "cdp_custom_objects_batch_upsert", "summary": "Batch upsert objects", "description": "Upsert up to 1000 custom objects in one request. Idempotent and safely retryable.", "tags": [ "CDP Custom Objects" ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "items": { "minItems": 1, "maxItems": 1000, "type": "array", "items": { "type": "object", "properties": { "type": { "type": "string", "minLength": 1, "maxLength": 255, "description": "The custom object type name. Must already exist (create it with the types endpoint) — unknown types are rejected." }, "externalId": { "type": "string", "minLength": 1, "maxLength": 255, "description": "Your stable identifier for this object within its type (idempotency key)." }, "displayName": { "description": "Human-readable label for the object.", "type": "string", "minLength": 1, "maxLength": 255 }, "attributes": { "description": "Free-form custom traits (full-replace on upsert).", "type": "object", "propertyNames": { "type": "string", "maxLength": 255 }, "additionalProperties": {} } }, "required": [ "type", "externalId" ] }, "description": "Custom objects to upsert." } }, "required": [ "items" ] } } } }, "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "summary": { "type": "object", "properties": { "total": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "created": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "updated": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "failed": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 } }, "required": [ "total", "created", "updated", "failed" ], "additionalProperties": false }, "errors": { "type": "array", "items": { "type": "object", "properties": { "index": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Zero-based index of the failed item." }, "externalId": { "type": "string" }, "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ], "additionalProperties": false } }, "required": [ "index", "error" ], "additionalProperties": false } } }, "required": [ "summary", "errors" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } } }, "/api/v1/cdp/custom-objects/types": { "get": { "operationId": "cdp_custom_object_types_list", "summary": "List object types", "description": "List the organization's custom object types.", "tags": [ "CDP Custom Objects" ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "data": { "type": "array", "items": { "type": "object", "properties": { "name": { "type": "string", "description": "Unique machine name for the type." }, "displayName": { "type": "string" }, "description": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "required": [ "name", "displayName", "description" ], "additionalProperties": false } }, "next_cursor": { "type": "null" } }, "required": [ "data", "next_cursor" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } }, "post": { "operationId": "cdp_custom_object_types_create", "summary": "Create object type", "description": "Create a custom object type — required before you can upsert objects of that kind.", "tags": [ "CDP Custom Objects" ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "name": { "type": "string", "minLength": 1, "maxLength": 255, "description": "Unique machine name for the type (e.g. \"order\")." }, "displayName": { "type": "string", "minLength": 1, "maxLength": 255, "description": "Human-readable label for the type." }, "description": { "description": "Optional description of what this type represents.", "type": "string", "minLength": 1, "maxLength": 1000 } }, "required": [ "name", "displayName" ] } } } }, "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "name": { "type": "string", "description": "Unique machine name for the type." }, "displayName": { "type": "string" }, "description": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "created": { "type": "boolean" } }, "required": [ "name", "displayName", "description", "created" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } } }, "/api/v1/cdp/custom-objects/types/{type}": { "get": { "operationId": "cdp_custom_object_types_get", "summary": "Get object type", "description": "Read one custom object type by name.", "tags": [ "CDP Custom Objects" ], "parameters": [ { "name": "type", "in": "path", "required": true, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "minLength": 1, "maxLength": 255, "description": "The custom object type name." } } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "name": { "type": "string", "description": "Unique machine name for the type." }, "displayName": { "type": "string" }, "description": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "required": [ "name", "displayName", "description" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } } }, "/api/v1/cdp/events": { "get": { "operationId": "cdp_events_list", "summary": "List events", "description": "List events, newest first, with optional filters by name, subject, and time range.", "tags": [ "CDP Events" ], "parameters": [ { "name": "name", "in": "query", "required": false, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "description": "Filter by exact event name.", "type": "string", "minLength": 1 } }, { "name": "personExternalId", "in": "query", "required": false, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "description": "Filter to events whose subject is this person externalId.", "type": "string", "minLength": 1 } }, { "name": "customObjectType", "in": "query", "required": false, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "description": "Filter by custom-object type name.", "type": "string", "minLength": 1 } }, { "name": "customObjectExternalId", "in": "query", "required": false, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "description": "Filter by custom-object externalId.", "type": "string", "minLength": 1 } }, { "name": "start", "in": "query", "required": false, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "description": "Inclusive lower bound on event timestamp, ISO 8601.", "type": "string" } }, { "name": "end", "in": "query", "required": false, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "description": "Inclusive upper bound on event timestamp, ISO 8601.", "type": "string" } }, { "name": "limit", "in": "query", "required": false, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "description": "Max items to return, 1-1000 (default 100).", "type": "integer", "minimum": 1, "maximum": 1000 } }, { "name": "cursor", "in": "query", "required": false, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "description": "Opaque pagination token from a previous response's `next_cursor`. Omit for the first page.", "type": "string" } } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "data": { "type": "array", "items": { "type": "object", "properties": { "externalId": { "type": "string", "description": "Your stable identifier for this event (idempotency key)." }, "name": { "type": "string" }, "timestamp": { "type": "string", "description": "When the event occurred, ISO 8601." }, "personExternalId": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "customObjectType": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "customObjectExternalId": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "properties": { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": {}, "description": "Free-form event payload." }, "receivedAt": { "type": "string", "description": "When the event was received, ISO 8601." } }, "required": [ "externalId", "name", "timestamp", "personExternalId", "customObjectType", "customObjectExternalId", "properties", "receivedAt" ], "additionalProperties": false } }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "required": [ "data", "next_cursor" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } }, "post": { "operationId": "cdp_events_record", "summary": "Record event", "description": "Record one behavioral event for a person and/or custom object. This is the real-time path — it triggers journey enrollment. Unknown subjects still ingest and are linked later.", "tags": [ "CDP Events" ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "name": { "type": "string", "minLength": 1, "maxLength": 255, "pattern": "^[a-zA-Z0-9_]+$", "description": "Event name, e.g. \"checkout_completed\". Letters, numbers, underscores only." }, "externalId": { "type": "string", "minLength": 1, "maxLength": 255, "description": "Your stable id for this event (idempotency key). Re-recording returns created: false." }, "timestamp": { "description": "When the event occurred, ISO 8601. Defaults to now if omitted.", "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$" }, "personExternalId": { "description": "Subject: the person externalId this event is about.", "type": "string", "minLength": 1, "maxLength": 255 }, "customObjectType": { "description": "Subject: the custom-object type name. Must be paired with customObjectExternalId.", "type": "string", "minLength": 1, "maxLength": 255 }, "customObjectExternalId": { "description": "Subject: the custom-object externalId. Must be paired with customObjectType.", "type": "string", "minLength": 1, "maxLength": 255 }, "properties": { "description": "Free-form event payload.", "type": "object", "propertyNames": { "type": "string", "maxLength": 255 }, "additionalProperties": {} } }, "required": [ "name", "externalId" ] } } } }, "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "created": { "type": "boolean", "description": "false when the externalId was already recorded (idempotent)." }, "eventId": { "type": "string" }, "personId": { "type": "string" }, "personExternalId": { "type": "string" }, "customObjectType": { "type": "string" }, "customObjectExternalId": { "type": "string" } }, "required": [ "created" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } } }, "/api/v1/cdp/events/{externalId}": { "get": { "operationId": "cdp_events_get", "summary": "Get event", "description": "Read one event by its external id.", "tags": [ "CDP Events" ], "parameters": [ { "name": "externalId", "in": "path", "required": true, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "minLength": 1, "maxLength": 255, "description": "The event externalId, as supplied at record time." } } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "externalId": { "type": "string", "description": "Your stable identifier for this event (idempotency key)." }, "name": { "type": "string" }, "timestamp": { "type": "string", "description": "When the event occurred, ISO 8601." }, "personExternalId": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "customObjectType": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "customObjectExternalId": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "properties": { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": {}, "description": "Free-form event payload." }, "receivedAt": { "type": "string", "description": "When the event was received, ISO 8601." } }, "required": [ "externalId", "name", "timestamp", "personExternalId", "customObjectType", "customObjectExternalId", "properties", "receivedAt" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } } }, "/api/v1/cdp/events/batch": { "post": { "operationId": "cdp_events_batch_record", "summary": "Batch record events", "description": "Ingest up to 1000 events in one request, for bulk or historical loads. Unlike the single endpoint, this does not trigger journey enrollment.", "tags": [ "CDP Events" ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "items": { "minItems": 1, "maxItems": 1000, "type": "array", "items": { "type": "object", "properties": { "name": { "type": "string", "minLength": 1, "maxLength": 255, "pattern": "^[a-zA-Z0-9_]+$", "description": "Event name, e.g. \"checkout_completed\". Letters, numbers, underscores only." }, "externalId": { "type": "string", "minLength": 1, "maxLength": 255, "description": "Your stable id for this event (idempotency key). Re-recording returns created: false." }, "timestamp": { "description": "When the event occurred, ISO 8601. Defaults to now if omitted.", "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$" }, "personExternalId": { "description": "Subject: the person externalId this event is about.", "type": "string", "minLength": 1, "maxLength": 255 }, "customObjectType": { "description": "Subject: the custom-object type name. Must be paired with customObjectExternalId.", "type": "string", "minLength": 1, "maxLength": 255 }, "customObjectExternalId": { "description": "Subject: the custom-object externalId. Must be paired with customObjectType.", "type": "string", "minLength": 1, "maxLength": 255 }, "properties": { "description": "Free-form event payload.", "type": "object", "propertyNames": { "type": "string", "maxLength": 255 }, "additionalProperties": {} } }, "required": [ "name", "externalId" ] }, "description": "Events to record." } }, "required": [ "items" ] } } } }, "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "summary": { "type": "object", "properties": { "total": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "created": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "skipped": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Idempotent duplicates (externalId already recorded)." }, "failed": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 } }, "required": [ "total", "created", "skipped", "failed" ], "additionalProperties": false }, "errors": { "type": "array", "items": { "type": "object", "properties": { "index": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Zero-based index of the failed item." }, "externalId": { "type": "string" }, "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ], "additionalProperties": false } }, "required": [ "index", "error" ], "additionalProperties": false } } }, "required": [ "summary", "errors" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } } }, "/api/v1/cdp/people": { "get": { "operationId": "cdp_people_list", "summary": "List people", "description": "List the organization's people, newest first.", "tags": [ "CDP People" ], "parameters": [ { "name": "limit", "in": "query", "required": false, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "description": "Max items to return, 1-1000 (default 100).", "type": "integer", "minimum": 1, "maximum": 1000 } }, { "name": "cursor", "in": "query", "required": false, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "description": "Opaque pagination token from a previous response's `next_cursor`. Omit for the first page.", "type": "string" } } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "data": { "type": "array", "items": { "type": "object", "properties": { "externalId": { "type": "string", "description": "Your stable identifier for this person." }, "firstName": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "lastName": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "email": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "phoneNumber": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "E.164 format." }, "attributes": { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": {}, "description": "Free-form custom traits." }, "createdAt": { "type": "string", "description": "ISO 8601 timestamp." }, "updatedAt": { "type": "string", "description": "ISO 8601 timestamp." } }, "required": [ "externalId", "firstName", "lastName", "email", "phoneNumber", "attributes", "createdAt", "updatedAt" ], "additionalProperties": false } }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "required": [ "data", "next_cursor" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } }, "post": { "operationId": "cdp_people_upsert", "summary": "Upsert person", "description": "Create or update a person by external id. Free-form attributes are fully replaced on each write.", "tags": [ "CDP People" ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "externalId": { "type": "string", "minLength": 1, "maxLength": 255, "description": "Your stable identifier for this person (idempotency key)." }, "firstName": { "description": "Given name.", "anyOf": [ { "type": "string", "maxLength": 255 }, { "type": "null" } ] }, "lastName": { "description": "Family name.", "anyOf": [ { "type": "string", "maxLength": 255 }, { "type": "null" } ] }, "email": { "description": "Email address.", "anyOf": [ { "type": "string", "maxLength": 255 }, { "type": "null" } ] }, "phoneNumber": { "description": "Phone number in E.164 format (e.g. +5215555555555).", "anyOf": [ { "type": "string", "maxLength": 255 }, { "type": "null" } ] }, "attributes": { "description": "Free-form custom traits (full-replace on upsert).", "type": "object", "propertyNames": { "type": "string", "maxLength": 255 }, "additionalProperties": {} } }, "required": [ "externalId" ] } } } }, "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "externalId": { "type": "string" }, "created": { "type": "boolean" } }, "required": [ "externalId", "created" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } } }, "/api/v1/cdp/people/{externalId}": { "delete": { "operationId": "cdp_people_delete", "summary": "Delete person", "description": "Soft-delete a person and their outgoing links. Idempotent; behavioral events are kept.", "tags": [ "CDP People" ], "parameters": [ { "name": "externalId", "in": "path", "required": true, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "minLength": 1, "maxLength": 255, "description": "The person externalId." } } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "removed": { "type": "boolean" } }, "required": [ "removed" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } }, "get": { "operationId": "cdp_people_get", "summary": "Get person", "description": "Read one person by their external id.", "tags": [ "CDP People" ], "parameters": [ { "name": "externalId", "in": "path", "required": true, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "minLength": 1, "maxLength": 255, "description": "The person externalId." } } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "externalId": { "type": "string", "description": "Your stable identifier for this person." }, "firstName": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "lastName": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "email": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "phoneNumber": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "E.164 format." }, "attributes": { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": {}, "description": "Free-form custom traits." }, "createdAt": { "type": "string", "description": "ISO 8601 timestamp." }, "updatedAt": { "type": "string", "description": "ISO 8601 timestamp." } }, "required": [ "externalId", "firstName", "lastName", "email", "phoneNumber", "attributes", "createdAt", "updatedAt" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } } }, "/api/v1/cdp/people/batch": { "post": { "operationId": "cdp_people_batch_upsert", "summary": "Batch upsert people", "description": "Upsert up to 1000 people in one request. Idempotent and safely retryable.", "tags": [ "CDP People" ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "items": { "minItems": 1, "maxItems": 1000, "type": "array", "items": { "type": "object", "properties": { "externalId": { "type": "string", "minLength": 1, "maxLength": 255, "description": "Your stable identifier for this person (idempotency key)." }, "firstName": { "description": "Given name.", "anyOf": [ { "type": "string", "maxLength": 255 }, { "type": "null" } ] }, "lastName": { "description": "Family name.", "anyOf": [ { "type": "string", "maxLength": 255 }, { "type": "null" } ] }, "email": { "description": "Email address.", "anyOf": [ { "type": "string", "maxLength": 255 }, { "type": "null" } ] }, "phoneNumber": { "description": "Phone number in E.164 format (e.g. +5215555555555).", "anyOf": [ { "type": "string", "maxLength": 255 }, { "type": "null" } ] }, "attributes": { "description": "Free-form custom traits (full-replace on upsert).", "type": "object", "propertyNames": { "type": "string", "maxLength": 255 }, "additionalProperties": {} } }, "required": [ "externalId" ] }, "description": "People to upsert." } }, "required": [ "items" ] } } } }, "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "summary": { "type": "object", "properties": { "total": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "created": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "updated": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "failed": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 } }, "required": [ "total", "created", "updated", "failed" ], "additionalProperties": false }, "errors": { "type": "array", "items": { "type": "object", "properties": { "index": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Zero-based index of the failed item." }, "externalId": { "type": "string" }, "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ], "additionalProperties": false } }, "required": [ "index", "error" ], "additionalProperties": false } } }, "required": [ "summary", "errors" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } } }, "/api/v1/cdp/people/search": { "get": { "operationId": "cdp_people_search", "summary": "Search people", "description": "Search the organization's people by name, or a partial email / phone / externalId. Returns a relevance-ranked shortlist.", "tags": [ "CDP People" ], "parameters": [ { "name": "query", "in": "query", "required": true, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "minLength": 2, "maxLength": 200, "description": "A person name, or a partial email / phone / externalId. At least 2 characters." } }, { "name": "limit", "in": "query", "required": false, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "description": "Max matches to return, 1-25 (default 10).", "type": "integer", "minimum": 1, "maximum": 25 } } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "data": { "type": "array", "items": { "type": "object", "properties": { "externalId": { "type": "string", "description": "Your stable identifier for this person." }, "firstName": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "lastName": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "email": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "phoneNumber": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "E.164 format." }, "attributes": { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": {}, "description": "Free-form custom traits." }, "createdAt": { "type": "string", "description": "ISO 8601 timestamp." }, "updatedAt": { "type": "string", "description": "ISO 8601 timestamp." } }, "required": [ "externalId", "firstName", "lastName", "email", "phoneNumber", "attributes", "createdAt", "updatedAt" ], "additionalProperties": false } } }, "required": [ "data" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } } }, "/api/v1/cdp/relationship-types": { "get": { "operationId": "cdp_relationship_types_list", "summary": "List relationship types", "description": "List the organization's relationship types — use it to discover valid link shapes before linking.", "tags": [ "CDP Relationships" ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "data": { "type": "array", "items": { "anyOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "person_to_co" }, "customObjectType": { "type": "string" }, "relationshipTypeId": { "type": "string" }, "role": { "type": "string", "description": "Edge role, e.g. \"placed\" or \"has_line_item\"." }, "cardinality": { "anyOf": [ { "type": "string", "enum": [ "ONE_TO_ONE", "ONE_TO_MANY", "MANY_TO_ONE", "MANY_TO_MANY" ] }, { "type": "null" } ] }, "description": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "bidirectional": { "type": "boolean" } }, "required": [ "kind", "customObjectType", "relationshipTypeId", "role", "cardinality", "description", "bidirectional" ], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "co_to_co" }, "parentCustomObjectType": { "type": "string" }, "childCustomObjectType": { "type": "string" }, "relationshipTypeId": { "type": "string" }, "role": { "type": "string", "description": "Edge role, e.g. \"placed\" or \"has_line_item\"." }, "cardinality": { "anyOf": [ { "type": "string", "enum": [ "ONE_TO_ONE", "ONE_TO_MANY", "MANY_TO_ONE", "MANY_TO_MANY" ] }, { "type": "null" } ] }, "description": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "bidirectional": { "type": "boolean" } }, "required": [ "kind", "parentCustomObjectType", "childCustomObjectType", "relationshipTypeId", "role", "cardinality", "description", "bidirectional" ], "additionalProperties": false } ] } }, "next_cursor": { "type": "null" } }, "required": [ "data", "next_cursor" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } }, "post": { "operationId": "cdp_relationship_types_register", "summary": "Register relationship type", "description": "Register a relationship type and its metadata. Re-registering an existing type updates it in place.", "tags": [ "CDP Relationships" ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "kind": { "type": "string", "enum": [ "person_to_co", "co_to_co" ], "description": "Type kind. 'person_to_co' links people to one custom object type; 'co_to_co' links two custom object types." }, "role": { "type": "string", "minLength": 1, "maxLength": 255, "description": "Edge role, e.g. \"placed\" or \"has_line_item\"." }, "customObjectType": { "description": "Custom object type name. Required when kind is 'person_to_co'.", "type": "string", "minLength": 1, "maxLength": 255 }, "parentCustomObjectType": { "description": "Parent custom object type name. Required when kind is 'co_to_co'.", "type": "string", "minLength": 1, "maxLength": 255 }, "childCustomObjectType": { "description": "Child custom object type name. Required when kind is 'co_to_co'.", "type": "string", "minLength": 1, "maxLength": 255 }, "cardinality": { "description": "Optional cardinality: ONE_TO_ONE, ONE_TO_MANY, MANY_TO_ONE, MANY_TO_MANY.", "type": "string", "enum": [ "ONE_TO_ONE", "ONE_TO_MANY", "MANY_TO_ONE", "MANY_TO_MANY" ] }, "description": { "description": "Optional human-readable description of the relationship type.", "type": "string", "minLength": 1, "maxLength": 1000 }, "bidirectional": { "description": "Optional: whether the relationship is bidirectional.", "type": "boolean" } }, "required": [ "kind", "role" ] } } } }, "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "allOf": [ { "anyOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "person_to_co" }, "customObjectType": { "type": "string" }, "relationshipTypeId": { "type": "string" }, "role": { "type": "string", "description": "Edge role, e.g. \"placed\" or \"has_line_item\"." }, "cardinality": { "anyOf": [ { "type": "string", "enum": [ "ONE_TO_ONE", "ONE_TO_MANY", "MANY_TO_ONE", "MANY_TO_MANY" ] }, { "type": "null" } ] }, "description": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "bidirectional": { "type": "boolean" } }, "required": [ "kind", "customObjectType", "relationshipTypeId", "role", "cardinality", "description", "bidirectional" ], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "co_to_co" }, "parentCustomObjectType": { "type": "string" }, "childCustomObjectType": { "type": "string" }, "relationshipTypeId": { "type": "string" }, "role": { "type": "string", "description": "Edge role, e.g. \"placed\" or \"has_line_item\"." }, "cardinality": { "anyOf": [ { "type": "string", "enum": [ "ONE_TO_ONE", "ONE_TO_MANY", "MANY_TO_ONE", "MANY_TO_MANY" ] }, { "type": "null" } ] }, "description": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "bidirectional": { "type": "boolean" } }, "required": [ "kind", "parentCustomObjectType", "childCustomObjectType", "relationshipTypeId", "role", "cardinality", "description", "bidirectional" ], "additionalProperties": false } ] }, { "type": "object", "properties": { "created": { "type": "boolean" } }, "required": [ "created" ], "additionalProperties": false } ] } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } } }, "/api/v1/cdp/relationship-types/{relationshipTypeId}": { "get": { "operationId": "cdp_relationship_types_get", "summary": "Get relationship type", "description": "Read one relationship type by id.", "tags": [ "CDP Relationships" ], "parameters": [ { "name": "relationshipTypeId", "in": "path", "required": true, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "minLength": 1, "description": "The relationship type id." } } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "anyOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "person_to_co" }, "customObjectType": { "type": "string" }, "relationshipTypeId": { "type": "string" }, "role": { "type": "string", "description": "Edge role, e.g. \"placed\" or \"has_line_item\"." }, "cardinality": { "anyOf": [ { "type": "string", "enum": [ "ONE_TO_ONE", "ONE_TO_MANY", "MANY_TO_ONE", "MANY_TO_MANY" ] }, { "type": "null" } ] }, "description": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "bidirectional": { "type": "boolean" } }, "required": [ "kind", "customObjectType", "relationshipTypeId", "role", "cardinality", "description", "bidirectional" ], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "co_to_co" }, "parentCustomObjectType": { "type": "string" }, "childCustomObjectType": { "type": "string" }, "relationshipTypeId": { "type": "string" }, "role": { "type": "string", "description": "Edge role, e.g. \"placed\" or \"has_line_item\"." }, "cardinality": { "anyOf": [ { "type": "string", "enum": [ "ONE_TO_ONE", "ONE_TO_MANY", "MANY_TO_ONE", "MANY_TO_MANY" ] }, { "type": "null" } ] }, "description": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "bidirectional": { "type": "boolean" } }, "required": [ "kind", "parentCustomObjectType", "childCustomObjectType", "relationshipTypeId", "role", "cardinality", "description", "bidirectional" ], "additionalProperties": false } ] } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } } }, "/api/v1/cdp/relationships": { "delete": { "operationId": "cdp_relationships_unlink", "summary": "Unlink relationship", "description": "Unlink (soft-delete) a relationship. Idempotent.", "tags": [ "CDP Relationships" ], "parameters": [ { "name": "kind", "in": "query", "required": false, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "description": "Edge kind. 'person_to_co' (default) links a person to a custom object; 'co_to_co' links a parent custom object to a child custom object.", "type": "string", "enum": [ "person_to_co", "co_to_co" ] } }, { "name": "relationshipTypeId", "in": "query", "required": true, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "minLength": 1, "maxLength": 255, "description": "Id of the relationship type (from the relationship-types list). Fixes the role and the custom object type(s) the edge targets." } }, { "name": "personExternalId", "in": "query", "required": false, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "description": "Person externalId. Required when kind is 'person_to_co'.", "type": "string", "minLength": 1, "maxLength": 255 } }, { "name": "customObjectExternalId", "in": "query", "required": false, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "description": "Custom object externalId. Required when kind is 'person_to_co'.", "type": "string", "minLength": 1, "maxLength": 255 } }, { "name": "parentExternalId", "in": "query", "required": false, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "description": "Parent custom object externalId. Required when kind is 'co_to_co'.", "type": "string", "minLength": 1, "maxLength": 255 } }, { "name": "childExternalId", "in": "query", "required": false, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "description": "Child custom object externalId. Required when kind is 'co_to_co'.", "type": "string", "minLength": 1, "maxLength": 255 } } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "removed": { "type": "boolean" } }, "required": [ "removed" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } }, "get": { "operationId": "cdp_relationships_list", "summary": "List relationships", "description": "List relationship edges of one kind, anchored on a person or custom object, newest first.", "tags": [ "CDP Relationships" ], "parameters": [ { "name": "kind", "in": "query", "required": true, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "enum": [ "person_to_co", "co_to_co" ], "description": "Which edge set to list." } }, { "name": "personExternalId", "in": "query", "required": false, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "description": "Anchor: person externalId (kind 'person_to_co').", "type": "string", "minLength": 1 } }, { "name": "customObjectType", "in": "query", "required": false, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "description": "Anchor: custom object type name. Required with customObjectExternalId.", "type": "string", "minLength": 1 } }, { "name": "customObjectExternalId", "in": "query", "required": false, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "description": "Anchor: custom object externalId (scoped by customObjectType).", "type": "string", "minLength": 1 } }, { "name": "direction", "in": "query", "required": false, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "description": "For kind 'co_to_co': list the anchor's children (default) or parents.", "type": "string", "enum": [ "children", "parents" ] } }, { "name": "include_removed", "in": "query", "required": false, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "description": "Include soft-deleted (unlinked) edges. Defaults to false.", "type": "boolean" } }, { "name": "relationshipTypeId", "in": "query", "required": false, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "description": "Filter by relationship type id.", "type": "string", "minLength": 1 } }, { "name": "role", "in": "query", "required": false, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "description": "Filter by edge role.", "type": "string", "minLength": 1 } }, { "name": "limit", "in": "query", "required": false, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "description": "Max items to return, 1-1000 (default 100).", "type": "integer", "minimum": 1, "maximum": 1000 } }, { "name": "cursor", "in": "query", "required": false, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "description": "Opaque pagination token from a previous response's `next_cursor`. Omit for the first page.", "type": "string" } } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "data": { "type": "array", "items": { "anyOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "person_to_co" }, "personExternalId": { "type": "string" }, "customObjectType": { "type": "string" }, "customObjectExternalId": { "type": "string" }, "relationshipTypeId": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "role": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "attributes": { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": {} }, "createdAt": { "type": "string", "description": "ISO 8601 timestamp." }, "updatedAt": { "type": "string", "description": "ISO 8601 timestamp." } }, "required": [ "kind", "personExternalId", "customObjectType", "customObjectExternalId", "relationshipTypeId", "role", "attributes", "createdAt", "updatedAt" ], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "co_to_co" }, "parentCustomObjectType": { "type": "string" }, "parentExternalId": { "type": "string" }, "childCustomObjectType": { "type": "string" }, "childExternalId": { "type": "string" }, "relationshipTypeId": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "role": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "attributes": { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": {} }, "createdAt": { "type": "string", "description": "ISO 8601 timestamp." }, "updatedAt": { "type": "string", "description": "ISO 8601 timestamp." } }, "required": [ "kind", "parentCustomObjectType", "parentExternalId", "childCustomObjectType", "childExternalId", "relationshipTypeId", "role", "attributes", "createdAt", "updatedAt" ], "additionalProperties": false } ] } }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "required": [ "data", "next_cursor" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } }, "post": { "operationId": "cdp_relationships_link", "summary": "Link relationship", "description": "Link a person to a custom object, or one custom object to another. Idempotent.", "tags": [ "CDP Relationships" ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "kind": { "description": "Edge kind. 'person_to_co' (default) links a person to a custom object; 'co_to_co' links a parent custom object to a child custom object.", "type": "string", "enum": [ "person_to_co", "co_to_co" ] }, "relationshipTypeId": { "type": "string", "minLength": 1, "maxLength": 255, "description": "Id of the relationship type (from the relationship-types list). Fixes the role and the custom object type(s) the edge targets." }, "personExternalId": { "description": "Person externalId. Required when kind is 'person_to_co'.", "type": "string", "minLength": 1, "maxLength": 255 }, "customObjectExternalId": { "description": "Custom object externalId. Required when kind is 'person_to_co'.", "type": "string", "minLength": 1, "maxLength": 255 }, "parentExternalId": { "description": "Parent custom object externalId. Required when kind is 'co_to_co'.", "type": "string", "minLength": 1, "maxLength": 255 }, "childExternalId": { "description": "Child custom object externalId. Required when kind is 'co_to_co'.", "type": "string", "minLength": 1, "maxLength": 255 } }, "required": [ "relationshipTypeId" ] } } } }, "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "created": { "type": "boolean" }, "relationshipTypeId": { "type": "string" } }, "required": [ "created", "relationshipTypeId" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } } }, "/api/v1/cdp/relationships/batch": { "post": { "operationId": "cdp_relationships_batch", "summary": "Batch link / unlink", "description": "Link or unlink up to 1000 relationships in one request.", "tags": [ "CDP Relationships" ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "items": { "minItems": 1, "maxItems": 1000, "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "person_to_co" }, "personExternalId": { "type": "string", "minLength": 1, "maxLength": 255, "description": "Person externalId." }, "customObjectExternalId": { "type": "string", "minLength": 1, "maxLength": 255, "description": "Custom object externalId." }, "relationshipTypeId": { "type": "string", "minLength": 1, "maxLength": 255, "description": "Relationship type id (from the relationship-types list)." }, "remove": { "description": "Set true to unlink (soft-delete) instead of link.", "type": "boolean" } }, "required": [ "kind", "personExternalId", "customObjectExternalId", "relationshipTypeId" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "co_to_co" }, "parentExternalId": { "type": "string", "minLength": 1, "maxLength": 255, "description": "Parent custom object externalId." }, "childExternalId": { "type": "string", "minLength": 1, "maxLength": 255, "description": "Child custom object externalId." }, "relationshipTypeId": { "type": "string", "minLength": 1, "maxLength": 255, "description": "Relationship type id (from the relationship-types list)." }, "remove": { "description": "Set true to unlink (soft-delete) instead of link.", "type": "boolean" } }, "required": [ "kind", "parentExternalId", "childExternalId", "relationshipTypeId" ] } ] }, "description": "Relationships to link or unlink." } }, "required": [ "items" ] } } } }, "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "summary": { "type": "object", "properties": { "total": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "created": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "reactivated": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Previously-unlinked edges that were re-activated." }, "removed": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "failed": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 } }, "required": [ "total", "created", "reactivated", "removed", "failed" ], "additionalProperties": false }, "errors": { "type": "array", "items": { "type": "object", "properties": { "index": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Zero-based index of the failed item." }, "externalId": { "type": "string" }, "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ], "additionalProperties": false } }, "required": [ "index", "error" ], "additionalProperties": false } } }, "required": [ "summary", "errors" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } } }, "/api/v1/cdp/sources": { "get": { "operationId": "cdp_sources_list", "summary": "List sources", "description": "List the org's connected data sources (e.g. Shopify, Skio) with their provider and status. Use to confirm an integration like Shopify is connected and ACTIVE before building a journey that depends on it. For Shopify it also returns the store's domains — `checkoutDomain` is the one an abandoned-checkout template's URL button must use.", "tags": [ "CDP Sources" ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "data": { "type": "array", "items": { "type": "object", "properties": { "provider": { "type": "string" }, "status": { "type": "string" }, "displayName": { "type": "string" }, "shopDomain": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "The Shopify admin handle (`*.myshopify.com`). NOT the domain shoppers see — never use it in a customer-facing URL. Null for non-Shopify sources." }, "checkoutDomain": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "The storefront domain shoppers check out on (e.g. `www.store.com`) — use this as the base of an abandoned-checkout template's URL button. Null when the store has no checkout data yet, in which case ask the operator instead of guessing." } }, "required": [ "provider", "status", "displayName", "shopDomain", "checkoutDomain" ], "additionalProperties": false } } }, "required": [ "data" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } } }, "/api/v1/environments": { "get": { "operationId": "environments_list", "summary": "List environments", "description": "List your organization's journey environments and the `{{env.*}}` variable keys each one defines. A journey pinned to an environment resolves those variables and its environment-scoped HTTP credentials at run time. Variable values are not returned.", "tags": [ "Environments" ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "data": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "isDefault": { "type": "boolean", "description": "The environment a journey with no environment pinned falls back to for its `{{env.*}}` values." }, "variableKeys": { "type": "array", "items": { "type": "string" }, "description": "The keys defined for this environment, referenceable as `{{env.}}`. Values are omitted." } }, "required": [ "id", "name", "isDefault", "variableKeys" ], "additionalProperties": false } }, "next_cursor": { "type": "null" } }, "required": [ "data", "next_cursor" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } } }, "/api/v1/http-credentials": { "get": { "operationId": "http_credentials_list", "summary": "List HTTP credentials", "description": "List the reusable HTTP credentials configured for your organization. Reference a credential by its logical `key` (environment-aware) or its `id` to authenticate an HTTP Request journey node. Secrets are never returned.", "tags": [ "HTTP credentials" ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "data": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "key": { "type": "string", "description": "Stable logical key used to reference this credential from an HTTP Request node. A pre-migration legacy row may have an empty key until it is backfilled." }, "name": { "type": "string" }, "authType": { "type": "string", "enum": [ "NONE", "API_KEY", "BEARER", "BASIC" ], "description": "How the request authenticates: NONE, API_KEY, BEARER, or BASIC." }, "environmentId": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "The environment this credential is scoped to; null is a Global credential that resolves in every environment. The same key can have a Global row plus per-environment overrides." } }, "required": [ "id", "key", "name", "authType", "environmentId" ], "additionalProperties": false } }, "next_cursor": { "type": "null" } }, "required": [ "data", "next_cursor" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } } }, "/api/v1/initiatives": { "get": { "operationId": "initiatives_list", "summary": "List initiatives", "description": "List the organization's initiatives, newest first. Archived initiatives are excluded.", "tags": [ "Initiatives" ], "parameters": [ { "name": "limit", "in": "query", "required": false, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "default": 100, "description": "Page size.", "type": "integer", "minimum": 1, "maximum": 1000 } }, { "name": "cursor", "in": "query", "required": false, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "description": "Opaque token from a prior response’s `next_cursor`.", "type": "string" } }, { "name": "status", "in": "query", "required": false, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "description": "Comma-separated lifecycle filter, e.g. `DRAFT,ACTIVE`. Allowed: DRAFT, ACTIVE, PAUSED, COMPLETED, CANCELED.", "type": "string" } } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "data": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Initiative id." }, "name": { "type": "string" }, "channel": { "type": "string", "enum": [ "WHATSAPP", "EMAIL" ] }, "status": { "type": "string", "enum": [ "DRAFT", "ACTIVE", "PAUSED", "COMPLETED", "CANCELED" ] }, "language": { "type": "string", "description": "Conversation language, e.g. `es`." }, "objective": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "isRecurring": { "type": "boolean", "description": "Whether the initiative keeps processing newly added participants on a schedule." }, "flagCondition": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Natural-language condition; matching conversations get flagged during analysis." }, "identityDeflection": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Custom reply when a contact asks whether they are talking to a bot." }, "createdAt": { "type": "string", "description": "ISO 8601 timestamp." }, "updatedAt": { "type": "string", "description": "ISO 8601 timestamp." }, "activatedAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "completedAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "canceledAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "pausedAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "required": [ "id", "name", "channel", "status", "language", "objective", "isRecurring", "flagCondition", "identityDeflection", "createdAt", "updatedAt", "activatedAt", "completedAt", "canceledAt", "pausedAt" ], "additionalProperties": false } }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "required": [ "data", "next_cursor" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } }, "post": { "operationId": "initiatives_create", "summary": "Create initiative", "description": "Create a draft initiative — only a name is required. For a WhatsApp initiative, link an approved template before launching.", "tags": [ "Initiatives" ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "name": { "type": "string", "minLength": 1, "maxLength": 255, "description": "Initiative name." }, "language": { "type": "string", "enum": [ "en", "es", "pt" ] }, "objective": { "description": "What the initiative aims to learn.", "type": "string", "maxLength": 2000 }, "context": { "description": "Background the conversation draws on.", "type": "string", "maxLength": 20000 }, "maxAttempts": { "description": "Outreach attempts per participant. Default 3.", "type": "integer", "minimum": 1, "maximum": 5 }, "isRecurring": { "description": "Recurring initiative: keeps processing newly added participants on a schedule instead of ending after one pass. Default false.", "type": "boolean" }, "flagCondition": { "description": "Natural-language condition; conversations matching it get flagged during analysis. Set null to clear.", "anyOf": [ { "type": "string", "maxLength": 500 }, { "type": "null" } ] }, "identityDeflection": { "description": "Custom reply when a contact asks whether they are talking to a bot. Set null to clear.", "anyOf": [ { "type": "string", "maxLength": 1000 }, { "type": "null" } ] }, "channel": { "default": "WHATSAPP", "description": "Default WHATSAPP.", "type": "string", "enum": [ "WHATSAPP", "EMAIL" ] }, "guidingQuestions": { "description": "The questions the conversation aims to answer.", "maxItems": 50, "type": "array", "items": { "type": "object", "properties": { "questionText": { "type": "string", "minLength": 1, "maxLength": 280, "description": "The question to cover." }, "answerType": { "description": "Default OPEN.", "type": "string", "enum": [ "OPEN", "MULTIPLE_CHOICE", "BOOLEAN", "SCALE" ] }, "priority": { "type": "integer", "minimum": 1, "maximum": 5 }, "scaleMin": { "anyOf": [ { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, { "type": "null" } ] }, "scaleMax": { "anyOf": [ { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, { "type": "null" } ] }, "options": { "description": "Answer options (MULTIPLE_CHOICE only).", "maxItems": 20, "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 280 } } }, "required": [ "questionText" ] } } }, "required": [ "name" ] } } } }, "responses": { "201": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "id": { "type": "string", "description": "Initiative id." }, "name": { "type": "string" }, "channel": { "type": "string", "enum": [ "WHATSAPP", "EMAIL" ] }, "status": { "type": "string", "enum": [ "DRAFT", "ACTIVE", "PAUSED", "COMPLETED", "CANCELED" ] }, "language": { "type": "string", "description": "Conversation language, e.g. `es`." }, "objective": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "isRecurring": { "type": "boolean", "description": "Whether the initiative keeps processing newly added participants on a schedule." }, "flagCondition": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Natural-language condition; matching conversations get flagged during analysis." }, "identityDeflection": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Custom reply when a contact asks whether they are talking to a bot." }, "createdAt": { "type": "string", "description": "ISO 8601 timestamp." }, "updatedAt": { "type": "string", "description": "ISO 8601 timestamp." }, "activatedAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "completedAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "canceledAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "pausedAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "context": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "maxAttempts": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "guidingQuestions": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "questionText": { "type": "string" }, "answerType": { "type": "string" }, "priority": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "scaleMin": { "anyOf": [ { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, { "type": "null" } ] }, "scaleMax": { "anyOf": [ { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, { "type": "null" } ] }, "options": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "label": { "type": "string" }, "position": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 } }, "required": [ "id", "label", "position" ], "additionalProperties": false } } }, "required": [ "id", "questionText", "answerType", "priority", "scaleMin", "scaleMax", "options" ], "additionalProperties": false } } }, "required": [ "id", "name", "channel", "status", "language", "objective", "isRecurring", "flagCondition", "identityDeflection", "createdAt", "updatedAt", "activatedAt", "completedAt", "canceledAt", "pausedAt", "context", "maxAttempts", "guidingQuestions" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } } }, "/api/v1/initiatives/{id}": { "get": { "operationId": "initiatives_get", "summary": "Get initiative", "description": "Get one initiative by id.", "tags": [ "Initiatives" ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "minLength": 1, "description": "The initiative id." } } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "id": { "type": "string", "description": "Initiative id." }, "name": { "type": "string" }, "channel": { "type": "string", "enum": [ "WHATSAPP", "EMAIL" ] }, "status": { "type": "string", "enum": [ "DRAFT", "ACTIVE", "PAUSED", "COMPLETED", "CANCELED" ] }, "language": { "type": "string", "description": "Conversation language, e.g. `es`." }, "objective": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "isRecurring": { "type": "boolean", "description": "Whether the initiative keeps processing newly added participants on a schedule." }, "flagCondition": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Natural-language condition; matching conversations get flagged during analysis." }, "identityDeflection": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Custom reply when a contact asks whether they are talking to a bot." }, "createdAt": { "type": "string", "description": "ISO 8601 timestamp." }, "updatedAt": { "type": "string", "description": "ISO 8601 timestamp." }, "activatedAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "completedAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "canceledAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "pausedAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "context": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "maxAttempts": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "guidingQuestions": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "questionText": { "type": "string" }, "answerType": { "type": "string" }, "priority": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "scaleMin": { "anyOf": [ { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, { "type": "null" } ] }, "scaleMax": { "anyOf": [ { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, { "type": "null" } ] }, "options": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "label": { "type": "string" }, "position": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 } }, "required": [ "id", "label", "position" ], "additionalProperties": false } } }, "required": [ "id", "questionText", "answerType", "priority", "scaleMin", "scaleMax", "options" ], "additionalProperties": false } } }, "required": [ "id", "name", "channel", "status", "language", "objective", "isRecurring", "flagCondition", "identityDeflection", "createdAt", "updatedAt", "activatedAt", "completedAt", "canceledAt", "pausedAt", "context", "maxAttempts", "guidingQuestions" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } }, "patch": { "operationId": "initiatives_update", "summary": "Update initiative", "description": "Edit a draft initiative. Only draft initiatives are editable.", "tags": [ "Initiatives" ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "name": { "type": "string", "minLength": 1, "maxLength": 255, "description": "Initiative name." }, "language": { "type": "string", "enum": [ "en", "es", "pt" ] }, "objective": { "description": "What the initiative aims to learn.", "type": "string", "maxLength": 2000 }, "context": { "description": "Background the conversation draws on.", "type": "string", "maxLength": 20000 }, "maxAttempts": { "description": "Outreach attempts per participant. Default 3.", "type": "integer", "minimum": 1, "maximum": 5 }, "isRecurring": { "description": "Recurring initiative: keeps processing newly added participants on a schedule instead of ending after one pass. Default false.", "type": "boolean" }, "flagCondition": { "description": "Natural-language condition; conversations matching it get flagged during analysis. Set null to clear.", "anyOf": [ { "type": "string", "maxLength": 500 }, { "type": "null" } ] }, "identityDeflection": { "description": "Custom reply when a contact asks whether they are talking to a bot. Set null to clear.", "anyOf": [ { "type": "string", "maxLength": 1000 }, { "type": "null" } ] } } } } } }, "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "minLength": 1, "description": "The initiative id." } } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "id": { "type": "string", "description": "Initiative id." }, "name": { "type": "string" }, "channel": { "type": "string", "enum": [ "WHATSAPP", "EMAIL" ] }, "status": { "type": "string", "enum": [ "DRAFT", "ACTIVE", "PAUSED", "COMPLETED", "CANCELED" ] }, "language": { "type": "string", "description": "Conversation language, e.g. `es`." }, "objective": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "isRecurring": { "type": "boolean", "description": "Whether the initiative keeps processing newly added participants on a schedule." }, "flagCondition": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Natural-language condition; matching conversations get flagged during analysis." }, "identityDeflection": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Custom reply when a contact asks whether they are talking to a bot." }, "createdAt": { "type": "string", "description": "ISO 8601 timestamp." }, "updatedAt": { "type": "string", "description": "ISO 8601 timestamp." }, "activatedAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "completedAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "canceledAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "pausedAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "context": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "maxAttempts": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "guidingQuestions": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "questionText": { "type": "string" }, "answerType": { "type": "string" }, "priority": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "scaleMin": { "anyOf": [ { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, { "type": "null" } ] }, "scaleMax": { "anyOf": [ { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, { "type": "null" } ] }, "options": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "label": { "type": "string" }, "position": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 } }, "required": [ "id", "label", "position" ], "additionalProperties": false } } }, "required": [ "id", "questionText", "answerType", "priority", "scaleMin", "scaleMax", "options" ], "additionalProperties": false } } }, "required": [ "id", "name", "channel", "status", "language", "objective", "isRecurring", "flagCondition", "identityDeflection", "createdAt", "updatedAt", "activatedAt", "completedAt", "canceledAt", "pausedAt", "context", "maxAttempts", "guidingQuestions" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } } }, "/api/v1/initiatives/{id}/archive": { "post": { "operationId": "initiatives_archive", "summary": "Archive initiative", "description": "Archive a completed or canceled initiative, hiding it from the default list. Reversible with unarchive.", "tags": [ "Initiatives" ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "minLength": 1, "description": "The initiative id." } } ], "responses": { "201": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "id": { "type": "string", "description": "Initiative id." }, "name": { "type": "string" }, "channel": { "type": "string", "enum": [ "WHATSAPP", "EMAIL" ] }, "status": { "type": "string", "enum": [ "DRAFT", "ACTIVE", "PAUSED", "COMPLETED", "CANCELED" ] }, "language": { "type": "string", "description": "Conversation language, e.g. `es`." }, "objective": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "isRecurring": { "type": "boolean", "description": "Whether the initiative keeps processing newly added participants on a schedule." }, "flagCondition": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Natural-language condition; matching conversations get flagged during analysis." }, "identityDeflection": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Custom reply when a contact asks whether they are talking to a bot." }, "createdAt": { "type": "string", "description": "ISO 8601 timestamp." }, "updatedAt": { "type": "string", "description": "ISO 8601 timestamp." }, "activatedAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "completedAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "canceledAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "pausedAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "context": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "maxAttempts": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "guidingQuestions": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "questionText": { "type": "string" }, "answerType": { "type": "string" }, "priority": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "scaleMin": { "anyOf": [ { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, { "type": "null" } ] }, "scaleMax": { "anyOf": [ { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, { "type": "null" } ] }, "options": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "label": { "type": "string" }, "position": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 } }, "required": [ "id", "label", "position" ], "additionalProperties": false } } }, "required": [ "id", "questionText", "answerType", "priority", "scaleMin", "scaleMax", "options" ], "additionalProperties": false } } }, "required": [ "id", "name", "channel", "status", "language", "objective", "isRecurring", "flagCondition", "identityDeflection", "createdAt", "updatedAt", "activatedAt", "completedAt", "canceledAt", "pausedAt", "context", "maxAttempts", "guidingQuestions" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } } }, "/api/v1/initiatives/{id}/cancel": { "post": { "operationId": "initiatives_cancel", "summary": "Cancel initiative", "description": "Cancel an initiative and stop its conversations. Terminal. Requires an org admin.", "tags": [ "Initiatives" ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "minLength": 1, "description": "The initiative id." } } ], "responses": { "201": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "id": { "type": "string", "description": "Initiative id." }, "name": { "type": "string" }, "channel": { "type": "string", "enum": [ "WHATSAPP", "EMAIL" ] }, "status": { "type": "string", "enum": [ "DRAFT", "ACTIVE", "PAUSED", "COMPLETED", "CANCELED" ] }, "language": { "type": "string", "description": "Conversation language, e.g. `es`." }, "objective": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "isRecurring": { "type": "boolean", "description": "Whether the initiative keeps processing newly added participants on a schedule." }, "flagCondition": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Natural-language condition; matching conversations get flagged during analysis." }, "identityDeflection": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Custom reply when a contact asks whether they are talking to a bot." }, "createdAt": { "type": "string", "description": "ISO 8601 timestamp." }, "updatedAt": { "type": "string", "description": "ISO 8601 timestamp." }, "activatedAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "completedAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "canceledAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "pausedAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "context": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "maxAttempts": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "guidingQuestions": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "questionText": { "type": "string" }, "answerType": { "type": "string" }, "priority": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "scaleMin": { "anyOf": [ { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, { "type": "null" } ] }, "scaleMax": { "anyOf": [ { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, { "type": "null" } ] }, "options": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "label": { "type": "string" }, "position": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 } }, "required": [ "id", "label", "position" ], "additionalProperties": false } } }, "required": [ "id", "questionText", "answerType", "priority", "scaleMin", "scaleMax", "options" ], "additionalProperties": false } } }, "required": [ "id", "name", "channel", "status", "language", "objective", "isRecurring", "flagCondition", "identityDeflection", "createdAt", "updatedAt", "activatedAt", "completedAt", "canceledAt", "pausedAt", "context", "maxAttempts", "guidingQuestions" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } } }, "/api/v1/initiatives/{id}/data/summary": { "get": { "operationId": "initiatives_summary", "summary": "Data summary", "description": "The initiative's data summary — participant count and, per captured variable, its coverage and rollup.", "tags": [ "Initiatives" ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "minLength": 1, "description": "The initiative id." } } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "participantCount": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "variables": { "type": "array", "items": { "type": "object", "properties": { "key": { "type": "string", "description": "Stable variable key (also used in participant `values`)." }, "label": { "type": "string" }, "valueKind": { "type": "string" }, "cardinality": { "type": "string" }, "source": { "type": "string" }, "coverage": { "type": "object", "properties": { "answered": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "eligible": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 } }, "required": [ "answered", "eligible" ], "additionalProperties": false }, "average": { "description": "Numeric variables only.", "type": "number" }, "distribution": { "description": "Categorical variables only.", "type": "array", "items": { "type": "object", "properties": { "value": { "type": "string" }, "count": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 } }, "required": [ "value", "count" ], "additionalProperties": false } }, "samples": { "description": "Example answers (text variables only).", "type": "array", "items": { "type": "string" } } }, "required": [ "key", "label", "valueKind", "cardinality", "source", "coverage" ], "additionalProperties": false } } }, "required": [ "participantCount", "variables" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } } }, "/api/v1/initiatives/{id}/extraction-schema": { "get": { "operationId": "extraction_schema_get", "summary": "Get extraction schema", "description": "Read an initiative's current extraction schema — the typed fields pulled from each conversation. Returns the schema in the exact shape extraction_schema_set accepts, so you can read it, edit it, and set it back. `hasSchema` is false when none is configured yet.", "tags": [ "Initiatives" ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "minLength": 1, "description": "The initiative id." } } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "initiativeId": { "type": "string" }, "hasSchema": { "type": "boolean", "description": "False when the initiative has no extraction schema yet." }, "version": { "anyOf": [ { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, { "type": "null" } ], "description": "The current schema version, or null when none is set." }, "schema": { "anyOf": [ { "type": "object", "properties": { "fields": { "type": "object", "propertyNames": { "type": "string", "pattern": "^[a-z][a-z0-9_]{0,39}$" }, "additionalProperties": { "oneOf": [ { "type": "object", "properties": { "label": { "type": "string", "minLength": 1, "maxLength": 80 }, "description": { "type": "string", "minLength": 1, "maxLength": 500 }, "mapsTo": { "type": "string", "pattern": "^canonical\\.[a-zA-Z][a-zA-Z0-9]*$" }, "type": { "type": "string", "const": "bool" } }, "required": [ "label", "description", "type" ], "additionalProperties": false }, { "type": "object", "properties": { "label": { "type": "string", "minLength": 1, "maxLength": 80 }, "description": { "type": "string", "minLength": 1, "maxLength": 500 }, "mapsTo": { "type": "string", "pattern": "^canonical\\.[a-zA-Z][a-zA-Z0-9]*$" }, "type": { "type": "string", "const": "int" }, "min": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "max": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 } }, "required": [ "label", "description", "type" ], "additionalProperties": false }, { "type": "object", "properties": { "label": { "type": "string", "minLength": 1, "maxLength": 80 }, "description": { "type": "string", "minLength": 1, "maxLength": 500 }, "mapsTo": { "type": "string", "pattern": "^canonical\\.[a-zA-Z][a-zA-Z0-9]*$" }, "type": { "type": "string", "const": "enum" }, "values": { "minItems": 1, "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 64 } } }, "required": [ "label", "description", "type", "values" ], "additionalProperties": false }, { "type": "object", "properties": { "label": { "type": "string", "minLength": 1, "maxLength": 80 }, "description": { "type": "string", "minLength": 1, "maxLength": 500 }, "mapsTo": { "type": "string", "pattern": "^canonical\\.[a-zA-Z][a-zA-Z0-9]*$" }, "type": { "type": "string", "const": "enum[]" }, "values": { "minItems": 1, "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 64 } } }, "required": [ "label", "description", "type", "values" ], "additionalProperties": false }, { "type": "object", "properties": { "label": { "type": "string", "minLength": 1, "maxLength": 80 }, "description": { "type": "string", "minLength": 1, "maxLength": 500 }, "mapsTo": { "type": "string", "pattern": "^canonical\\.[a-zA-Z][a-zA-Z0-9]*$" }, "type": { "type": "string", "const": "string" }, "maxLength": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991 } }, "required": [ "label", "description", "type" ], "additionalProperties": false }, { "type": "object", "properties": { "label": { "type": "string", "minLength": 1, "maxLength": 80 }, "description": { "type": "string", "minLength": 1, "maxLength": 500 }, "mapsTo": { "type": "string", "pattern": "^canonical\\.[a-zA-Z][a-zA-Z0-9]*$" }, "type": { "type": "string", "const": "string[]" } }, "required": [ "label", "description", "type" ], "additionalProperties": false } ] } } }, "required": [ "fields" ], "additionalProperties": false }, { "type": "null" } ], "description": "The current extraction schema, ready to edit and pass back to extraction_schema_set. Null when none is set." }, "notes": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Note on the current version." }, "createdAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "ISO 8601 timestamp of the current version, or null." } }, "required": [ "initiativeId", "hasSchema", "version", "schema", "notes", "createdAt" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } }, "post": { "operationId": "extraction_schema_set", "summary": "Set extraction schema", "description": "Author or replace an initiative's extraction schema — the typed fields (bool/int/enum/string) pulled from each conversation. Replaces the schema wholesale; submit the complete set of fields, not a diff. A version is created only when the schema actually changes.", "tags": [ "Initiatives" ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "schema": { "type": "object", "properties": { "fields": { "type": "object", "propertyNames": { "type": "string", "pattern": "^[a-z][a-z0-9_]{0,39}$" }, "additionalProperties": { "oneOf": [ { "type": "object", "properties": { "label": { "type": "string", "minLength": 1, "maxLength": 80 }, "description": { "type": "string", "minLength": 1, "maxLength": 500 }, "mapsTo": { "type": "string", "pattern": "^canonical\\.[a-zA-Z][a-zA-Z0-9]*$" }, "type": { "type": "string", "const": "bool" } }, "required": [ "label", "description", "type" ] }, { "type": "object", "properties": { "label": { "type": "string", "minLength": 1, "maxLength": 80 }, "description": { "type": "string", "minLength": 1, "maxLength": 500 }, "mapsTo": { "type": "string", "pattern": "^canonical\\.[a-zA-Z][a-zA-Z0-9]*$" }, "type": { "type": "string", "const": "int" }, "min": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "max": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 } }, "required": [ "label", "description", "type" ] }, { "type": "object", "properties": { "label": { "type": "string", "minLength": 1, "maxLength": 80 }, "description": { "type": "string", "minLength": 1, "maxLength": 500 }, "mapsTo": { "type": "string", "pattern": "^canonical\\.[a-zA-Z][a-zA-Z0-9]*$" }, "type": { "type": "string", "const": "enum" }, "values": { "minItems": 1, "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 64 } } }, "required": [ "label", "description", "type", "values" ] }, { "type": "object", "properties": { "label": { "type": "string", "minLength": 1, "maxLength": 80 }, "description": { "type": "string", "minLength": 1, "maxLength": 500 }, "mapsTo": { "type": "string", "pattern": "^canonical\\.[a-zA-Z][a-zA-Z0-9]*$" }, "type": { "type": "string", "const": "enum[]" }, "values": { "minItems": 1, "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 64 } } }, "required": [ "label", "description", "type", "values" ] }, { "type": "object", "properties": { "label": { "type": "string", "minLength": 1, "maxLength": 80 }, "description": { "type": "string", "minLength": 1, "maxLength": 500 }, "mapsTo": { "type": "string", "pattern": "^canonical\\.[a-zA-Z][a-zA-Z0-9]*$" }, "type": { "type": "string", "const": "string" }, "maxLength": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991 } }, "required": [ "label", "description", "type" ] }, { "type": "object", "properties": { "label": { "type": "string", "minLength": 1, "maxLength": 80 }, "description": { "type": "string", "minLength": 1, "maxLength": 500 }, "mapsTo": { "type": "string", "pattern": "^canonical\\.[a-zA-Z][a-zA-Z0-9]*$" }, "type": { "type": "string", "const": "string[]" } }, "required": [ "label", "description", "type" ] } ] } } }, "required": [ "fields" ], "description": "The complete extraction schema: `{ fields: { : { type, label, description, ... } } }`. Replaces the current schema." }, "notes": { "description": "Optional note recorded on this schema version.", "type": "string", "maxLength": 280 } }, "required": [ "schema" ] } } } }, "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "minLength": 1, "description": "The initiative id." } } ], "responses": { "201": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "initiativeId": { "type": "string" }, "version": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "The extraction schema version now current for the initiative. Unchanged when the submitted schema was semantically identical to the current one." }, "changed": { "type": "boolean", "description": "Whether a new version was created. False when the submitted schema was semantically identical to the current one — no version bump, and the submitted `notes` were NOT recorded." }, "fieldCount": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Number of fields in the schema." }, "notes": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "The note on the current version — not necessarily the submitted note when `changed` is false." }, "createdAt": { "type": "string", "description": "ISO 8601 timestamp of this version." } }, "required": [ "initiativeId", "version", "changed", "fieldCount", "notes", "createdAt" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } } }, "/api/v1/initiatives/{id}/launch": { "post": { "operationId": "initiatives_launch", "summary": "Launch initiative", "description": "Launch a draft initiative — it goes active and Boom starts reaching out. A WhatsApp initiative needs an approved template first; its journey is published as part of the launch (fails with the journey's issues if it cannot be). Requires an org admin.", "tags": [ "Initiatives" ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "minLength": 1, "description": "The initiative id." } } ], "responses": { "201": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "id": { "type": "string", "description": "Initiative id." }, "name": { "type": "string" }, "channel": { "type": "string", "enum": [ "WHATSAPP", "EMAIL" ] }, "status": { "type": "string", "enum": [ "DRAFT", "ACTIVE", "PAUSED", "COMPLETED", "CANCELED" ] }, "language": { "type": "string", "description": "Conversation language, e.g. `es`." }, "objective": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "isRecurring": { "type": "boolean", "description": "Whether the initiative keeps processing newly added participants on a schedule." }, "flagCondition": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Natural-language condition; matching conversations get flagged during analysis." }, "identityDeflection": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Custom reply when a contact asks whether they are talking to a bot." }, "createdAt": { "type": "string", "description": "ISO 8601 timestamp." }, "updatedAt": { "type": "string", "description": "ISO 8601 timestamp." }, "activatedAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "completedAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "canceledAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "pausedAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "context": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "maxAttempts": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "guidingQuestions": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "questionText": { "type": "string" }, "answerType": { "type": "string" }, "priority": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "scaleMin": { "anyOf": [ { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, { "type": "null" } ] }, "scaleMax": { "anyOf": [ { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, { "type": "null" } ] }, "options": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "label": { "type": "string" }, "position": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 } }, "required": [ "id", "label", "position" ], "additionalProperties": false } } }, "required": [ "id", "questionText", "answerType", "priority", "scaleMin", "scaleMax", "options" ], "additionalProperties": false } } }, "required": [ "id", "name", "channel", "status", "language", "objective", "isRecurring", "flagCondition", "identityDeflection", "createdAt", "updatedAt", "activatedAt", "completedAt", "canceledAt", "pausedAt", "context", "maxAttempts", "guidingQuestions" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } } }, "/api/v1/initiatives/{id}/participants": { "get": { "operationId": "initiatives_participants_list", "summary": "List participants", "description": "List an initiative's participants and the values Boom captured from each, newest first. Filter by personExternalId to find one person's runs — including the live one, to stop it before starting another.", "tags": [ "Initiatives" ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "minLength": 1, "description": "Initiative id." } }, { "name": "personExternalId", "in": "query", "required": false, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "description": "Return only this person's runs, matched on the external id recorded when the run started. Exact match, case-sensitive. Participants enrolled without an external id are never returned, so an empty result means no run carries this id — not that the person has no run.", "type": "string", "minLength": 1, "maxLength": 255 } }, { "name": "limit", "in": "query", "required": false, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "description": "Page size, up to 1000.", "type": "integer", "minimum": 1, "maximum": 1000 } }, { "name": "cursor", "in": "query", "required": false, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "description": "Opaque cursor from a previous page.", "type": "string" } } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "data": { "type": "array", "items": { "type": "object", "properties": { "participantId": { "type": "string" }, "phoneNumber": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "name": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "status": { "type": "string", "enum": [ "ACTIVE", "COMPLETED", "STOPPED", "EXPIRED", "FAILED" ], "description": "ACTIVE (conversation may still happen), COMPLETED, STOPPED (messaging halted), EXPIRED, or FAILED." }, "messageCount": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "createdAt": { "type": "string", "description": "ISO 8601 timestamp." }, "capturedAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "When values were last captured (ISO 8601), if any." }, "extractionStatus": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "PENDING (queued, not yet run), EXTRACTED (ran and wrote), INSUFFICIENT_DATA (nothing extractable here — too few messages or no reply on THIS initiative), FAILED, or null for a participant whose extraction has never been triggered. INSUFFICIENT_DATA does NOT mean the person never replied: check their other initiatives with scope=\"customer\" on the messages endpoint." }, "values": { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "type": "array", "items": { "type": "string" } }, "description": "Captured values, keyed by variable key." } }, "required": [ "participantId", "phoneNumber", "name", "status", "messageCount", "createdAt", "capturedAt", "extractionStatus", "values" ], "additionalProperties": false } }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "required": [ "data", "next_cursor" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } }, "post": { "operationId": "initiatives_participants_add", "summary": "Add participants", "description": "Add people to an active WhatsApp initiative. WARNING: each person added receives a real outbound WhatsApp message immediately. Requires a published journey. Do-Not-Contact people are skipped.", "tags": [ "Initiatives" ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "people": { "minItems": 1, "maxItems": 500, "type": "array", "items": { "type": "object", "properties": { "externalId": { "type": "string", "minLength": 1, "maxLength": 255, "description": "Stable unique identifier for this person in your system (CDP identity key)." }, "phoneNumber": { "type": "string", "minLength": 1, "maxLength": 20, "description": "Phone number in E.164 format, e.g. +5215512345678 — the WhatsApp recipient." }, "name": { "description": "First name.", "type": "string", "minLength": 1, "maxLength": 255 }, "lastName": { "description": "Last name.", "type": "string", "minLength": 1, "maxLength": 255 }, "context": { "description": "Per-person context values. Keys must match the initiative's context schema.", "type": "object", "propertyNames": { "type": "string", "maxLength": 100 }, "additionalProperties": { "type": "string", "maxLength": 1000 } } }, "required": [ "externalId", "phoneNumber" ] }, "description": "The people to add. Each receives a real WhatsApp message." } }, "required": [ "people" ] } } } }, "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "minLength": 1, "description": "Initiative id." } } ], "responses": { "201": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "data": { "type": "array", "items": { "type": "object", "properties": { "participantId": { "type": "string" }, "phoneNumber": { "type": "string" }, "status": { "type": "string", "enum": [ "ACTIVE", "COMPLETED", "STOPPED", "EXPIRED", "FAILED" ], "description": "ACTIVE (conversation may still happen), COMPLETED, STOPPED (messaging halted), EXPIRED, or FAILED." } }, "required": [ "participantId", "phoneNumber", "status" ], "additionalProperties": false } }, "errors": { "type": "array", "items": { "type": "object", "properties": { "index": { "type": "number", "description": "Index of the person in the request `people` array." }, "error": { "type": "object", "properties": { "code": { "type": "string", "description": "One of: contact_suppressed, invalid_phone_number, unknown_context_key, enrollment_failed." }, "message": { "type": "string" } }, "required": [ "code", "message" ], "additionalProperties": false } }, "required": [ "index", "error" ], "additionalProperties": false } } }, "required": [ "data", "errors" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } } }, "/api/v1/initiatives/{id}/participants/{participantId}": { "get": { "operationId": "initiatives_participant_get", "summary": "Get participant", "description": "Get one participant's status and captured answers.", "tags": [ "Initiatives" ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "minLength": 1, "description": "Initiative id." } }, { "name": "participantId", "in": "path", "required": true, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "minLength": 1, "description": "Participant id, as returned when adding or listing." } } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "participantId": { "type": "string" }, "phoneNumber": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "name": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "status": { "type": "string", "enum": [ "ACTIVE", "COMPLETED", "STOPPED", "EXPIRED", "FAILED" ], "description": "ACTIVE (conversation may still happen), COMPLETED, STOPPED (messaging halted), EXPIRED, or FAILED." }, "extractionStatus": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "PENDING (queued, not yet run), EXTRACTED (ran and wrote), INSUFFICIENT_DATA (nothing extractable here — too few messages or no reply on THIS initiative), FAILED, or null for a participant whose extraction has never been triggered. INSUFFICIENT_DATA does NOT mean the person never replied: check their other initiatives with scope=\"customer\" on the messages endpoint." }, "values": { "type": "array", "items": { "type": "object", "properties": { "label": { "type": "string" }, "valueKind": { "type": "string" }, "value": { "type": "string" }, "sourceQuote": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "confidence": { "anyOf": [ { "type": "number" }, { "type": "null" } ] } }, "required": [ "label", "valueKind", "value", "sourceQuote", "confidence" ], "additionalProperties": false } } }, "required": [ "participantId", "phoneNumber", "name", "status", "extractionStatus", "values" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } } }, "/api/v1/initiatives/{id}/participants/{participantId}/messages": { "get": { "operationId": "initiatives_participant_messages_list", "summary": "Participant messages", "description": "The participant's conversation transcript, in order. Defaults to this initiative only; pass scope=\"customer\" for everything this person ever said to you across initiatives — use that whenever you need to know whether someone answered at all, since a reply lands on whichever initiative was live at the time and is invisible to the others.", "tags": [ "Initiatives" ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "minLength": 1, "description": "Initiative id." } }, { "name": "participantId", "in": "path", "required": true, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "minLength": 1, "description": "Participant id, as returned when adding or listing." } }, { "name": "scope", "in": "query", "required": false, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "default": "initiative", "description": "initiative (default) = only what was said under this initiative. customer = this person's whole message history across every initiative, each message tagged with the one it belongs to.", "type": "string", "enum": [ "initiative", "customer" ] } } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "participantId": { "type": "string" }, "phoneNumber": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "channel": { "type": "string" }, "scope": { "type": "string", "enum": [ "initiative", "customer" ] }, "data": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "direction": { "type": "string", "enum": [ "outbound", "inbound" ] }, "author": { "type": "string", "enum": [ "agent", "participant" ] }, "type": { "type": "string", "enum": [ "text", "media", "template" ] }, "text": { "type": "string" }, "mediaUrl": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "sentAt": { "type": "string", "description": "ISO 8601 timestamp." }, "initiative": { "description": "Which initiative this message was exchanged under. Present only when reading a whole customer history (scope=\"customer\"), where messages from several initiatives interleave.", "type": "object", "properties": { "id": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "name": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "required": [ "id", "name" ], "additionalProperties": false } }, "required": [ "id", "direction", "author", "type", "text", "mediaUrl", "sentAt" ], "additionalProperties": false } }, "next_cursor": { "type": "null" } }, "required": [ "participantId", "phoneNumber", "channel", "scope", "data", "next_cursor" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } } }, "/api/v1/initiatives/{id}/participants/{participantId}/steps": { "get": { "operationId": "initiatives_participant_steps_list", "summary": "Participant run steps", "description": "The participant's node-by-node journey run timeline (most recent first): which nodes ran, the routing signal each emitted, and bounded handler output/error. Engine execution history — for what the customer said, use the messages endpoint.", "tags": [ "Initiatives" ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "minLength": 1, "description": "Initiative id." } }, { "name": "participantId", "in": "path", "required": true, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "minLength": 1, "description": "Participant id, as returned when adding or listing." } }, { "name": "limit", "in": "query", "required": false, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "description": "Most-recent steps to return (default 50, max 200). Bounded tail — no older-page cursor; compare against totalSteps.", "type": "integer", "minimum": 1, "maximum": 200 } }, { "name": "includeBody", "in": "query", "required": false, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "description": "Include HTTP_REQUEST bodies in step output: the response `body` (verbatim from the third party — may carry PII) and the resolved `requestBody` (credential secrets, env values, and document URLs are always masked at capture). Defaults to false: bodies are stripped; failure `reason` is always included.", "type": "boolean" } } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "participantId": { "type": "string" }, "totalSteps": { "type": "number", "description": "Full step count, even when more than `limit` were returned." }, "data": { "type": "array", "items": { "type": "object", "properties": { "nodeId": { "type": "string" }, "nodeKind": { "type": "string", "description": "The workflow node kind, e.g. HTTP_REQUEST." }, "status": { "type": "string", "description": "RUNNING, COMPLETED, or FAILED." }, "emittedSignal": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "The routing signal the node emitted, e.g. SUCCESS / FAILED." }, "targetNodeId": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "The node the emitted signal routed to." }, "enteredAt": { "type": "string", "description": "ISO 8601 timestamp." }, "exitedAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "ISO 8601 timestamp, null if open." }, "output": { "description": "Handler output (bounded); shape depends on node kind. HTTP_REQUEST body/requestBody appear only with includeBody=true; its failure `reason` (e.g. blocked_host, dns_failure, timeout) is always present when status is null." }, "error": { "anyOf": [ { "type": "object", "properties": { "name": { "type": "string" }, "message": { "type": "string" }, "code": { "anyOf": [ { "type": "string" }, { "type": "number" } ] } }, "required": [ "name", "message" ], "additionalProperties": false }, { "type": "null" } ], "description": "Failure detail when the step FAILED (no stack trace)." } }, "required": [ "nodeId", "nodeKind", "status", "emittedSignal", "targetNodeId", "enteredAt", "exitedAt", "output", "error" ], "additionalProperties": false } }, "next_cursor": { "type": "null" } }, "required": [ "participantId", "totalSteps", "data", "next_cursor" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } } }, "/api/v1/initiatives/{id}/participants/{participantId}/stop": { "post": { "operationId": "initiatives_participants_stop", "summary": "Stop participant", "description": "Stop all messaging to one participant and close their conversation. Idempotent and safe — it never sends. Their answers and transcript stay readable.", "tags": [ "Initiatives" ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "minLength": 1, "description": "Initiative id." } }, { "name": "participantId", "in": "path", "required": true, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "minLength": 1, "description": "Participant id, as returned when adding or listing." } } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "stopped": { "type": "boolean", "const": true }, "status": { "type": "string", "enum": [ "ACTIVE", "COMPLETED", "STOPPED", "EXPIRED", "FAILED" ], "description": "ACTIVE (conversation may still happen), COMPLETED, STOPPED (messaging halted), EXPIRED, or FAILED." } }, "required": [ "stopped", "status" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } } }, "/api/v1/initiatives/{id}/pause": { "post": { "operationId": "initiatives_pause", "summary": "Pause initiative", "description": "Stop enrolling new people into this initiative. Anyone already enrolled keeps their run, and conversations in progress continue normally. Reversible with resume.", "tags": [ "Initiatives" ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "minLength": 1, "description": "The initiative id." } } ], "responses": { "201": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "id": { "type": "string", "description": "Initiative id." }, "name": { "type": "string" }, "channel": { "type": "string", "enum": [ "WHATSAPP", "EMAIL" ] }, "status": { "type": "string", "enum": [ "DRAFT", "ACTIVE", "PAUSED", "COMPLETED", "CANCELED" ] }, "language": { "type": "string", "description": "Conversation language, e.g. `es`." }, "objective": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "isRecurring": { "type": "boolean", "description": "Whether the initiative keeps processing newly added participants on a schedule." }, "flagCondition": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Natural-language condition; matching conversations get flagged during analysis." }, "identityDeflection": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Custom reply when a contact asks whether they are talking to a bot." }, "createdAt": { "type": "string", "description": "ISO 8601 timestamp." }, "updatedAt": { "type": "string", "description": "ISO 8601 timestamp." }, "activatedAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "completedAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "canceledAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "pausedAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "context": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "maxAttempts": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "guidingQuestions": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "questionText": { "type": "string" }, "answerType": { "type": "string" }, "priority": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "scaleMin": { "anyOf": [ { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, { "type": "null" } ] }, "scaleMax": { "anyOf": [ { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, { "type": "null" } ] }, "options": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "label": { "type": "string" }, "position": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 } }, "required": [ "id", "label", "position" ], "additionalProperties": false } } }, "required": [ "id", "questionText", "answerType", "priority", "scaleMin", "scaleMax", "options" ], "additionalProperties": false } } }, "required": [ "id", "name", "channel", "status", "language", "objective", "isRecurring", "flagCondition", "identityDeflection", "createdAt", "updatedAt", "activatedAt", "completedAt", "canceledAt", "pausedAt", "context", "maxAttempts", "guidingQuestions" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } } }, "/api/v1/initiatives/{id}/reextract": { "post": { "operationId": "extraction_reextract", "summary": "Re-extract conversations", "description": "Re-run extraction over an initiative's existing conversations — the fix for participants whose replies were never read (a schema authored after the conversations happened, or an initiative that never had extraction run at all). Start with dryRun to see how many conversations are eligible and how many actually carry enough transcript to extract from. Only conversations with at least 3 messages including one reply can produce anything.", "tags": [ "Initiatives" ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "dryRun": { "default": false, "description": "Count what would run without queueing anything. Do this first — the counts tell you whether re-extraction is worth the spend.", "type": "boolean" }, "force": { "default": false, "description": "Re-extract conversations already extracted at the current schema version. Off by default, so a plain call only fills gaps.", "type": "boolean" }, "fromDate": { "description": "Only consider conversations created at or after this ISO 8601 instant.", "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$" } } } } } }, "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "minLength": 1, "description": "The initiative id." } } ], "responses": { "201": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "initiativeId": { "type": "string" }, "eligible": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Conversations targeted for re-extraction." }, "queued": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Extractions actually enqueued — always 0 on a dry run." }, "willExtract": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Of the eligible set, how many carry enough transcript to produce values." }, "insufficient": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Eligible but below the analyzability bar (under 3 messages, or no reply on this initiative) — these will be marked INSUFFICIENT_DATA rather than extracted. A high number here usually means the replies live on a different initiative." }, "dryRun": { "type": "boolean" } }, "required": [ "initiativeId", "eligible", "queued", "willExtract", "insufficient", "dryRun" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } } }, "/api/v1/initiatives/{id}/resume": { "post": { "operationId": "initiatives_resume", "summary": "Resume initiative", "description": "Resume a paused initiative so it starts enrolling people again.", "tags": [ "Initiatives" ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "minLength": 1, "description": "The initiative id." } } ], "responses": { "201": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "id": { "type": "string", "description": "Initiative id." }, "name": { "type": "string" }, "channel": { "type": "string", "enum": [ "WHATSAPP", "EMAIL" ] }, "status": { "type": "string", "enum": [ "DRAFT", "ACTIVE", "PAUSED", "COMPLETED", "CANCELED" ] }, "language": { "type": "string", "description": "Conversation language, e.g. `es`." }, "objective": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "isRecurring": { "type": "boolean", "description": "Whether the initiative keeps processing newly added participants on a schedule." }, "flagCondition": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Natural-language condition; matching conversations get flagged during analysis." }, "identityDeflection": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Custom reply when a contact asks whether they are talking to a bot." }, "createdAt": { "type": "string", "description": "ISO 8601 timestamp." }, "updatedAt": { "type": "string", "description": "ISO 8601 timestamp." }, "activatedAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "completedAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "canceledAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "pausedAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "context": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "maxAttempts": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "guidingQuestions": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "questionText": { "type": "string" }, "answerType": { "type": "string" }, "priority": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "scaleMin": { "anyOf": [ { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, { "type": "null" } ] }, "scaleMax": { "anyOf": [ { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, { "type": "null" } ] }, "options": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "label": { "type": "string" }, "position": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 } }, "required": [ "id", "label", "position" ], "additionalProperties": false } } }, "required": [ "id", "questionText", "answerType", "priority", "scaleMin", "scaleMax", "options" ], "additionalProperties": false } } }, "required": [ "id", "name", "channel", "status", "language", "objective", "isRecurring", "flagCondition", "identityDeflection", "createdAt", "updatedAt", "activatedAt", "completedAt", "canceledAt", "pausedAt", "context", "maxAttempts", "guidingQuestions" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } } }, "/api/v1/initiatives/{id}/templates": { "get": { "operationId": "initiatives_templates_get", "summary": "Get templates", "description": "List which WhatsApp template each outreach round sends. Round 1 must be linked before a WhatsApp initiative can launch.", "tags": [ "Initiatives" ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "minLength": 1, "description": "The initiative id." } } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "data": { "type": "array", "items": { "type": "object", "properties": { "round": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Which outreach message this is (1 = the first message)." }, "templateId": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "The linked WhatsApp template, or null if none is linked yet." }, "templateName": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "required": [ "round", "templateId", "templateName" ], "additionalProperties": false } } }, "required": [ "data" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } }, "post": { "operationId": "initiatives_templates_set", "summary": "Set template", "description": "Link an approved WhatsApp template as a round's outreach message. Required before a WhatsApp initiative can launch.", "tags": [ "Initiatives" ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "templateId": { "type": "string", "minLength": 1, "description": "An APPROVED WhatsApp template id (from templates_list)." }, "round": { "default": 1, "description": "Which outreach message (1 = the first). Default 1.", "type": "integer", "minimum": 1, "maximum": 4 } }, "required": [ "templateId" ] } } } }, "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "minLength": 1, "description": "The initiative id." } } ], "responses": { "201": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "round": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Which outreach message this is (1 = the first message)." }, "templateId": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "The linked WhatsApp template, or null if none is linked yet." }, "templateName": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "required": [ "round", "templateId", "templateName" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } } }, "/api/v1/initiatives/{id}/transcripts": { "get": { "operationId": "initiatives_transcripts_list", "summary": "List transcripts", "description": "Full conversation transcripts for a page of participants, newest participant first. Use this to read or export ALL conversations of an initiative — one call per page (up to 100 participants) instead of looping the per-participant messages endpoint.", "tags": [ "Initiatives" ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "minLength": 1, "description": "Initiative id." } }, { "name": "limit", "in": "query", "required": false, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "description": "Participants per page (default 20, max 100).", "type": "integer", "minimum": 1, "maximum": 100 } }, { "name": "cursor", "in": "query", "required": false, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "description": "Opaque cursor from a previous page.", "type": "string" } } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "data": { "type": "array", "items": { "type": "object", "properties": { "participantId": { "type": "string" }, "phoneNumber": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "name": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "status": { "type": "string", "enum": [ "ACTIVE", "COMPLETED", "STOPPED", "EXPIRED", "FAILED" ], "description": "ACTIVE (conversation may still happen), COMPLETED, STOPPED (messaging halted), EXPIRED, or FAILED." }, "createdAt": { "type": "string", "description": "When the participant was added (ISO 8601)." }, "messages": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "direction": { "type": "string", "enum": [ "outbound", "inbound" ] }, "author": { "type": "string", "enum": [ "agent", "participant" ] }, "type": { "type": "string", "enum": [ "text", "media", "template" ] }, "text": { "type": "string" }, "mediaUrl": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "sentAt": { "type": "string", "description": "ISO 8601 timestamp." }, "initiative": { "description": "Which initiative this message was exchanged under. Present only when reading a whole customer history (scope=\"customer\"), where messages from several initiatives interleave.", "type": "object", "properties": { "id": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "name": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "required": [ "id", "name" ], "additionalProperties": false } }, "required": [ "id", "direction", "author", "type", "text", "mediaUrl", "sentAt" ], "additionalProperties": false }, "description": "The full conversation, in order. Empty if no outreach yet." } }, "required": [ "participantId", "phoneNumber", "name", "status", "createdAt", "messages" ], "additionalProperties": false } }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "required": [ "data", "next_cursor" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } } }, "/api/v1/initiatives/{id}/unarchive": { "post": { "operationId": "initiatives_unarchive", "summary": "Unarchive initiative", "description": "Unarchive an initiative, restoring it to the default list. Its status is unchanged.", "tags": [ "Initiatives" ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "minLength": 1, "description": "The initiative id." } } ], "responses": { "201": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "id": { "type": "string", "description": "Initiative id." }, "name": { "type": "string" }, "channel": { "type": "string", "enum": [ "WHATSAPP", "EMAIL" ] }, "status": { "type": "string", "enum": [ "DRAFT", "ACTIVE", "PAUSED", "COMPLETED", "CANCELED" ] }, "language": { "type": "string", "description": "Conversation language, e.g. `es`." }, "objective": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "isRecurring": { "type": "boolean", "description": "Whether the initiative keeps processing newly added participants on a schedule." }, "flagCondition": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Natural-language condition; matching conversations get flagged during analysis." }, "identityDeflection": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Custom reply when a contact asks whether they are talking to a bot." }, "createdAt": { "type": "string", "description": "ISO 8601 timestamp." }, "updatedAt": { "type": "string", "description": "ISO 8601 timestamp." }, "activatedAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "completedAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "canceledAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "pausedAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "context": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "maxAttempts": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "guidingQuestions": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "questionText": { "type": "string" }, "answerType": { "type": "string" }, "priority": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "scaleMin": { "anyOf": [ { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, { "type": "null" } ] }, "scaleMax": { "anyOf": [ { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, { "type": "null" } ] }, "options": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "label": { "type": "string" }, "position": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 } }, "required": [ "id", "label", "position" ], "additionalProperties": false } } }, "required": [ "id", "questionText", "answerType", "priority", "scaleMin", "scaleMax", "options" ], "additionalProperties": false } } }, "required": [ "id", "name", "channel", "status", "language", "objective", "isRecurring", "flagCondition", "identityDeflection", "createdAt", "updatedAt", "activatedAt", "completedAt", "canceledAt", "pausedAt", "context", "maxAttempts", "guidingQuestions" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } } }, "/api/v1/journeys": { "get": { "operationId": "journeys_list", "summary": "List journeys", "description": "List the organization's journeys, newest first. A journey is the step sequence people move through, attached to an initiative. Read-only.", "tags": [ "Journeys" ], "parameters": [ { "name": "initiativeId", "in": "query", "required": false, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "description": "Only the journey attached to this initiative.", "type": "string", "minLength": 1 } }, { "name": "status", "in": "query", "required": false, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "description": "Only journeys with this status.", "type": "string", "enum": [ "DRAFT", "ACTIVE", "ARCHIVED" ] } }, { "name": "limit", "in": "query", "required": false, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "description": "Page size (default 100, max 1000).", "type": "integer", "minimum": 1, "maximum": 1000 } }, { "name": "cursor", "in": "query", "required": false, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "description": "Opaque pagination token from a previous response's next_cursor.", "type": "string" } } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "data": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Journey id." }, "initiativeId": { "type": "string", "description": "The initiative this journey belongs to." }, "name": { "type": "string", "description": "Journey name (from its initiative)." }, "status": { "type": "string", "enum": [ "DRAFT", "ACTIVE", "ARCHIVED" ], "description": "DRAFT (still being configured), ACTIVE (live — people can move through it), or ARCHIVED (no longer running)." }, "version": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Version number of the journey's current setup. Each time the steps are edited and re-activated, the version increases." }, "createdAt": { "type": "string", "description": "ISO 8601 timestamp." }, "updatedAt": { "type": "string", "description": "ISO 8601 timestamp." } }, "required": [ "id", "initiativeId", "name", "status", "version", "createdAt", "updatedAt" ], "additionalProperties": false } }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Pass as `cursor` to fetch the next page; null on the last." } }, "required": [ "data", "next_cursor" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } }, "post": { "operationId": "journeys_create_draft", "summary": "Create draft", "description": "Create a new draft journey on an initiative from a full graph. The draft is editable and does not run until published (which is done in the app). Omit node positions and the server lays the graph out automatically.", "tags": [ "Journeys" ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "initiativeId": { "type": "string", "minLength": 1, "description": "The initiative to attach the new draft journey to." }, "definition": { "type": "object", "properties": { "id": { "description": "Journey id; carried for round-trip ergonomics. Optional on create.", "type": "string" }, "name": { "type": "string", "minLength": 1, "description": "Journey name." }, "metadata": { "type": "object", "properties": { "initiativeType": { "type": "string" }, "version": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "cancelOnEvents": { "description": "Cancel an in-flight run when any of these events arrive.", "type": "object", "properties": { "eventNames": { "type": "array", "items": { "type": "string" } } }, "required": [ "eventNames" ] }, "environmentId": { "description": "Pinned environment whose non-secret {{env.*}} values HTTP nodes resolve against. Frozen at publish. The server preserves the stored value when a whole-graph update omits it.", "type": "string" } }, "description": "Optional journey-level metadata." }, "actions": { "minItems": 1, "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "ENTRY" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "description": { "type": "string" }, "triggerType": { "description": "How people enter: manual (added by an operator or API call), segment (on entering a segment), or cdp_event (when an event is received). Defaults to manual.", "type": "string", "enum": [ "manual", "segment", "cdp_event" ] }, "segmentId": { "description": "Segment id — required when triggerType is segment.", "type": "string" }, "segmentName": { "description": "Cached segment display name (optional).", "type": "string" }, "eventName": { "description": "CDP event name — required when triggerType is cdp_event.", "type": "string" }, "maxEnrollments": { "description": "Frequency cap: max enrollments per person within enrollmentWindow. Both-or-neither with enrollmentWindow.", "type": "integer", "minimum": 1, "maximum": 9007199254740991 }, "enrollmentWindow": { "description": "Rolling window for the frequency cap.", "type": "string" } }, "description": "Trigger node config. Exactly one ENTRY node per journey." } }, "required": [ "id", "kind" ] }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "SEND_MESSAGE" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "templateId": { "description": "Approved WhatsApp template id. Resolve ids from the catalog.", "type": "string" }, "templateName": { "type": "string" }, "channel": { "description": "Send channel. Only whatsapp is live today.", "type": "string", "enum": [ "whatsapp", "sms", "email" ] }, "templateBindings": { "description": "Map of template placeholder → variable reference.", "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "type": "string" } }, "channelId": { "description": "Sending WhatsApp channel (WABA) id. Required before publishing.", "type": "string" }, "sendImmediately": { "description": "Deprecated business-hours gate; prefer a preceding DELAY.", "type": "boolean" } }, "description": "Sends a WhatsApp template." } }, "required": [ "id", "kind" ] }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "CONVERSATION_BLOCK" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "goal": { "type": "string" }, "maxTimeout": { "description": "How long to wait for a reply before timing out.", "type": "string" }, "mode": { "type": "string", "enum": [ "AGENT", "ESCALATE" ] }, "outputs": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "label": { "type": "string" }, "type": { "type": "string", "enum": [ "string", "number", "date", "boolean", "json" ] }, "description": { "type": "string" }, "builtin": { "type": "boolean" } }, "required": [ "id", "label", "type", "builtin" ] } } }, "description": "Legacy combined wait + AI conversation block." } }, "required": [ "id", "kind" ] }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "WAIT_FOR_REPLY" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "maxTimeout": { "description": "How long to wait for the first reply before timing out.", "type": "string" } }, "description": "Waits for the person to reply." } }, "required": [ "id", "kind" ] }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "MANAGE_CONVERSATION" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "mode": { "description": "AGENT (AI-led) or ESCALATE (human handoff). Defaults to AGENT.", "type": "string", "enum": [ "AGENT", "ESCALATE" ] }, "inactivityTimeout": { "description": "Optional custom idle window (e.g. '2h', '30m') that overrides the global inactive-conversation close. Resets on each inbound message; after this much silence the node closes the conversation (routes CLOSED). Hard cap 24h; under 30m is allowed but flagged 'not recommended'. Requires the journey-inactivity-timeout flag.", "type": "string" } }, "description": "Runs the AI-led conversation." } }, "required": [ "id", "kind" ] }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "DISPATCH_EVENT" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "eventName": { "type": "string", "minLength": 1, "description": "CDP event name to record. Must match the CDP name pattern." }, "properties": { "description": "Literal string values, or { var: path } bindings resolved to typed values at dispatch time.", "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "anyOf": [ { "type": "string" }, { "type": "object", "properties": { "var": { "type": "string" } }, "required": [ "var" ] } ] } }, "description": { "type": "string" } }, "required": [ "eventName" ], "description": "Records a CDP event for the person." } }, "required": [ "id", "kind" ] }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "DELAY" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "mode": { "description": "How the wait is measured. Defaults to duration.", "type": "string", "enum": [ "duration", "until_date", "until_weekday" ] }, "duration": { "description": "For mode duration.", "type": "string" }, "targetAt": { "description": "ISO 8601 instant, for mode until_date.", "type": "string" }, "weekdays": { "description": "ISO weekdays 1=Mon..7=Sun, for mode until_weekday.", "type": "array", "items": { "type": "integer", "minimum": 1, "maximum": 7 } }, "windowStartMinutes": { "type": "integer", "minimum": 0, "maximum": 1439 }, "windowEndMinutes": { "type": "integer", "minimum": 0, "maximum": 1439 }, "timezone": { "description": "IANA timezone. Load-bearing for until_weekday.", "type": "string" }, "description": { "type": "string" } }, "description": "Pauses the run." } }, "required": [ "id", "kind" ] }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "DECISION" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "logic": { "type": "string", "enum": [ "AND", "OR" ] }, "conditions": { "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "value" }, "selectionPath": { "type": "string", "description": "Dot-path into the run; must start with one of \"engagement.workflowState.\", \"engagement.extracted.\", \"engagement.nodeOutputs.\" (e.g. engagement.workflowState.totalPrice). customer.*, person.*, attributes.* and engagement.context.* are NOT resolvable here." }, "operator": { "type": "string", "enum": [ "eq", "neq", "gt", "lt", "contains", "isSet" ] }, "value": { "type": "string" } }, "required": [ "kind", "selectionPath", "operator", "value" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "event" }, "eventName": { "type": "string" }, "subjectSelectionPath": { "type": "string", "description": "Dot-path into the run; must start with one of \"engagement.workflowState.\", \"engagement.extracted.\", \"engagement.nodeOutputs.\" (e.g. engagement.workflowState.totalPrice). customer.*, person.*, attributes.* and engagement.context.* are NOT resolvable here." }, "occurred": { "type": "boolean" } }, "required": [ "kind", "eventName", "subjectSelectionPath", "occurred" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "cdp_predicate" }, "term": { "type": "object", "properties": { "attr": { "type": "string", "minLength": 1, "description": "Typed person column, `attributes.`, or `computed.`. See journeys_condition_catalog for the available attributes." }, "type": { "type": "string", "enum": [ "STRING", "NUMBER", "BOOLEAN", "DATE", "JSON", "ARRAY" ], "description": "CDP attribute type. Determines which `op` values are legal — see journeys_condition_catalog." }, "op": { "type": "string", "minLength": 1, "description": "Segments OperatorEnum value (eq | neq | gt | lt | in_last_n | ...). Must be legal for `type` — see journeys_condition_catalog." }, "value": { "description": "Shape depends on `op`: a plain scalar for eq/neq/gt/lt/starts_with/…, an array for in/not_in/contains/not_contains, {from, to} for between, {amount, unit} for in_last_n/in_next_n/more_than_n_ago/more_than_n_from_now, {minAmount, maxAmount, unit} for between_n_and_m_ago, {daysOffset} for exactly_n_from_today. Omit entirely for is_null/is_not_null.", "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" }, { "type": "array", "items": { "anyOf": [ { "type": "string" }, { "type": "number" } ] } }, { "type": "object", "properties": { "from": { "type": "string" }, "to": { "type": "string" } }, "required": [ "from", "to" ] }, { "type": "object", "properties": { "amount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "amount", "unit" ] }, { "type": "object", "properties": { "minAmount": { "type": "integer", "minimum": 0, "maximum": 9999 }, "maxAmount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "minAmount", "maxAmount", "unit" ] }, { "type": "object", "properties": { "daysOffset": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "rollForward": { "type": "object", "properties": { "fromDow": { "type": "integer", "minimum": 0, "maximum": 6 }, "includeDows": { "minItems": 1, "type": "array", "items": { "type": "integer", "minimum": 0, "maximum": 6 } } }, "required": [ "fromDow", "includeDows" ] } }, "required": [ "daysOffset" ] } ] } }, "required": [ "attr", "type", "op" ], "description": "A single live person/computed predicate term. See journeys_condition_catalog for its shape and the legal operator/value pairing." } }, "required": [ "kind", "term" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "cdp_object" }, "objectType": { "type": "string" }, "matchAttr": { "type": "string" }, "matchSelectionPath": { "type": "string", "description": "Dot-path into the run; must start with one of \"engagement.workflowState.\", \"engagement.extracted.\", \"engagement.nodeOutputs.\" (e.g. engagement.workflowState.totalPrice). customer.*, person.*, attributes.* and engagement.context.* are NOT resolvable here." }, "exists": { "type": "boolean" } }, "required": [ "kind", "objectType", "matchAttr", "matchSelectionPath", "exists" ] } ], "description": "One decision condition." } }, "description": { "type": "string" } }, "required": [ "logic", "conditions" ], "description": "Two-way branch. Emits YES / NO." } }, "required": [ "id", "kind" ] }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "CASE" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "selectionPath": { "type": "string", "description": "Value to switch on; must start with one of \"attributes.\", \"engagement.extracted.\", \"engagement.nodeOutputs.\" (e.g. attributes.plan_tier)." }, "branches": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable branch id; edge handle is case:." }, "value": { "type": "string", "description": "Value matched. Unique within the node." }, "label": { "type": "string", "minLength": 1, "description": "Required. Names the variant in analytics and on canvas." } }, "required": [ "id", "value", "label" ] }, "description": "Up to 10 branches. A case:default handle is always required." }, "description": { "type": "string" } }, "required": [ "selectionPath", "branches" ], "description": "N-way switch on a person attribute." } }, "required": [ "id", "kind" ] }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "RANDOM_SPLIT" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "arms": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable arm id; edge handle is split:." }, "weight": { "type": "integer", "minimum": 1, "maximum": 100, "description": "Integer percentage. A node's arms must total 100." }, "label": { "type": "string" } }, "required": [ "id", "weight" ] }, "description": "At least 2 and at most 10 arms whose weights total exactly 100. There is no default handle — every roll lands on a declared arm." }, "description": { "type": "string" } }, "required": [ "arms" ], "description": "Randomly routes each run down one of N weighted arms." } }, "required": [ "id", "kind" ] }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "HTTP_REQUEST" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "method": { "type": "string", "enum": [ "GET", "POST", "PUT", "PATCH", "DELETE" ], "description": "HTTP method." }, "url": { "type": "string", "minLength": 1, "description": "Target URL. Supports {{variable}} placeholders." }, "headers": { "description": "Request headers as key/value pairs.", "type": "array", "items": { "type": "object", "properties": { "key": { "type": "string" }, "value": { "type": "string" } }, "required": [ "key", "value" ] } }, "body": { "description": "Request body. mode none sends no body.", "type": "object", "properties": { "mode": { "type": "string", "enum": [ "none", "json", "raw" ] }, "content": { "type": "string" }, "contentType": { "type": "string" } }, "required": [ "mode" ] }, "credentialId": { "description": "Deprecated/legacy: HttpCredential row id used to authenticate the request. Prefer credentialKey.", "type": "string" }, "credentialKey": { "description": "Logical credential key; the pinned environment selects the secret.", "type": "string" }, "timeoutMs": { "description": "Request timeout in milliseconds. Max 30000 (30s).", "type": "integer", "exclusiveMinimum": 0, "maximum": 30000 }, "maxAttempts": { "description": "Max attempts including the first. Max 5.", "type": "integer", "exclusiveMinimum": 0, "maximum": 5 }, "documentUrlTtlSeconds": { "description": "TTL (seconds, ≤86400) for presigned engagement.documents URLs this node emits. Default 86400.", "type": "integer", "exclusiveMinimum": 0, "maximum": 86400 } }, "required": [ "method", "url" ], "description": "Calls an external HTTP endpoint. Emits SUCCESS or FAILED." } }, "required": [ "id", "kind" ] }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "EXIT" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "outcome": { "type": "string" }, "nextInitiativeId": { "description": "Chain into another initiative on exit.", "type": "string" } }, "description": "Terminal node." } }, "required": [ "id", "kind" ] } ] }, "description": "The nodes. Exactly one ENTRY and at least one EXIT are required to publish." }, "edges": { "type": "array", "items": { "type": "object", "properties": { "from": { "type": "string", "description": "Source node id." }, "to": { "type": "string", "description": "Target node id." }, "sourceHandle": { "type": "string", "description": "The emitted signal that activates this edge (e.g. SENT, REPLIED, YES, case:). A handle may wire to at most one node." }, "metadata": { "type": "object", "properties": { "signalCategory": { "type": "string", "enum": [ "lifecycle", "system" ] }, "signalDescription": { "type": "string" } } } }, "required": [ "from", "to", "sourceHandle" ], "description": "A connection: node `from` routes to `to` when it emits `sourceHandle`." }, "description": "The connections between node handles." } }, "required": [ "name", "actions", "edges" ], "description": "The full journey graph. Drafts may be incomplete; run journeys_validate before publishing." } }, "required": [ "initiativeId", "definition" ] } } } }, "responses": { "201": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "id": { "type": "string", "description": "Journey (workflow version) id." }, "initiativeId": { "type": "string", "description": "The initiative this journey belongs to." }, "status": { "type": "string", "enum": [ "DRAFT", "PUBLISHED", "STOPPED" ], "description": "DRAFT (editable), PUBLISHED (live, frozen), or STOPPED (retired)." }, "version": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Version number within the initiative." }, "definition": { "type": "object", "properties": { "id": { "description": "Journey id; carried for round-trip ergonomics. Optional on create.", "type": "string" }, "name": { "type": "string", "minLength": 1, "description": "Journey name." }, "metadata": { "type": "object", "properties": { "initiativeType": { "type": "string" }, "version": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "cancelOnEvents": { "description": "Cancel an in-flight run when any of these events arrive.", "type": "object", "properties": { "eventNames": { "type": "array", "items": { "type": "string" } } }, "required": [ "eventNames" ], "additionalProperties": false }, "environmentId": { "description": "Pinned environment whose non-secret {{env.*}} values HTTP nodes resolve against. Frozen at publish. The server preserves the stored value when a whole-graph update omits it.", "type": "string" } }, "additionalProperties": false, "description": "Optional journey-level metadata." }, "actions": { "minItems": 1, "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "ENTRY" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "description": { "type": "string" }, "triggerType": { "description": "How people enter: manual (added by an operator or API call), segment (on entering a segment), or cdp_event (when an event is received). Defaults to manual.", "type": "string", "enum": [ "manual", "segment", "cdp_event" ] }, "segmentId": { "description": "Segment id — required when triggerType is segment.", "type": "string" }, "segmentName": { "description": "Cached segment display name (optional).", "type": "string" }, "eventName": { "description": "CDP event name — required when triggerType is cdp_event.", "type": "string" }, "maxEnrollments": { "description": "Frequency cap: max enrollments per person within enrollmentWindow. Both-or-neither with enrollmentWindow.", "type": "integer", "minimum": 1, "maximum": 9007199254740991 }, "enrollmentWindow": { "description": "Rolling window for the frequency cap.", "type": "string" } }, "additionalProperties": false, "description": "Trigger node config. Exactly one ENTRY node per journey." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "SEND_MESSAGE" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "templateId": { "description": "Approved WhatsApp template id. Resolve ids from the catalog.", "type": "string" }, "templateName": { "type": "string" }, "channel": { "description": "Send channel. Only whatsapp is live today.", "type": "string", "enum": [ "whatsapp", "sms", "email" ] }, "templateBindings": { "description": "Map of template placeholder → variable reference.", "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "type": "string" } }, "channelId": { "description": "Sending WhatsApp channel (WABA) id. Required before publishing.", "type": "string" }, "sendImmediately": { "description": "Deprecated business-hours gate; prefer a preceding DELAY.", "type": "boolean" } }, "additionalProperties": false, "description": "Sends a WhatsApp template." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "CONVERSATION_BLOCK" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "goal": { "type": "string" }, "maxTimeout": { "description": "How long to wait for a reply before timing out.", "type": "string" }, "mode": { "type": "string", "enum": [ "AGENT", "ESCALATE" ] }, "outputs": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "label": { "type": "string" }, "type": { "type": "string", "enum": [ "string", "number", "date", "boolean", "json" ] }, "description": { "type": "string" }, "builtin": { "type": "boolean" } }, "required": [ "id", "label", "type", "builtin" ], "additionalProperties": false } } }, "additionalProperties": false, "description": "Legacy combined wait + AI conversation block." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "WAIT_FOR_REPLY" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "maxTimeout": { "description": "How long to wait for the first reply before timing out.", "type": "string" } }, "additionalProperties": false, "description": "Waits for the person to reply." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "MANAGE_CONVERSATION" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "mode": { "description": "AGENT (AI-led) or ESCALATE (human handoff). Defaults to AGENT.", "type": "string", "enum": [ "AGENT", "ESCALATE" ] }, "inactivityTimeout": { "description": "Optional custom idle window (e.g. '2h', '30m') that overrides the global inactive-conversation close. Resets on each inbound message; after this much silence the node closes the conversation (routes CLOSED). Hard cap 24h; under 30m is allowed but flagged 'not recommended'. Requires the journey-inactivity-timeout flag.", "type": "string" } }, "additionalProperties": false, "description": "Runs the AI-led conversation." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "DISPATCH_EVENT" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "eventName": { "type": "string", "minLength": 1, "description": "CDP event name to record. Must match the CDP name pattern." }, "properties": { "description": "Literal string values, or { var: path } bindings resolved to typed values at dispatch time.", "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "anyOf": [ { "type": "string" }, { "type": "object", "properties": { "var": { "type": "string" } }, "required": [ "var" ], "additionalProperties": false } ] } }, "description": { "type": "string" } }, "required": [ "eventName" ], "additionalProperties": false, "description": "Records a CDP event for the person." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "DELAY" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "mode": { "description": "How the wait is measured. Defaults to duration.", "type": "string", "enum": [ "duration", "until_date", "until_weekday" ] }, "duration": { "description": "For mode duration.", "type": "string" }, "targetAt": { "description": "ISO 8601 instant, for mode until_date.", "type": "string" }, "weekdays": { "description": "ISO weekdays 1=Mon..7=Sun, for mode until_weekday.", "type": "array", "items": { "type": "integer", "minimum": 1, "maximum": 7 } }, "windowStartMinutes": { "type": "integer", "minimum": 0, "maximum": 1439 }, "windowEndMinutes": { "type": "integer", "minimum": 0, "maximum": 1439 }, "timezone": { "description": "IANA timezone. Load-bearing for until_weekday.", "type": "string" }, "description": { "type": "string" } }, "additionalProperties": false, "description": "Pauses the run." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "DECISION" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "logic": { "type": "string", "enum": [ "AND", "OR" ] }, "conditions": { "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "value" }, "selectionPath": { "type": "string", "description": "Dot-path into the run; must start with one of \"engagement.workflowState.\", \"engagement.extracted.\", \"engagement.nodeOutputs.\" (e.g. engagement.workflowState.totalPrice). customer.*, person.*, attributes.* and engagement.context.* are NOT resolvable here." }, "operator": { "type": "string", "enum": [ "eq", "neq", "gt", "lt", "contains", "isSet" ] }, "value": { "type": "string" } }, "required": [ "kind", "selectionPath", "operator", "value" ], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "event" }, "eventName": { "type": "string" }, "subjectSelectionPath": { "type": "string", "description": "Dot-path into the run; must start with one of \"engagement.workflowState.\", \"engagement.extracted.\", \"engagement.nodeOutputs.\" (e.g. engagement.workflowState.totalPrice). customer.*, person.*, attributes.* and engagement.context.* are NOT resolvable here." }, "occurred": { "type": "boolean" } }, "required": [ "kind", "eventName", "subjectSelectionPath", "occurred" ], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "cdp_predicate" }, "term": { "type": "object", "properties": { "attr": { "type": "string", "minLength": 1, "description": "Typed person column, `attributes.`, or `computed.`. See journeys_condition_catalog for the available attributes." }, "type": { "type": "string", "enum": [ "STRING", "NUMBER", "BOOLEAN", "DATE", "JSON", "ARRAY" ], "description": "CDP attribute type. Determines which `op` values are legal — see journeys_condition_catalog." }, "op": { "type": "string", "minLength": 1, "description": "Segments OperatorEnum value (eq | neq | gt | lt | in_last_n | ...). Must be legal for `type` — see journeys_condition_catalog." }, "value": { "description": "Shape depends on `op`: a plain scalar for eq/neq/gt/lt/starts_with/…, an array for in/not_in/contains/not_contains, {from, to} for between, {amount, unit} for in_last_n/in_next_n/more_than_n_ago/more_than_n_from_now, {minAmount, maxAmount, unit} for between_n_and_m_ago, {daysOffset} for exactly_n_from_today. Omit entirely for is_null/is_not_null.", "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" }, { "type": "array", "items": { "anyOf": [ { "type": "string" }, { "type": "number" } ] } }, { "type": "object", "properties": { "from": { "type": "string" }, "to": { "type": "string" } }, "required": [ "from", "to" ], "additionalProperties": false }, { "type": "object", "properties": { "amount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "amount", "unit" ], "additionalProperties": false }, { "type": "object", "properties": { "minAmount": { "type": "integer", "minimum": 0, "maximum": 9999 }, "maxAmount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "minAmount", "maxAmount", "unit" ], "additionalProperties": false }, { "type": "object", "properties": { "daysOffset": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "rollForward": { "type": "object", "properties": { "fromDow": { "type": "integer", "minimum": 0, "maximum": 6 }, "includeDows": { "minItems": 1, "type": "array", "items": { "type": "integer", "minimum": 0, "maximum": 6 } } }, "required": [ "fromDow", "includeDows" ], "additionalProperties": false } }, "required": [ "daysOffset" ], "additionalProperties": false } ] } }, "required": [ "attr", "type", "op" ], "additionalProperties": false, "description": "A single live person/computed predicate term. See journeys_condition_catalog for its shape and the legal operator/value pairing." } }, "required": [ "kind", "term" ], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "cdp_object" }, "objectType": { "type": "string" }, "matchAttr": { "type": "string" }, "matchSelectionPath": { "type": "string", "description": "Dot-path into the run; must start with one of \"engagement.workflowState.\", \"engagement.extracted.\", \"engagement.nodeOutputs.\" (e.g. engagement.workflowState.totalPrice). customer.*, person.*, attributes.* and engagement.context.* are NOT resolvable here." }, "exists": { "type": "boolean" } }, "required": [ "kind", "objectType", "matchAttr", "matchSelectionPath", "exists" ], "additionalProperties": false } ], "description": "One decision condition." } }, "description": { "type": "string" } }, "required": [ "logic", "conditions" ], "additionalProperties": false, "description": "Two-way branch. Emits YES / NO." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "CASE" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "selectionPath": { "type": "string", "description": "Value to switch on; must start with one of \"attributes.\", \"engagement.extracted.\", \"engagement.nodeOutputs.\" (e.g. attributes.plan_tier)." }, "branches": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable branch id; edge handle is case:." }, "value": { "type": "string", "description": "Value matched. Unique within the node." }, "label": { "type": "string", "minLength": 1, "description": "Required. Names the variant in analytics and on canvas." } }, "required": [ "id", "value", "label" ], "additionalProperties": false }, "description": "Up to 10 branches. A case:default handle is always required." }, "description": { "type": "string" } }, "required": [ "selectionPath", "branches" ], "additionalProperties": false, "description": "N-way switch on a person attribute." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "RANDOM_SPLIT" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "arms": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable arm id; edge handle is split:." }, "weight": { "type": "integer", "minimum": 1, "maximum": 100, "description": "Integer percentage. A node's arms must total 100." }, "label": { "type": "string" } }, "required": [ "id", "weight" ], "additionalProperties": false }, "description": "At least 2 and at most 10 arms whose weights total exactly 100. There is no default handle — every roll lands on a declared arm." }, "description": { "type": "string" } }, "required": [ "arms" ], "additionalProperties": false, "description": "Randomly routes each run down one of N weighted arms." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "HTTP_REQUEST" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "method": { "type": "string", "enum": [ "GET", "POST", "PUT", "PATCH", "DELETE" ], "description": "HTTP method." }, "url": { "type": "string", "minLength": 1, "description": "Target URL. Supports {{variable}} placeholders." }, "headers": { "description": "Request headers as key/value pairs.", "type": "array", "items": { "type": "object", "properties": { "key": { "type": "string" }, "value": { "type": "string" } }, "required": [ "key", "value" ], "additionalProperties": false } }, "body": { "description": "Request body. mode none sends no body.", "type": "object", "properties": { "mode": { "type": "string", "enum": [ "none", "json", "raw" ] }, "content": { "type": "string" }, "contentType": { "type": "string" } }, "required": [ "mode" ], "additionalProperties": false }, "credentialId": { "description": "Deprecated/legacy: HttpCredential row id used to authenticate the request. Prefer credentialKey.", "type": "string" }, "credentialKey": { "description": "Logical credential key; the pinned environment selects the secret.", "type": "string" }, "timeoutMs": { "description": "Request timeout in milliseconds. Max 30000 (30s).", "type": "integer", "exclusiveMinimum": 0, "maximum": 30000 }, "maxAttempts": { "description": "Max attempts including the first. Max 5.", "type": "integer", "exclusiveMinimum": 0, "maximum": 5 }, "documentUrlTtlSeconds": { "description": "TTL (seconds, ≤86400) for presigned engagement.documents URLs this node emits. Default 86400.", "type": "integer", "exclusiveMinimum": 0, "maximum": 86400 } }, "required": [ "method", "url" ], "additionalProperties": false, "description": "Calls an external HTTP endpoint. Emits SUCCESS or FAILED." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "EXIT" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "outcome": { "type": "string" }, "nextInitiativeId": { "description": "Chain into another initiative on exit.", "type": "string" } }, "additionalProperties": false, "description": "Terminal node." } }, "required": [ "id", "kind" ], "additionalProperties": false } ] }, "description": "The nodes. Exactly one ENTRY and at least one EXIT are required to publish." }, "edges": { "type": "array", "items": { "type": "object", "properties": { "from": { "type": "string", "description": "Source node id." }, "to": { "type": "string", "description": "Target node id." }, "sourceHandle": { "type": "string", "description": "The emitted signal that activates this edge (e.g. SENT, REPLIED, YES, case:). A handle may wire to at most one node." }, "metadata": { "type": "object", "properties": { "signalCategory": { "type": "string", "enum": [ "lifecycle", "system" ] }, "signalDescription": { "type": "string" } }, "additionalProperties": false } }, "required": [ "from", "to", "sourceHandle" ], "additionalProperties": false, "description": "A connection: node `from` routes to `to` when it emits `sourceHandle`." }, "description": "The connections between node handles." } }, "required": [ "name", "actions", "edges" ], "additionalProperties": false, "description": "The full journey graph." } }, "required": [ "id", "initiativeId", "status", "version", "definition" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } } }, "/api/v1/journeys/{journeyId}": { "get": { "operationId": "journeys_get", "summary": "Get journey", "description": "Get one journey by id — its trigger and the ordered steps people move through. Read-only, for inspecting setup.", "tags": [ "Journeys" ], "parameters": [ { "name": "journeyId", "in": "path", "required": true, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "minLength": 1, "description": "Journey id." } } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "id": { "type": "string", "description": "Journey id." }, "initiativeId": { "type": "string", "description": "The initiative this journey belongs to." }, "name": { "type": "string", "description": "Journey name (from its initiative)." }, "status": { "type": "string", "enum": [ "DRAFT", "ACTIVE", "ARCHIVED" ], "description": "DRAFT (still being configured), ACTIVE (live — people can move through it), or ARCHIVED (no longer running)." }, "version": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Version number of the journey's current setup. Each time the steps are edited and re-activated, the version increases." }, "createdAt": { "type": "string", "description": "ISO 8601 timestamp." }, "updatedAt": { "type": "string", "description": "ISO 8601 timestamp." }, "trigger": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "manual", "segment", "event" ], "description": "How people enter the journey: manual (added by an operator or API call), segment (added when they enter a segment), or event (added when an event is received for them)." }, "segment": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Segment name, when type is segment." }, "event": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Event name, when type is event." } }, "required": [ "type", "segment", "event" ], "additionalProperties": false }, "steps": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Step id, unique within the journey." }, "type": { "type": "string", "enum": [ "entry", "message", "conversation", "wait", "branch", "split", "event", "end", "step" ], "description": "What the step does: entry (where people start), message (sends a message template), conversation (an AI-led conversation), wait (pauses before continuing), branch (routes down a yes or no path), split (routes across several cases), event (records an event), end (finishes the journey), or step (a step of another kind)." }, "title": { "description": "The name the journey author gave this step.", "type": "string" }, "description": { "description": "Plain-language summary of what the step is configured to do.", "type": "string" } }, "required": [ "id", "type" ], "additionalProperties": false }, "description": "The steps that make up the journey, in the order a person moves through them." } }, "required": [ "id", "initiativeId", "name", "status", "version", "createdAt", "updatedAt", "trigger", "steps" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } }, "patch": { "operationId": "journeys_update_draft", "summary": "Update draft", "description": "Replace a draft journey's whole graph. Journey-level metadata is merged, not replaced — keys the payload omits (e.g. the environment pin) keep their stored values. Only drafts can be edited; published versions are frozen (edit a live journey in the app to fork a new draft). Omit node positions and the server lays the graph out automatically.", "tags": [ "Journeys" ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "definition": { "type": "object", "properties": { "id": { "description": "Journey id; carried for round-trip ergonomics. Optional on create.", "type": "string" }, "name": { "type": "string", "minLength": 1, "description": "Journey name." }, "metadata": { "type": "object", "properties": { "initiativeType": { "type": "string" }, "version": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "cancelOnEvents": { "description": "Cancel an in-flight run when any of these events arrive.", "type": "object", "properties": { "eventNames": { "type": "array", "items": { "type": "string" } } }, "required": [ "eventNames" ] }, "environmentId": { "description": "Pinned environment whose non-secret {{env.*}} values HTTP nodes resolve against. Frozen at publish. The server preserves the stored value when a whole-graph update omits it.", "type": "string" } }, "description": "Optional journey-level metadata." }, "actions": { "minItems": 1, "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "ENTRY" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "description": { "type": "string" }, "triggerType": { "description": "How people enter: manual (added by an operator or API call), segment (on entering a segment), or cdp_event (when an event is received). Defaults to manual.", "type": "string", "enum": [ "manual", "segment", "cdp_event" ] }, "segmentId": { "description": "Segment id — required when triggerType is segment.", "type": "string" }, "segmentName": { "description": "Cached segment display name (optional).", "type": "string" }, "eventName": { "description": "CDP event name — required when triggerType is cdp_event.", "type": "string" }, "maxEnrollments": { "description": "Frequency cap: max enrollments per person within enrollmentWindow. Both-or-neither with enrollmentWindow.", "type": "integer", "minimum": 1, "maximum": 9007199254740991 }, "enrollmentWindow": { "description": "Rolling window for the frequency cap.", "type": "string" } }, "description": "Trigger node config. Exactly one ENTRY node per journey." } }, "required": [ "id", "kind" ] }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "SEND_MESSAGE" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "templateId": { "description": "Approved WhatsApp template id. Resolve ids from the catalog.", "type": "string" }, "templateName": { "type": "string" }, "channel": { "description": "Send channel. Only whatsapp is live today.", "type": "string", "enum": [ "whatsapp", "sms", "email" ] }, "templateBindings": { "description": "Map of template placeholder → variable reference.", "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "type": "string" } }, "channelId": { "description": "Sending WhatsApp channel (WABA) id. Required before publishing.", "type": "string" }, "sendImmediately": { "description": "Deprecated business-hours gate; prefer a preceding DELAY.", "type": "boolean" } }, "description": "Sends a WhatsApp template." } }, "required": [ "id", "kind" ] }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "CONVERSATION_BLOCK" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "goal": { "type": "string" }, "maxTimeout": { "description": "How long to wait for a reply before timing out.", "type": "string" }, "mode": { "type": "string", "enum": [ "AGENT", "ESCALATE" ] }, "outputs": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "label": { "type": "string" }, "type": { "type": "string", "enum": [ "string", "number", "date", "boolean", "json" ] }, "description": { "type": "string" }, "builtin": { "type": "boolean" } }, "required": [ "id", "label", "type", "builtin" ] } } }, "description": "Legacy combined wait + AI conversation block." } }, "required": [ "id", "kind" ] }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "WAIT_FOR_REPLY" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "maxTimeout": { "description": "How long to wait for the first reply before timing out.", "type": "string" } }, "description": "Waits for the person to reply." } }, "required": [ "id", "kind" ] }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "MANAGE_CONVERSATION" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "mode": { "description": "AGENT (AI-led) or ESCALATE (human handoff). Defaults to AGENT.", "type": "string", "enum": [ "AGENT", "ESCALATE" ] }, "inactivityTimeout": { "description": "Optional custom idle window (e.g. '2h', '30m') that overrides the global inactive-conversation close. Resets on each inbound message; after this much silence the node closes the conversation (routes CLOSED). Hard cap 24h; under 30m is allowed but flagged 'not recommended'. Requires the journey-inactivity-timeout flag.", "type": "string" } }, "description": "Runs the AI-led conversation." } }, "required": [ "id", "kind" ] }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "DISPATCH_EVENT" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "eventName": { "type": "string", "minLength": 1, "description": "CDP event name to record. Must match the CDP name pattern." }, "properties": { "description": "Literal string values, or { var: path } bindings resolved to typed values at dispatch time.", "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "anyOf": [ { "type": "string" }, { "type": "object", "properties": { "var": { "type": "string" } }, "required": [ "var" ] } ] } }, "description": { "type": "string" } }, "required": [ "eventName" ], "description": "Records a CDP event for the person." } }, "required": [ "id", "kind" ] }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "DELAY" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "mode": { "description": "How the wait is measured. Defaults to duration.", "type": "string", "enum": [ "duration", "until_date", "until_weekday" ] }, "duration": { "description": "For mode duration.", "type": "string" }, "targetAt": { "description": "ISO 8601 instant, for mode until_date.", "type": "string" }, "weekdays": { "description": "ISO weekdays 1=Mon..7=Sun, for mode until_weekday.", "type": "array", "items": { "type": "integer", "minimum": 1, "maximum": 7 } }, "windowStartMinutes": { "type": "integer", "minimum": 0, "maximum": 1439 }, "windowEndMinutes": { "type": "integer", "minimum": 0, "maximum": 1439 }, "timezone": { "description": "IANA timezone. Load-bearing for until_weekday.", "type": "string" }, "description": { "type": "string" } }, "description": "Pauses the run." } }, "required": [ "id", "kind" ] }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "DECISION" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "logic": { "type": "string", "enum": [ "AND", "OR" ] }, "conditions": { "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "value" }, "selectionPath": { "type": "string", "description": "Dot-path into the run; must start with one of \"engagement.workflowState.\", \"engagement.extracted.\", \"engagement.nodeOutputs.\" (e.g. engagement.workflowState.totalPrice). customer.*, person.*, attributes.* and engagement.context.* are NOT resolvable here." }, "operator": { "type": "string", "enum": [ "eq", "neq", "gt", "lt", "contains", "isSet" ] }, "value": { "type": "string" } }, "required": [ "kind", "selectionPath", "operator", "value" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "event" }, "eventName": { "type": "string" }, "subjectSelectionPath": { "type": "string", "description": "Dot-path into the run; must start with one of \"engagement.workflowState.\", \"engagement.extracted.\", \"engagement.nodeOutputs.\" (e.g. engagement.workflowState.totalPrice). customer.*, person.*, attributes.* and engagement.context.* are NOT resolvable here." }, "occurred": { "type": "boolean" } }, "required": [ "kind", "eventName", "subjectSelectionPath", "occurred" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "cdp_predicate" }, "term": { "type": "object", "properties": { "attr": { "type": "string", "minLength": 1, "description": "Typed person column, `attributes.`, or `computed.`. See journeys_condition_catalog for the available attributes." }, "type": { "type": "string", "enum": [ "STRING", "NUMBER", "BOOLEAN", "DATE", "JSON", "ARRAY" ], "description": "CDP attribute type. Determines which `op` values are legal — see journeys_condition_catalog." }, "op": { "type": "string", "minLength": 1, "description": "Segments OperatorEnum value (eq | neq | gt | lt | in_last_n | ...). Must be legal for `type` — see journeys_condition_catalog." }, "value": { "description": "Shape depends on `op`: a plain scalar for eq/neq/gt/lt/starts_with/…, an array for in/not_in/contains/not_contains, {from, to} for between, {amount, unit} for in_last_n/in_next_n/more_than_n_ago/more_than_n_from_now, {minAmount, maxAmount, unit} for between_n_and_m_ago, {daysOffset} for exactly_n_from_today. Omit entirely for is_null/is_not_null.", "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" }, { "type": "array", "items": { "anyOf": [ { "type": "string" }, { "type": "number" } ] } }, { "type": "object", "properties": { "from": { "type": "string" }, "to": { "type": "string" } }, "required": [ "from", "to" ] }, { "type": "object", "properties": { "amount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "amount", "unit" ] }, { "type": "object", "properties": { "minAmount": { "type": "integer", "minimum": 0, "maximum": 9999 }, "maxAmount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "minAmount", "maxAmount", "unit" ] }, { "type": "object", "properties": { "daysOffset": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "rollForward": { "type": "object", "properties": { "fromDow": { "type": "integer", "minimum": 0, "maximum": 6 }, "includeDows": { "minItems": 1, "type": "array", "items": { "type": "integer", "minimum": 0, "maximum": 6 } } }, "required": [ "fromDow", "includeDows" ] } }, "required": [ "daysOffset" ] } ] } }, "required": [ "attr", "type", "op" ], "description": "A single live person/computed predicate term. See journeys_condition_catalog for its shape and the legal operator/value pairing." } }, "required": [ "kind", "term" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "cdp_object" }, "objectType": { "type": "string" }, "matchAttr": { "type": "string" }, "matchSelectionPath": { "type": "string", "description": "Dot-path into the run; must start with one of \"engagement.workflowState.\", \"engagement.extracted.\", \"engagement.nodeOutputs.\" (e.g. engagement.workflowState.totalPrice). customer.*, person.*, attributes.* and engagement.context.* are NOT resolvable here." }, "exists": { "type": "boolean" } }, "required": [ "kind", "objectType", "matchAttr", "matchSelectionPath", "exists" ] } ], "description": "One decision condition." } }, "description": { "type": "string" } }, "required": [ "logic", "conditions" ], "description": "Two-way branch. Emits YES / NO." } }, "required": [ "id", "kind" ] }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "CASE" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "selectionPath": { "type": "string", "description": "Value to switch on; must start with one of \"attributes.\", \"engagement.extracted.\", \"engagement.nodeOutputs.\" (e.g. attributes.plan_tier)." }, "branches": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable branch id; edge handle is case:." }, "value": { "type": "string", "description": "Value matched. Unique within the node." }, "label": { "type": "string", "minLength": 1, "description": "Required. Names the variant in analytics and on canvas." } }, "required": [ "id", "value", "label" ] }, "description": "Up to 10 branches. A case:default handle is always required." }, "description": { "type": "string" } }, "required": [ "selectionPath", "branches" ], "description": "N-way switch on a person attribute." } }, "required": [ "id", "kind" ] }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "RANDOM_SPLIT" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "arms": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable arm id; edge handle is split:." }, "weight": { "type": "integer", "minimum": 1, "maximum": 100, "description": "Integer percentage. A node's arms must total 100." }, "label": { "type": "string" } }, "required": [ "id", "weight" ] }, "description": "At least 2 and at most 10 arms whose weights total exactly 100. There is no default handle — every roll lands on a declared arm." }, "description": { "type": "string" } }, "required": [ "arms" ], "description": "Randomly routes each run down one of N weighted arms." } }, "required": [ "id", "kind" ] }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "HTTP_REQUEST" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "method": { "type": "string", "enum": [ "GET", "POST", "PUT", "PATCH", "DELETE" ], "description": "HTTP method." }, "url": { "type": "string", "minLength": 1, "description": "Target URL. Supports {{variable}} placeholders." }, "headers": { "description": "Request headers as key/value pairs.", "type": "array", "items": { "type": "object", "properties": { "key": { "type": "string" }, "value": { "type": "string" } }, "required": [ "key", "value" ] } }, "body": { "description": "Request body. mode none sends no body.", "type": "object", "properties": { "mode": { "type": "string", "enum": [ "none", "json", "raw" ] }, "content": { "type": "string" }, "contentType": { "type": "string" } }, "required": [ "mode" ] }, "credentialId": { "description": "Deprecated/legacy: HttpCredential row id used to authenticate the request. Prefer credentialKey.", "type": "string" }, "credentialKey": { "description": "Logical credential key; the pinned environment selects the secret.", "type": "string" }, "timeoutMs": { "description": "Request timeout in milliseconds. Max 30000 (30s).", "type": "integer", "exclusiveMinimum": 0, "maximum": 30000 }, "maxAttempts": { "description": "Max attempts including the first. Max 5.", "type": "integer", "exclusiveMinimum": 0, "maximum": 5 }, "documentUrlTtlSeconds": { "description": "TTL (seconds, ≤86400) for presigned engagement.documents URLs this node emits. Default 86400.", "type": "integer", "exclusiveMinimum": 0, "maximum": 86400 } }, "required": [ "method", "url" ], "description": "Calls an external HTTP endpoint. Emits SUCCESS or FAILED." } }, "required": [ "id", "kind" ] }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "EXIT" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "outcome": { "type": "string" }, "nextInitiativeId": { "description": "Chain into another initiative on exit.", "type": "string" } }, "description": "Terminal node." } }, "required": [ "id", "kind" ] } ] }, "description": "The nodes. Exactly one ENTRY and at least one EXIT are required to publish." }, "edges": { "type": "array", "items": { "type": "object", "properties": { "from": { "type": "string", "description": "Source node id." }, "to": { "type": "string", "description": "Target node id." }, "sourceHandle": { "type": "string", "description": "The emitted signal that activates this edge (e.g. SENT, REPLIED, YES, case:). A handle may wire to at most one node." }, "metadata": { "type": "object", "properties": { "signalCategory": { "type": "string", "enum": [ "lifecycle", "system" ] }, "signalDescription": { "type": "string" } } } }, "required": [ "from", "to", "sourceHandle" ], "description": "A connection: node `from` routes to `to` when it emits `sourceHandle`." }, "description": "The connections between node handles." } }, "required": [ "name", "actions", "edges" ], "description": "The full journey graph. Drafts may be incomplete; run journeys_validate before publishing." } }, "required": [ "definition" ] } } } }, "parameters": [ { "name": "journeyId", "in": "path", "required": true, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "minLength": 1, "description": "A draft journey id, or the initiative id (resolves to its current draft)." } } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "id": { "type": "string", "description": "Journey (workflow version) id." }, "initiativeId": { "type": "string", "description": "The initiative this journey belongs to." }, "status": { "type": "string", "enum": [ "DRAFT", "PUBLISHED", "STOPPED" ], "description": "DRAFT (editable), PUBLISHED (live, frozen), or STOPPED (retired)." }, "version": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Version number within the initiative." }, "definition": { "type": "object", "properties": { "id": { "description": "Journey id; carried for round-trip ergonomics. Optional on create.", "type": "string" }, "name": { "type": "string", "minLength": 1, "description": "Journey name." }, "metadata": { "type": "object", "properties": { "initiativeType": { "type": "string" }, "version": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "cancelOnEvents": { "description": "Cancel an in-flight run when any of these events arrive.", "type": "object", "properties": { "eventNames": { "type": "array", "items": { "type": "string" } } }, "required": [ "eventNames" ], "additionalProperties": false }, "environmentId": { "description": "Pinned environment whose non-secret {{env.*}} values HTTP nodes resolve against. Frozen at publish. The server preserves the stored value when a whole-graph update omits it.", "type": "string" } }, "additionalProperties": false, "description": "Optional journey-level metadata." }, "actions": { "minItems": 1, "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "ENTRY" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "description": { "type": "string" }, "triggerType": { "description": "How people enter: manual (added by an operator or API call), segment (on entering a segment), or cdp_event (when an event is received). Defaults to manual.", "type": "string", "enum": [ "manual", "segment", "cdp_event" ] }, "segmentId": { "description": "Segment id — required when triggerType is segment.", "type": "string" }, "segmentName": { "description": "Cached segment display name (optional).", "type": "string" }, "eventName": { "description": "CDP event name — required when triggerType is cdp_event.", "type": "string" }, "maxEnrollments": { "description": "Frequency cap: max enrollments per person within enrollmentWindow. Both-or-neither with enrollmentWindow.", "type": "integer", "minimum": 1, "maximum": 9007199254740991 }, "enrollmentWindow": { "description": "Rolling window for the frequency cap.", "type": "string" } }, "additionalProperties": false, "description": "Trigger node config. Exactly one ENTRY node per journey." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "SEND_MESSAGE" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "templateId": { "description": "Approved WhatsApp template id. Resolve ids from the catalog.", "type": "string" }, "templateName": { "type": "string" }, "channel": { "description": "Send channel. Only whatsapp is live today.", "type": "string", "enum": [ "whatsapp", "sms", "email" ] }, "templateBindings": { "description": "Map of template placeholder → variable reference.", "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "type": "string" } }, "channelId": { "description": "Sending WhatsApp channel (WABA) id. Required before publishing.", "type": "string" }, "sendImmediately": { "description": "Deprecated business-hours gate; prefer a preceding DELAY.", "type": "boolean" } }, "additionalProperties": false, "description": "Sends a WhatsApp template." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "CONVERSATION_BLOCK" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "goal": { "type": "string" }, "maxTimeout": { "description": "How long to wait for a reply before timing out.", "type": "string" }, "mode": { "type": "string", "enum": [ "AGENT", "ESCALATE" ] }, "outputs": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "label": { "type": "string" }, "type": { "type": "string", "enum": [ "string", "number", "date", "boolean", "json" ] }, "description": { "type": "string" }, "builtin": { "type": "boolean" } }, "required": [ "id", "label", "type", "builtin" ], "additionalProperties": false } } }, "additionalProperties": false, "description": "Legacy combined wait + AI conversation block." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "WAIT_FOR_REPLY" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "maxTimeout": { "description": "How long to wait for the first reply before timing out.", "type": "string" } }, "additionalProperties": false, "description": "Waits for the person to reply." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "MANAGE_CONVERSATION" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "mode": { "description": "AGENT (AI-led) or ESCALATE (human handoff). Defaults to AGENT.", "type": "string", "enum": [ "AGENT", "ESCALATE" ] }, "inactivityTimeout": { "description": "Optional custom idle window (e.g. '2h', '30m') that overrides the global inactive-conversation close. Resets on each inbound message; after this much silence the node closes the conversation (routes CLOSED). Hard cap 24h; under 30m is allowed but flagged 'not recommended'. Requires the journey-inactivity-timeout flag.", "type": "string" } }, "additionalProperties": false, "description": "Runs the AI-led conversation." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "DISPATCH_EVENT" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "eventName": { "type": "string", "minLength": 1, "description": "CDP event name to record. Must match the CDP name pattern." }, "properties": { "description": "Literal string values, or { var: path } bindings resolved to typed values at dispatch time.", "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "anyOf": [ { "type": "string" }, { "type": "object", "properties": { "var": { "type": "string" } }, "required": [ "var" ], "additionalProperties": false } ] } }, "description": { "type": "string" } }, "required": [ "eventName" ], "additionalProperties": false, "description": "Records a CDP event for the person." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "DELAY" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "mode": { "description": "How the wait is measured. Defaults to duration.", "type": "string", "enum": [ "duration", "until_date", "until_weekday" ] }, "duration": { "description": "For mode duration.", "type": "string" }, "targetAt": { "description": "ISO 8601 instant, for mode until_date.", "type": "string" }, "weekdays": { "description": "ISO weekdays 1=Mon..7=Sun, for mode until_weekday.", "type": "array", "items": { "type": "integer", "minimum": 1, "maximum": 7 } }, "windowStartMinutes": { "type": "integer", "minimum": 0, "maximum": 1439 }, "windowEndMinutes": { "type": "integer", "minimum": 0, "maximum": 1439 }, "timezone": { "description": "IANA timezone. Load-bearing for until_weekday.", "type": "string" }, "description": { "type": "string" } }, "additionalProperties": false, "description": "Pauses the run." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "DECISION" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "logic": { "type": "string", "enum": [ "AND", "OR" ] }, "conditions": { "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "value" }, "selectionPath": { "type": "string", "description": "Dot-path into the run; must start with one of \"engagement.workflowState.\", \"engagement.extracted.\", \"engagement.nodeOutputs.\" (e.g. engagement.workflowState.totalPrice). customer.*, person.*, attributes.* and engagement.context.* are NOT resolvable here." }, "operator": { "type": "string", "enum": [ "eq", "neq", "gt", "lt", "contains", "isSet" ] }, "value": { "type": "string" } }, "required": [ "kind", "selectionPath", "operator", "value" ], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "event" }, "eventName": { "type": "string" }, "subjectSelectionPath": { "type": "string", "description": "Dot-path into the run; must start with one of \"engagement.workflowState.\", \"engagement.extracted.\", \"engagement.nodeOutputs.\" (e.g. engagement.workflowState.totalPrice). customer.*, person.*, attributes.* and engagement.context.* are NOT resolvable here." }, "occurred": { "type": "boolean" } }, "required": [ "kind", "eventName", "subjectSelectionPath", "occurred" ], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "cdp_predicate" }, "term": { "type": "object", "properties": { "attr": { "type": "string", "minLength": 1, "description": "Typed person column, `attributes.`, or `computed.`. See journeys_condition_catalog for the available attributes." }, "type": { "type": "string", "enum": [ "STRING", "NUMBER", "BOOLEAN", "DATE", "JSON", "ARRAY" ], "description": "CDP attribute type. Determines which `op` values are legal — see journeys_condition_catalog." }, "op": { "type": "string", "minLength": 1, "description": "Segments OperatorEnum value (eq | neq | gt | lt | in_last_n | ...). Must be legal for `type` — see journeys_condition_catalog." }, "value": { "description": "Shape depends on `op`: a plain scalar for eq/neq/gt/lt/starts_with/…, an array for in/not_in/contains/not_contains, {from, to} for between, {amount, unit} for in_last_n/in_next_n/more_than_n_ago/more_than_n_from_now, {minAmount, maxAmount, unit} for between_n_and_m_ago, {daysOffset} for exactly_n_from_today. Omit entirely for is_null/is_not_null.", "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" }, { "type": "array", "items": { "anyOf": [ { "type": "string" }, { "type": "number" } ] } }, { "type": "object", "properties": { "from": { "type": "string" }, "to": { "type": "string" } }, "required": [ "from", "to" ], "additionalProperties": false }, { "type": "object", "properties": { "amount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "amount", "unit" ], "additionalProperties": false }, { "type": "object", "properties": { "minAmount": { "type": "integer", "minimum": 0, "maximum": 9999 }, "maxAmount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "minAmount", "maxAmount", "unit" ], "additionalProperties": false }, { "type": "object", "properties": { "daysOffset": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "rollForward": { "type": "object", "properties": { "fromDow": { "type": "integer", "minimum": 0, "maximum": 6 }, "includeDows": { "minItems": 1, "type": "array", "items": { "type": "integer", "minimum": 0, "maximum": 6 } } }, "required": [ "fromDow", "includeDows" ], "additionalProperties": false } }, "required": [ "daysOffset" ], "additionalProperties": false } ] } }, "required": [ "attr", "type", "op" ], "additionalProperties": false, "description": "A single live person/computed predicate term. See journeys_condition_catalog for its shape and the legal operator/value pairing." } }, "required": [ "kind", "term" ], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "cdp_object" }, "objectType": { "type": "string" }, "matchAttr": { "type": "string" }, "matchSelectionPath": { "type": "string", "description": "Dot-path into the run; must start with one of \"engagement.workflowState.\", \"engagement.extracted.\", \"engagement.nodeOutputs.\" (e.g. engagement.workflowState.totalPrice). customer.*, person.*, attributes.* and engagement.context.* are NOT resolvable here." }, "exists": { "type": "boolean" } }, "required": [ "kind", "objectType", "matchAttr", "matchSelectionPath", "exists" ], "additionalProperties": false } ], "description": "One decision condition." } }, "description": { "type": "string" } }, "required": [ "logic", "conditions" ], "additionalProperties": false, "description": "Two-way branch. Emits YES / NO." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "CASE" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "selectionPath": { "type": "string", "description": "Value to switch on; must start with one of \"attributes.\", \"engagement.extracted.\", \"engagement.nodeOutputs.\" (e.g. attributes.plan_tier)." }, "branches": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable branch id; edge handle is case:." }, "value": { "type": "string", "description": "Value matched. Unique within the node." }, "label": { "type": "string", "minLength": 1, "description": "Required. Names the variant in analytics and on canvas." } }, "required": [ "id", "value", "label" ], "additionalProperties": false }, "description": "Up to 10 branches. A case:default handle is always required." }, "description": { "type": "string" } }, "required": [ "selectionPath", "branches" ], "additionalProperties": false, "description": "N-way switch on a person attribute." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "RANDOM_SPLIT" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "arms": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable arm id; edge handle is split:." }, "weight": { "type": "integer", "minimum": 1, "maximum": 100, "description": "Integer percentage. A node's arms must total 100." }, "label": { "type": "string" } }, "required": [ "id", "weight" ], "additionalProperties": false }, "description": "At least 2 and at most 10 arms whose weights total exactly 100. There is no default handle — every roll lands on a declared arm." }, "description": { "type": "string" } }, "required": [ "arms" ], "additionalProperties": false, "description": "Randomly routes each run down one of N weighted arms." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "HTTP_REQUEST" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "method": { "type": "string", "enum": [ "GET", "POST", "PUT", "PATCH", "DELETE" ], "description": "HTTP method." }, "url": { "type": "string", "minLength": 1, "description": "Target URL. Supports {{variable}} placeholders." }, "headers": { "description": "Request headers as key/value pairs.", "type": "array", "items": { "type": "object", "properties": { "key": { "type": "string" }, "value": { "type": "string" } }, "required": [ "key", "value" ], "additionalProperties": false } }, "body": { "description": "Request body. mode none sends no body.", "type": "object", "properties": { "mode": { "type": "string", "enum": [ "none", "json", "raw" ] }, "content": { "type": "string" }, "contentType": { "type": "string" } }, "required": [ "mode" ], "additionalProperties": false }, "credentialId": { "description": "Deprecated/legacy: HttpCredential row id used to authenticate the request. Prefer credentialKey.", "type": "string" }, "credentialKey": { "description": "Logical credential key; the pinned environment selects the secret.", "type": "string" }, "timeoutMs": { "description": "Request timeout in milliseconds. Max 30000 (30s).", "type": "integer", "exclusiveMinimum": 0, "maximum": 30000 }, "maxAttempts": { "description": "Max attempts including the first. Max 5.", "type": "integer", "exclusiveMinimum": 0, "maximum": 5 }, "documentUrlTtlSeconds": { "description": "TTL (seconds, ≤86400) for presigned engagement.documents URLs this node emits. Default 86400.", "type": "integer", "exclusiveMinimum": 0, "maximum": 86400 } }, "required": [ "method", "url" ], "additionalProperties": false, "description": "Calls an external HTTP endpoint. Emits SUCCESS or FAILED." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "EXIT" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "outcome": { "type": "string" }, "nextInitiativeId": { "description": "Chain into another initiative on exit.", "type": "string" } }, "additionalProperties": false, "description": "Terminal node." } }, "required": [ "id", "kind" ], "additionalProperties": false } ] }, "description": "The nodes. Exactly one ENTRY and at least one EXIT are required to publish." }, "edges": { "type": "array", "items": { "type": "object", "properties": { "from": { "type": "string", "description": "Source node id." }, "to": { "type": "string", "description": "Target node id." }, "sourceHandle": { "type": "string", "description": "The emitted signal that activates this edge (e.g. SENT, REPLIED, YES, case:). A handle may wire to at most one node." }, "metadata": { "type": "object", "properties": { "signalCategory": { "type": "string", "enum": [ "lifecycle", "system" ] }, "signalDescription": { "type": "string" } }, "additionalProperties": false } }, "required": [ "from", "to", "sourceHandle" ], "additionalProperties": false, "description": "A connection: node `from` routes to `to` when it emits `sourceHandle`." }, "description": "The connections between node handles." } }, "required": [ "name", "actions", "edges" ], "additionalProperties": false, "description": "The full journey graph." } }, "required": [ "id", "initiativeId", "status", "version", "definition" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } } }, "/api/v1/journeys/{journeyId}/definition": { "get": { "operationId": "journeys_get_definition", "summary": "Get journey definition", "description": "Get a journey's full editable graph (all nodes, their config, and connections) so it can be modified and saved back. Unlike journeys_get, this is the complete authoring shape, not the sanitized public summary.", "tags": [ "Journeys" ], "parameters": [ { "name": "journeyId", "in": "path", "required": true, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "minLength": 1, "description": "A draft journey id, or the initiative id (resolves to its current draft)." } } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "id": { "type": "string", "description": "Journey (workflow version) id." }, "initiativeId": { "type": "string", "description": "The initiative this journey belongs to." }, "status": { "type": "string", "enum": [ "DRAFT", "PUBLISHED", "STOPPED" ], "description": "DRAFT (editable), PUBLISHED (live, frozen), or STOPPED (retired)." }, "version": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Version number within the initiative." }, "definition": { "type": "object", "properties": { "id": { "description": "Journey id; carried for round-trip ergonomics. Optional on create.", "type": "string" }, "name": { "type": "string", "minLength": 1, "description": "Journey name." }, "metadata": { "type": "object", "properties": { "initiativeType": { "type": "string" }, "version": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "cancelOnEvents": { "description": "Cancel an in-flight run when any of these events arrive.", "type": "object", "properties": { "eventNames": { "type": "array", "items": { "type": "string" } } }, "required": [ "eventNames" ], "additionalProperties": false }, "environmentId": { "description": "Pinned environment whose non-secret {{env.*}} values HTTP nodes resolve against. Frozen at publish. The server preserves the stored value when a whole-graph update omits it.", "type": "string" } }, "additionalProperties": false, "description": "Optional journey-level metadata." }, "actions": { "minItems": 1, "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "ENTRY" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "description": { "type": "string" }, "triggerType": { "description": "How people enter: manual (added by an operator or API call), segment (on entering a segment), or cdp_event (when an event is received). Defaults to manual.", "type": "string", "enum": [ "manual", "segment", "cdp_event" ] }, "segmentId": { "description": "Segment id — required when triggerType is segment.", "type": "string" }, "segmentName": { "description": "Cached segment display name (optional).", "type": "string" }, "eventName": { "description": "CDP event name — required when triggerType is cdp_event.", "type": "string" }, "maxEnrollments": { "description": "Frequency cap: max enrollments per person within enrollmentWindow. Both-or-neither with enrollmentWindow.", "type": "integer", "minimum": 1, "maximum": 9007199254740991 }, "enrollmentWindow": { "description": "Rolling window for the frequency cap.", "type": "string" } }, "additionalProperties": false, "description": "Trigger node config. Exactly one ENTRY node per journey." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "SEND_MESSAGE" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "templateId": { "description": "Approved WhatsApp template id. Resolve ids from the catalog.", "type": "string" }, "templateName": { "type": "string" }, "channel": { "description": "Send channel. Only whatsapp is live today.", "type": "string", "enum": [ "whatsapp", "sms", "email" ] }, "templateBindings": { "description": "Map of template placeholder → variable reference.", "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "type": "string" } }, "channelId": { "description": "Sending WhatsApp channel (WABA) id. Required before publishing.", "type": "string" }, "sendImmediately": { "description": "Deprecated business-hours gate; prefer a preceding DELAY.", "type": "boolean" } }, "additionalProperties": false, "description": "Sends a WhatsApp template." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "CONVERSATION_BLOCK" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "goal": { "type": "string" }, "maxTimeout": { "description": "How long to wait for a reply before timing out.", "type": "string" }, "mode": { "type": "string", "enum": [ "AGENT", "ESCALATE" ] }, "outputs": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "label": { "type": "string" }, "type": { "type": "string", "enum": [ "string", "number", "date", "boolean", "json" ] }, "description": { "type": "string" }, "builtin": { "type": "boolean" } }, "required": [ "id", "label", "type", "builtin" ], "additionalProperties": false } } }, "additionalProperties": false, "description": "Legacy combined wait + AI conversation block." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "WAIT_FOR_REPLY" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "maxTimeout": { "description": "How long to wait for the first reply before timing out.", "type": "string" } }, "additionalProperties": false, "description": "Waits for the person to reply." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "MANAGE_CONVERSATION" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "mode": { "description": "AGENT (AI-led) or ESCALATE (human handoff). Defaults to AGENT.", "type": "string", "enum": [ "AGENT", "ESCALATE" ] }, "inactivityTimeout": { "description": "Optional custom idle window (e.g. '2h', '30m') that overrides the global inactive-conversation close. Resets on each inbound message; after this much silence the node closes the conversation (routes CLOSED). Hard cap 24h; under 30m is allowed but flagged 'not recommended'. Requires the journey-inactivity-timeout flag.", "type": "string" } }, "additionalProperties": false, "description": "Runs the AI-led conversation." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "DISPATCH_EVENT" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "eventName": { "type": "string", "minLength": 1, "description": "CDP event name to record. Must match the CDP name pattern." }, "properties": { "description": "Literal string values, or { var: path } bindings resolved to typed values at dispatch time.", "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "anyOf": [ { "type": "string" }, { "type": "object", "properties": { "var": { "type": "string" } }, "required": [ "var" ], "additionalProperties": false } ] } }, "description": { "type": "string" } }, "required": [ "eventName" ], "additionalProperties": false, "description": "Records a CDP event for the person." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "DELAY" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "mode": { "description": "How the wait is measured. Defaults to duration.", "type": "string", "enum": [ "duration", "until_date", "until_weekday" ] }, "duration": { "description": "For mode duration.", "type": "string" }, "targetAt": { "description": "ISO 8601 instant, for mode until_date.", "type": "string" }, "weekdays": { "description": "ISO weekdays 1=Mon..7=Sun, for mode until_weekday.", "type": "array", "items": { "type": "integer", "minimum": 1, "maximum": 7 } }, "windowStartMinutes": { "type": "integer", "minimum": 0, "maximum": 1439 }, "windowEndMinutes": { "type": "integer", "minimum": 0, "maximum": 1439 }, "timezone": { "description": "IANA timezone. Load-bearing for until_weekday.", "type": "string" }, "description": { "type": "string" } }, "additionalProperties": false, "description": "Pauses the run." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "DECISION" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "logic": { "type": "string", "enum": [ "AND", "OR" ] }, "conditions": { "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "value" }, "selectionPath": { "type": "string", "description": "Dot-path into the run; must start with one of \"engagement.workflowState.\", \"engagement.extracted.\", \"engagement.nodeOutputs.\" (e.g. engagement.workflowState.totalPrice). customer.*, person.*, attributes.* and engagement.context.* are NOT resolvable here." }, "operator": { "type": "string", "enum": [ "eq", "neq", "gt", "lt", "contains", "isSet" ] }, "value": { "type": "string" } }, "required": [ "kind", "selectionPath", "operator", "value" ], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "event" }, "eventName": { "type": "string" }, "subjectSelectionPath": { "type": "string", "description": "Dot-path into the run; must start with one of \"engagement.workflowState.\", \"engagement.extracted.\", \"engagement.nodeOutputs.\" (e.g. engagement.workflowState.totalPrice). customer.*, person.*, attributes.* and engagement.context.* are NOT resolvable here." }, "occurred": { "type": "boolean" } }, "required": [ "kind", "eventName", "subjectSelectionPath", "occurred" ], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "cdp_predicate" }, "term": { "type": "object", "properties": { "attr": { "type": "string", "minLength": 1, "description": "Typed person column, `attributes.`, or `computed.`. See journeys_condition_catalog for the available attributes." }, "type": { "type": "string", "enum": [ "STRING", "NUMBER", "BOOLEAN", "DATE", "JSON", "ARRAY" ], "description": "CDP attribute type. Determines which `op` values are legal — see journeys_condition_catalog." }, "op": { "type": "string", "minLength": 1, "description": "Segments OperatorEnum value (eq | neq | gt | lt | in_last_n | ...). Must be legal for `type` — see journeys_condition_catalog." }, "value": { "description": "Shape depends on `op`: a plain scalar for eq/neq/gt/lt/starts_with/…, an array for in/not_in/contains/not_contains, {from, to} for between, {amount, unit} for in_last_n/in_next_n/more_than_n_ago/more_than_n_from_now, {minAmount, maxAmount, unit} for between_n_and_m_ago, {daysOffset} for exactly_n_from_today. Omit entirely for is_null/is_not_null.", "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" }, { "type": "array", "items": { "anyOf": [ { "type": "string" }, { "type": "number" } ] } }, { "type": "object", "properties": { "from": { "type": "string" }, "to": { "type": "string" } }, "required": [ "from", "to" ], "additionalProperties": false }, { "type": "object", "properties": { "amount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "amount", "unit" ], "additionalProperties": false }, { "type": "object", "properties": { "minAmount": { "type": "integer", "minimum": 0, "maximum": 9999 }, "maxAmount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "minAmount", "maxAmount", "unit" ], "additionalProperties": false }, { "type": "object", "properties": { "daysOffset": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "rollForward": { "type": "object", "properties": { "fromDow": { "type": "integer", "minimum": 0, "maximum": 6 }, "includeDows": { "minItems": 1, "type": "array", "items": { "type": "integer", "minimum": 0, "maximum": 6 } } }, "required": [ "fromDow", "includeDows" ], "additionalProperties": false } }, "required": [ "daysOffset" ], "additionalProperties": false } ] } }, "required": [ "attr", "type", "op" ], "additionalProperties": false, "description": "A single live person/computed predicate term. See journeys_condition_catalog for its shape and the legal operator/value pairing." } }, "required": [ "kind", "term" ], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "cdp_object" }, "objectType": { "type": "string" }, "matchAttr": { "type": "string" }, "matchSelectionPath": { "type": "string", "description": "Dot-path into the run; must start with one of \"engagement.workflowState.\", \"engagement.extracted.\", \"engagement.nodeOutputs.\" (e.g. engagement.workflowState.totalPrice). customer.*, person.*, attributes.* and engagement.context.* are NOT resolvable here." }, "exists": { "type": "boolean" } }, "required": [ "kind", "objectType", "matchAttr", "matchSelectionPath", "exists" ], "additionalProperties": false } ], "description": "One decision condition." } }, "description": { "type": "string" } }, "required": [ "logic", "conditions" ], "additionalProperties": false, "description": "Two-way branch. Emits YES / NO." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "CASE" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "selectionPath": { "type": "string", "description": "Value to switch on; must start with one of \"attributes.\", \"engagement.extracted.\", \"engagement.nodeOutputs.\" (e.g. attributes.plan_tier)." }, "branches": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable branch id; edge handle is case:." }, "value": { "type": "string", "description": "Value matched. Unique within the node." }, "label": { "type": "string", "minLength": 1, "description": "Required. Names the variant in analytics and on canvas." } }, "required": [ "id", "value", "label" ], "additionalProperties": false }, "description": "Up to 10 branches. A case:default handle is always required." }, "description": { "type": "string" } }, "required": [ "selectionPath", "branches" ], "additionalProperties": false, "description": "N-way switch on a person attribute." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "RANDOM_SPLIT" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "arms": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable arm id; edge handle is split:." }, "weight": { "type": "integer", "minimum": 1, "maximum": 100, "description": "Integer percentage. A node's arms must total 100." }, "label": { "type": "string" } }, "required": [ "id", "weight" ], "additionalProperties": false }, "description": "At least 2 and at most 10 arms whose weights total exactly 100. There is no default handle — every roll lands on a declared arm." }, "description": { "type": "string" } }, "required": [ "arms" ], "additionalProperties": false, "description": "Randomly routes each run down one of N weighted arms." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "HTTP_REQUEST" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "method": { "type": "string", "enum": [ "GET", "POST", "PUT", "PATCH", "DELETE" ], "description": "HTTP method." }, "url": { "type": "string", "minLength": 1, "description": "Target URL. Supports {{variable}} placeholders." }, "headers": { "description": "Request headers as key/value pairs.", "type": "array", "items": { "type": "object", "properties": { "key": { "type": "string" }, "value": { "type": "string" } }, "required": [ "key", "value" ], "additionalProperties": false } }, "body": { "description": "Request body. mode none sends no body.", "type": "object", "properties": { "mode": { "type": "string", "enum": [ "none", "json", "raw" ] }, "content": { "type": "string" }, "contentType": { "type": "string" } }, "required": [ "mode" ], "additionalProperties": false }, "credentialId": { "description": "Deprecated/legacy: HttpCredential row id used to authenticate the request. Prefer credentialKey.", "type": "string" }, "credentialKey": { "description": "Logical credential key; the pinned environment selects the secret.", "type": "string" }, "timeoutMs": { "description": "Request timeout in milliseconds. Max 30000 (30s).", "type": "integer", "exclusiveMinimum": 0, "maximum": 30000 }, "maxAttempts": { "description": "Max attempts including the first. Max 5.", "type": "integer", "exclusiveMinimum": 0, "maximum": 5 }, "documentUrlTtlSeconds": { "description": "TTL (seconds, ≤86400) for presigned engagement.documents URLs this node emits. Default 86400.", "type": "integer", "exclusiveMinimum": 0, "maximum": 86400 } }, "required": [ "method", "url" ], "additionalProperties": false, "description": "Calls an external HTTP endpoint. Emits SUCCESS or FAILED." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "EXIT" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "outcome": { "type": "string" }, "nextInitiativeId": { "description": "Chain into another initiative on exit.", "type": "string" } }, "additionalProperties": false, "description": "Terminal node." } }, "required": [ "id", "kind" ], "additionalProperties": false } ] }, "description": "The nodes. Exactly one ENTRY and at least one EXIT are required to publish." }, "edges": { "type": "array", "items": { "type": "object", "properties": { "from": { "type": "string", "description": "Source node id." }, "to": { "type": "string", "description": "Target node id." }, "sourceHandle": { "type": "string", "description": "The emitted signal that activates this edge (e.g. SENT, REPLIED, YES, case:). A handle may wire to at most one node." }, "metadata": { "type": "object", "properties": { "signalCategory": { "type": "string", "enum": [ "lifecycle", "system" ] }, "signalDescription": { "type": "string" } }, "additionalProperties": false } }, "required": [ "from", "to", "sourceHandle" ], "additionalProperties": false, "description": "A connection: node `from` routes to `to` when it emits `sourceHandle`." }, "description": "The connections between node handles." } }, "required": [ "name", "actions", "edges" ], "additionalProperties": false, "description": "The full journey graph." } }, "required": [ "id", "initiativeId", "status", "version", "definition" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } } }, "/api/v1/journeys/{journeyId}/edges": { "delete": { "operationId": "journeys_disconnect_nodes", "summary": "Disconnect nodes", "description": "Remove edges leaving a node. Narrow by target and/or handle; with neither, all outgoing edges from the node are removed.", "tags": [ "Journeys" ], "parameters": [ { "name": "journeyId", "in": "path", "required": true, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "minLength": 1, "description": "A draft journey id, or the initiative id (resolves to its current draft)." } }, { "name": "from", "in": "query", "required": true, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "minLength": 1, "description": "Source node id whose edges to remove." } }, { "name": "to", "in": "query", "required": false, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "description": "Only edges to this target.", "type": "string", "minLength": 1 } }, { "name": "sourceHandle", "in": "query", "required": false, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "description": "Only edges on this handle.", "type": "string", "minLength": 1 } } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "id": { "type": "string", "description": "Journey (workflow version) id." }, "initiativeId": { "type": "string", "description": "The initiative this journey belongs to." }, "status": { "type": "string", "enum": [ "DRAFT", "PUBLISHED", "STOPPED" ], "description": "DRAFT (editable), PUBLISHED (live, frozen), or STOPPED (retired)." }, "version": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Version number within the initiative." }, "definition": { "type": "object", "properties": { "id": { "description": "Journey id; carried for round-trip ergonomics. Optional on create.", "type": "string" }, "name": { "type": "string", "minLength": 1, "description": "Journey name." }, "metadata": { "type": "object", "properties": { "initiativeType": { "type": "string" }, "version": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "cancelOnEvents": { "description": "Cancel an in-flight run when any of these events arrive.", "type": "object", "properties": { "eventNames": { "type": "array", "items": { "type": "string" } } }, "required": [ "eventNames" ], "additionalProperties": false }, "environmentId": { "description": "Pinned environment whose non-secret {{env.*}} values HTTP nodes resolve against. Frozen at publish. The server preserves the stored value when a whole-graph update omits it.", "type": "string" } }, "additionalProperties": false, "description": "Optional journey-level metadata." }, "actions": { "minItems": 1, "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "ENTRY" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "description": { "type": "string" }, "triggerType": { "description": "How people enter: manual (added by an operator or API call), segment (on entering a segment), or cdp_event (when an event is received). Defaults to manual.", "type": "string", "enum": [ "manual", "segment", "cdp_event" ] }, "segmentId": { "description": "Segment id — required when triggerType is segment.", "type": "string" }, "segmentName": { "description": "Cached segment display name (optional).", "type": "string" }, "eventName": { "description": "CDP event name — required when triggerType is cdp_event.", "type": "string" }, "maxEnrollments": { "description": "Frequency cap: max enrollments per person within enrollmentWindow. Both-or-neither with enrollmentWindow.", "type": "integer", "minimum": 1, "maximum": 9007199254740991 }, "enrollmentWindow": { "description": "Rolling window for the frequency cap.", "type": "string" } }, "additionalProperties": false, "description": "Trigger node config. Exactly one ENTRY node per journey." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "SEND_MESSAGE" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "templateId": { "description": "Approved WhatsApp template id. Resolve ids from the catalog.", "type": "string" }, "templateName": { "type": "string" }, "channel": { "description": "Send channel. Only whatsapp is live today.", "type": "string", "enum": [ "whatsapp", "sms", "email" ] }, "templateBindings": { "description": "Map of template placeholder → variable reference.", "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "type": "string" } }, "channelId": { "description": "Sending WhatsApp channel (WABA) id. Required before publishing.", "type": "string" }, "sendImmediately": { "description": "Deprecated business-hours gate; prefer a preceding DELAY.", "type": "boolean" } }, "additionalProperties": false, "description": "Sends a WhatsApp template." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "CONVERSATION_BLOCK" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "goal": { "type": "string" }, "maxTimeout": { "description": "How long to wait for a reply before timing out.", "type": "string" }, "mode": { "type": "string", "enum": [ "AGENT", "ESCALATE" ] }, "outputs": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "label": { "type": "string" }, "type": { "type": "string", "enum": [ "string", "number", "date", "boolean", "json" ] }, "description": { "type": "string" }, "builtin": { "type": "boolean" } }, "required": [ "id", "label", "type", "builtin" ], "additionalProperties": false } } }, "additionalProperties": false, "description": "Legacy combined wait + AI conversation block." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "WAIT_FOR_REPLY" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "maxTimeout": { "description": "How long to wait for the first reply before timing out.", "type": "string" } }, "additionalProperties": false, "description": "Waits for the person to reply." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "MANAGE_CONVERSATION" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "mode": { "description": "AGENT (AI-led) or ESCALATE (human handoff). Defaults to AGENT.", "type": "string", "enum": [ "AGENT", "ESCALATE" ] }, "inactivityTimeout": { "description": "Optional custom idle window (e.g. '2h', '30m') that overrides the global inactive-conversation close. Resets on each inbound message; after this much silence the node closes the conversation (routes CLOSED). Hard cap 24h; under 30m is allowed but flagged 'not recommended'. Requires the journey-inactivity-timeout flag.", "type": "string" } }, "additionalProperties": false, "description": "Runs the AI-led conversation." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "DISPATCH_EVENT" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "eventName": { "type": "string", "minLength": 1, "description": "CDP event name to record. Must match the CDP name pattern." }, "properties": { "description": "Literal string values, or { var: path } bindings resolved to typed values at dispatch time.", "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "anyOf": [ { "type": "string" }, { "type": "object", "properties": { "var": { "type": "string" } }, "required": [ "var" ], "additionalProperties": false } ] } }, "description": { "type": "string" } }, "required": [ "eventName" ], "additionalProperties": false, "description": "Records a CDP event for the person." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "DELAY" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "mode": { "description": "How the wait is measured. Defaults to duration.", "type": "string", "enum": [ "duration", "until_date", "until_weekday" ] }, "duration": { "description": "For mode duration.", "type": "string" }, "targetAt": { "description": "ISO 8601 instant, for mode until_date.", "type": "string" }, "weekdays": { "description": "ISO weekdays 1=Mon..7=Sun, for mode until_weekday.", "type": "array", "items": { "type": "integer", "minimum": 1, "maximum": 7 } }, "windowStartMinutes": { "type": "integer", "minimum": 0, "maximum": 1439 }, "windowEndMinutes": { "type": "integer", "minimum": 0, "maximum": 1439 }, "timezone": { "description": "IANA timezone. Load-bearing for until_weekday.", "type": "string" }, "description": { "type": "string" } }, "additionalProperties": false, "description": "Pauses the run." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "DECISION" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "logic": { "type": "string", "enum": [ "AND", "OR" ] }, "conditions": { "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "value" }, "selectionPath": { "type": "string", "description": "Dot-path into the run; must start with one of \"engagement.workflowState.\", \"engagement.extracted.\", \"engagement.nodeOutputs.\" (e.g. engagement.workflowState.totalPrice). customer.*, person.*, attributes.* and engagement.context.* are NOT resolvable here." }, "operator": { "type": "string", "enum": [ "eq", "neq", "gt", "lt", "contains", "isSet" ] }, "value": { "type": "string" } }, "required": [ "kind", "selectionPath", "operator", "value" ], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "event" }, "eventName": { "type": "string" }, "subjectSelectionPath": { "type": "string", "description": "Dot-path into the run; must start with one of \"engagement.workflowState.\", \"engagement.extracted.\", \"engagement.nodeOutputs.\" (e.g. engagement.workflowState.totalPrice). customer.*, person.*, attributes.* and engagement.context.* are NOT resolvable here." }, "occurred": { "type": "boolean" } }, "required": [ "kind", "eventName", "subjectSelectionPath", "occurred" ], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "cdp_predicate" }, "term": { "type": "object", "properties": { "attr": { "type": "string", "minLength": 1, "description": "Typed person column, `attributes.`, or `computed.`. See journeys_condition_catalog for the available attributes." }, "type": { "type": "string", "enum": [ "STRING", "NUMBER", "BOOLEAN", "DATE", "JSON", "ARRAY" ], "description": "CDP attribute type. Determines which `op` values are legal — see journeys_condition_catalog." }, "op": { "type": "string", "minLength": 1, "description": "Segments OperatorEnum value (eq | neq | gt | lt | in_last_n | ...). Must be legal for `type` — see journeys_condition_catalog." }, "value": { "description": "Shape depends on `op`: a plain scalar for eq/neq/gt/lt/starts_with/…, an array for in/not_in/contains/not_contains, {from, to} for between, {amount, unit} for in_last_n/in_next_n/more_than_n_ago/more_than_n_from_now, {minAmount, maxAmount, unit} for between_n_and_m_ago, {daysOffset} for exactly_n_from_today. Omit entirely for is_null/is_not_null.", "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" }, { "type": "array", "items": { "anyOf": [ { "type": "string" }, { "type": "number" } ] } }, { "type": "object", "properties": { "from": { "type": "string" }, "to": { "type": "string" } }, "required": [ "from", "to" ], "additionalProperties": false }, { "type": "object", "properties": { "amount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "amount", "unit" ], "additionalProperties": false }, { "type": "object", "properties": { "minAmount": { "type": "integer", "minimum": 0, "maximum": 9999 }, "maxAmount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "minAmount", "maxAmount", "unit" ], "additionalProperties": false }, { "type": "object", "properties": { "daysOffset": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "rollForward": { "type": "object", "properties": { "fromDow": { "type": "integer", "minimum": 0, "maximum": 6 }, "includeDows": { "minItems": 1, "type": "array", "items": { "type": "integer", "minimum": 0, "maximum": 6 } } }, "required": [ "fromDow", "includeDows" ], "additionalProperties": false } }, "required": [ "daysOffset" ], "additionalProperties": false } ] } }, "required": [ "attr", "type", "op" ], "additionalProperties": false, "description": "A single live person/computed predicate term. See journeys_condition_catalog for its shape and the legal operator/value pairing." } }, "required": [ "kind", "term" ], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "cdp_object" }, "objectType": { "type": "string" }, "matchAttr": { "type": "string" }, "matchSelectionPath": { "type": "string", "description": "Dot-path into the run; must start with one of \"engagement.workflowState.\", \"engagement.extracted.\", \"engagement.nodeOutputs.\" (e.g. engagement.workflowState.totalPrice). customer.*, person.*, attributes.* and engagement.context.* are NOT resolvable here." }, "exists": { "type": "boolean" } }, "required": [ "kind", "objectType", "matchAttr", "matchSelectionPath", "exists" ], "additionalProperties": false } ], "description": "One decision condition." } }, "description": { "type": "string" } }, "required": [ "logic", "conditions" ], "additionalProperties": false, "description": "Two-way branch. Emits YES / NO." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "CASE" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "selectionPath": { "type": "string", "description": "Value to switch on; must start with one of \"attributes.\", \"engagement.extracted.\", \"engagement.nodeOutputs.\" (e.g. attributes.plan_tier)." }, "branches": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable branch id; edge handle is case:." }, "value": { "type": "string", "description": "Value matched. Unique within the node." }, "label": { "type": "string", "minLength": 1, "description": "Required. Names the variant in analytics and on canvas." } }, "required": [ "id", "value", "label" ], "additionalProperties": false }, "description": "Up to 10 branches. A case:default handle is always required." }, "description": { "type": "string" } }, "required": [ "selectionPath", "branches" ], "additionalProperties": false, "description": "N-way switch on a person attribute." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "RANDOM_SPLIT" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "arms": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable arm id; edge handle is split:." }, "weight": { "type": "integer", "minimum": 1, "maximum": 100, "description": "Integer percentage. A node's arms must total 100." }, "label": { "type": "string" } }, "required": [ "id", "weight" ], "additionalProperties": false }, "description": "At least 2 and at most 10 arms whose weights total exactly 100. There is no default handle — every roll lands on a declared arm." }, "description": { "type": "string" } }, "required": [ "arms" ], "additionalProperties": false, "description": "Randomly routes each run down one of N weighted arms." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "HTTP_REQUEST" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "method": { "type": "string", "enum": [ "GET", "POST", "PUT", "PATCH", "DELETE" ], "description": "HTTP method." }, "url": { "type": "string", "minLength": 1, "description": "Target URL. Supports {{variable}} placeholders." }, "headers": { "description": "Request headers as key/value pairs.", "type": "array", "items": { "type": "object", "properties": { "key": { "type": "string" }, "value": { "type": "string" } }, "required": [ "key", "value" ], "additionalProperties": false } }, "body": { "description": "Request body. mode none sends no body.", "type": "object", "properties": { "mode": { "type": "string", "enum": [ "none", "json", "raw" ] }, "content": { "type": "string" }, "contentType": { "type": "string" } }, "required": [ "mode" ], "additionalProperties": false }, "credentialId": { "description": "Deprecated/legacy: HttpCredential row id used to authenticate the request. Prefer credentialKey.", "type": "string" }, "credentialKey": { "description": "Logical credential key; the pinned environment selects the secret.", "type": "string" }, "timeoutMs": { "description": "Request timeout in milliseconds. Max 30000 (30s).", "type": "integer", "exclusiveMinimum": 0, "maximum": 30000 }, "maxAttempts": { "description": "Max attempts including the first. Max 5.", "type": "integer", "exclusiveMinimum": 0, "maximum": 5 }, "documentUrlTtlSeconds": { "description": "TTL (seconds, ≤86400) for presigned engagement.documents URLs this node emits. Default 86400.", "type": "integer", "exclusiveMinimum": 0, "maximum": 86400 } }, "required": [ "method", "url" ], "additionalProperties": false, "description": "Calls an external HTTP endpoint. Emits SUCCESS or FAILED." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "EXIT" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "outcome": { "type": "string" }, "nextInitiativeId": { "description": "Chain into another initiative on exit.", "type": "string" } }, "additionalProperties": false, "description": "Terminal node." } }, "required": [ "id", "kind" ], "additionalProperties": false } ] }, "description": "The nodes. Exactly one ENTRY and at least one EXIT are required to publish." }, "edges": { "type": "array", "items": { "type": "object", "properties": { "from": { "type": "string", "description": "Source node id." }, "to": { "type": "string", "description": "Target node id." }, "sourceHandle": { "type": "string", "description": "The emitted signal that activates this edge (e.g. SENT, REPLIED, YES, case:). A handle may wire to at most one node." }, "metadata": { "type": "object", "properties": { "signalCategory": { "type": "string", "enum": [ "lifecycle", "system" ] }, "signalDescription": { "type": "string" } }, "additionalProperties": false } }, "required": [ "from", "to", "sourceHandle" ], "additionalProperties": false, "description": "A connection: node `from` routes to `to` when it emits `sourceHandle`." }, "description": "The connections between node handles." } }, "required": [ "name", "actions", "edges" ], "additionalProperties": false, "description": "The full journey graph." } }, "required": [ "id", "initiativeId", "status", "version", "definition" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } }, "post": { "operationId": "journeys_connect_nodes", "summary": "Connect nodes", "description": "Wire an edge from one node to another on a given output handle (the emitted signal, e.g. SENT, REPLIED, YES, case:). A handle can wire to only one node.", "tags": [ "Journeys" ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "from": { "type": "string", "minLength": 1, "description": "Source node id." }, "to": { "type": "string", "minLength": 1, "description": "Target node id." }, "sourceHandle": { "type": "string", "minLength": 1, "description": "The source node output handle this edge fires on." } }, "required": [ "from", "to", "sourceHandle" ] } } } }, "parameters": [ { "name": "journeyId", "in": "path", "required": true, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "minLength": 1, "description": "A draft journey id, or the initiative id (resolves to its current draft)." } } ], "responses": { "201": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "id": { "type": "string", "description": "Journey (workflow version) id." }, "initiativeId": { "type": "string", "description": "The initiative this journey belongs to." }, "status": { "type": "string", "enum": [ "DRAFT", "PUBLISHED", "STOPPED" ], "description": "DRAFT (editable), PUBLISHED (live, frozen), or STOPPED (retired)." }, "version": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Version number within the initiative." }, "definition": { "type": "object", "properties": { "id": { "description": "Journey id; carried for round-trip ergonomics. Optional on create.", "type": "string" }, "name": { "type": "string", "minLength": 1, "description": "Journey name." }, "metadata": { "type": "object", "properties": { "initiativeType": { "type": "string" }, "version": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "cancelOnEvents": { "description": "Cancel an in-flight run when any of these events arrive.", "type": "object", "properties": { "eventNames": { "type": "array", "items": { "type": "string" } } }, "required": [ "eventNames" ], "additionalProperties": false }, "environmentId": { "description": "Pinned environment whose non-secret {{env.*}} values HTTP nodes resolve against. Frozen at publish. The server preserves the stored value when a whole-graph update omits it.", "type": "string" } }, "additionalProperties": false, "description": "Optional journey-level metadata." }, "actions": { "minItems": 1, "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "ENTRY" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "description": { "type": "string" }, "triggerType": { "description": "How people enter: manual (added by an operator or API call), segment (on entering a segment), or cdp_event (when an event is received). Defaults to manual.", "type": "string", "enum": [ "manual", "segment", "cdp_event" ] }, "segmentId": { "description": "Segment id — required when triggerType is segment.", "type": "string" }, "segmentName": { "description": "Cached segment display name (optional).", "type": "string" }, "eventName": { "description": "CDP event name — required when triggerType is cdp_event.", "type": "string" }, "maxEnrollments": { "description": "Frequency cap: max enrollments per person within enrollmentWindow. Both-or-neither with enrollmentWindow.", "type": "integer", "minimum": 1, "maximum": 9007199254740991 }, "enrollmentWindow": { "description": "Rolling window for the frequency cap.", "type": "string" } }, "additionalProperties": false, "description": "Trigger node config. Exactly one ENTRY node per journey." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "SEND_MESSAGE" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "templateId": { "description": "Approved WhatsApp template id. Resolve ids from the catalog.", "type": "string" }, "templateName": { "type": "string" }, "channel": { "description": "Send channel. Only whatsapp is live today.", "type": "string", "enum": [ "whatsapp", "sms", "email" ] }, "templateBindings": { "description": "Map of template placeholder → variable reference.", "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "type": "string" } }, "channelId": { "description": "Sending WhatsApp channel (WABA) id. Required before publishing.", "type": "string" }, "sendImmediately": { "description": "Deprecated business-hours gate; prefer a preceding DELAY.", "type": "boolean" } }, "additionalProperties": false, "description": "Sends a WhatsApp template." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "CONVERSATION_BLOCK" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "goal": { "type": "string" }, "maxTimeout": { "description": "How long to wait for a reply before timing out.", "type": "string" }, "mode": { "type": "string", "enum": [ "AGENT", "ESCALATE" ] }, "outputs": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "label": { "type": "string" }, "type": { "type": "string", "enum": [ "string", "number", "date", "boolean", "json" ] }, "description": { "type": "string" }, "builtin": { "type": "boolean" } }, "required": [ "id", "label", "type", "builtin" ], "additionalProperties": false } } }, "additionalProperties": false, "description": "Legacy combined wait + AI conversation block." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "WAIT_FOR_REPLY" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "maxTimeout": { "description": "How long to wait for the first reply before timing out.", "type": "string" } }, "additionalProperties": false, "description": "Waits for the person to reply." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "MANAGE_CONVERSATION" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "mode": { "description": "AGENT (AI-led) or ESCALATE (human handoff). Defaults to AGENT.", "type": "string", "enum": [ "AGENT", "ESCALATE" ] }, "inactivityTimeout": { "description": "Optional custom idle window (e.g. '2h', '30m') that overrides the global inactive-conversation close. Resets on each inbound message; after this much silence the node closes the conversation (routes CLOSED). Hard cap 24h; under 30m is allowed but flagged 'not recommended'. Requires the journey-inactivity-timeout flag.", "type": "string" } }, "additionalProperties": false, "description": "Runs the AI-led conversation." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "DISPATCH_EVENT" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "eventName": { "type": "string", "minLength": 1, "description": "CDP event name to record. Must match the CDP name pattern." }, "properties": { "description": "Literal string values, or { var: path } bindings resolved to typed values at dispatch time.", "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "anyOf": [ { "type": "string" }, { "type": "object", "properties": { "var": { "type": "string" } }, "required": [ "var" ], "additionalProperties": false } ] } }, "description": { "type": "string" } }, "required": [ "eventName" ], "additionalProperties": false, "description": "Records a CDP event for the person." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "DELAY" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "mode": { "description": "How the wait is measured. Defaults to duration.", "type": "string", "enum": [ "duration", "until_date", "until_weekday" ] }, "duration": { "description": "For mode duration.", "type": "string" }, "targetAt": { "description": "ISO 8601 instant, for mode until_date.", "type": "string" }, "weekdays": { "description": "ISO weekdays 1=Mon..7=Sun, for mode until_weekday.", "type": "array", "items": { "type": "integer", "minimum": 1, "maximum": 7 } }, "windowStartMinutes": { "type": "integer", "minimum": 0, "maximum": 1439 }, "windowEndMinutes": { "type": "integer", "minimum": 0, "maximum": 1439 }, "timezone": { "description": "IANA timezone. Load-bearing for until_weekday.", "type": "string" }, "description": { "type": "string" } }, "additionalProperties": false, "description": "Pauses the run." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "DECISION" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "logic": { "type": "string", "enum": [ "AND", "OR" ] }, "conditions": { "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "value" }, "selectionPath": { "type": "string", "description": "Dot-path into the run; must start with one of \"engagement.workflowState.\", \"engagement.extracted.\", \"engagement.nodeOutputs.\" (e.g. engagement.workflowState.totalPrice). customer.*, person.*, attributes.* and engagement.context.* are NOT resolvable here." }, "operator": { "type": "string", "enum": [ "eq", "neq", "gt", "lt", "contains", "isSet" ] }, "value": { "type": "string" } }, "required": [ "kind", "selectionPath", "operator", "value" ], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "event" }, "eventName": { "type": "string" }, "subjectSelectionPath": { "type": "string", "description": "Dot-path into the run; must start with one of \"engagement.workflowState.\", \"engagement.extracted.\", \"engagement.nodeOutputs.\" (e.g. engagement.workflowState.totalPrice). customer.*, person.*, attributes.* and engagement.context.* are NOT resolvable here." }, "occurred": { "type": "boolean" } }, "required": [ "kind", "eventName", "subjectSelectionPath", "occurred" ], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "cdp_predicate" }, "term": { "type": "object", "properties": { "attr": { "type": "string", "minLength": 1, "description": "Typed person column, `attributes.`, or `computed.`. See journeys_condition_catalog for the available attributes." }, "type": { "type": "string", "enum": [ "STRING", "NUMBER", "BOOLEAN", "DATE", "JSON", "ARRAY" ], "description": "CDP attribute type. Determines which `op` values are legal — see journeys_condition_catalog." }, "op": { "type": "string", "minLength": 1, "description": "Segments OperatorEnum value (eq | neq | gt | lt | in_last_n | ...). Must be legal for `type` — see journeys_condition_catalog." }, "value": { "description": "Shape depends on `op`: a plain scalar for eq/neq/gt/lt/starts_with/…, an array for in/not_in/contains/not_contains, {from, to} for between, {amount, unit} for in_last_n/in_next_n/more_than_n_ago/more_than_n_from_now, {minAmount, maxAmount, unit} for between_n_and_m_ago, {daysOffset} for exactly_n_from_today. Omit entirely for is_null/is_not_null.", "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" }, { "type": "array", "items": { "anyOf": [ { "type": "string" }, { "type": "number" } ] } }, { "type": "object", "properties": { "from": { "type": "string" }, "to": { "type": "string" } }, "required": [ "from", "to" ], "additionalProperties": false }, { "type": "object", "properties": { "amount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "amount", "unit" ], "additionalProperties": false }, { "type": "object", "properties": { "minAmount": { "type": "integer", "minimum": 0, "maximum": 9999 }, "maxAmount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "minAmount", "maxAmount", "unit" ], "additionalProperties": false }, { "type": "object", "properties": { "daysOffset": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "rollForward": { "type": "object", "properties": { "fromDow": { "type": "integer", "minimum": 0, "maximum": 6 }, "includeDows": { "minItems": 1, "type": "array", "items": { "type": "integer", "minimum": 0, "maximum": 6 } } }, "required": [ "fromDow", "includeDows" ], "additionalProperties": false } }, "required": [ "daysOffset" ], "additionalProperties": false } ] } }, "required": [ "attr", "type", "op" ], "additionalProperties": false, "description": "A single live person/computed predicate term. See journeys_condition_catalog for its shape and the legal operator/value pairing." } }, "required": [ "kind", "term" ], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "cdp_object" }, "objectType": { "type": "string" }, "matchAttr": { "type": "string" }, "matchSelectionPath": { "type": "string", "description": "Dot-path into the run; must start with one of \"engagement.workflowState.\", \"engagement.extracted.\", \"engagement.nodeOutputs.\" (e.g. engagement.workflowState.totalPrice). customer.*, person.*, attributes.* and engagement.context.* are NOT resolvable here." }, "exists": { "type": "boolean" } }, "required": [ "kind", "objectType", "matchAttr", "matchSelectionPath", "exists" ], "additionalProperties": false } ], "description": "One decision condition." } }, "description": { "type": "string" } }, "required": [ "logic", "conditions" ], "additionalProperties": false, "description": "Two-way branch. Emits YES / NO." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "CASE" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "selectionPath": { "type": "string", "description": "Value to switch on; must start with one of \"attributes.\", \"engagement.extracted.\", \"engagement.nodeOutputs.\" (e.g. attributes.plan_tier)." }, "branches": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable branch id; edge handle is case:." }, "value": { "type": "string", "description": "Value matched. Unique within the node." }, "label": { "type": "string", "minLength": 1, "description": "Required. Names the variant in analytics and on canvas." } }, "required": [ "id", "value", "label" ], "additionalProperties": false }, "description": "Up to 10 branches. A case:default handle is always required." }, "description": { "type": "string" } }, "required": [ "selectionPath", "branches" ], "additionalProperties": false, "description": "N-way switch on a person attribute." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "RANDOM_SPLIT" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "arms": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable arm id; edge handle is split:." }, "weight": { "type": "integer", "minimum": 1, "maximum": 100, "description": "Integer percentage. A node's arms must total 100." }, "label": { "type": "string" } }, "required": [ "id", "weight" ], "additionalProperties": false }, "description": "At least 2 and at most 10 arms whose weights total exactly 100. There is no default handle — every roll lands on a declared arm." }, "description": { "type": "string" } }, "required": [ "arms" ], "additionalProperties": false, "description": "Randomly routes each run down one of N weighted arms." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "HTTP_REQUEST" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "method": { "type": "string", "enum": [ "GET", "POST", "PUT", "PATCH", "DELETE" ], "description": "HTTP method." }, "url": { "type": "string", "minLength": 1, "description": "Target URL. Supports {{variable}} placeholders." }, "headers": { "description": "Request headers as key/value pairs.", "type": "array", "items": { "type": "object", "properties": { "key": { "type": "string" }, "value": { "type": "string" } }, "required": [ "key", "value" ], "additionalProperties": false } }, "body": { "description": "Request body. mode none sends no body.", "type": "object", "properties": { "mode": { "type": "string", "enum": [ "none", "json", "raw" ] }, "content": { "type": "string" }, "contentType": { "type": "string" } }, "required": [ "mode" ], "additionalProperties": false }, "credentialId": { "description": "Deprecated/legacy: HttpCredential row id used to authenticate the request. Prefer credentialKey.", "type": "string" }, "credentialKey": { "description": "Logical credential key; the pinned environment selects the secret.", "type": "string" }, "timeoutMs": { "description": "Request timeout in milliseconds. Max 30000 (30s).", "type": "integer", "exclusiveMinimum": 0, "maximum": 30000 }, "maxAttempts": { "description": "Max attempts including the first. Max 5.", "type": "integer", "exclusiveMinimum": 0, "maximum": 5 }, "documentUrlTtlSeconds": { "description": "TTL (seconds, ≤86400) for presigned engagement.documents URLs this node emits. Default 86400.", "type": "integer", "exclusiveMinimum": 0, "maximum": 86400 } }, "required": [ "method", "url" ], "additionalProperties": false, "description": "Calls an external HTTP endpoint. Emits SUCCESS or FAILED." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "EXIT" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "outcome": { "type": "string" }, "nextInitiativeId": { "description": "Chain into another initiative on exit.", "type": "string" } }, "additionalProperties": false, "description": "Terminal node." } }, "required": [ "id", "kind" ], "additionalProperties": false } ] }, "description": "The nodes. Exactly one ENTRY and at least one EXIT are required to publish." }, "edges": { "type": "array", "items": { "type": "object", "properties": { "from": { "type": "string", "description": "Source node id." }, "to": { "type": "string", "description": "Target node id." }, "sourceHandle": { "type": "string", "description": "The emitted signal that activates this edge (e.g. SENT, REPLIED, YES, case:). A handle may wire to at most one node." }, "metadata": { "type": "object", "properties": { "signalCategory": { "type": "string", "enum": [ "lifecycle", "system" ] }, "signalDescription": { "type": "string" } }, "additionalProperties": false } }, "required": [ "from", "to", "sourceHandle" ], "additionalProperties": false, "description": "A connection: node `from` routes to `to` when it emits `sourceHandle`." }, "description": "The connections between node handles." } }, "required": [ "name", "actions", "edges" ], "additionalProperties": false, "description": "The full journey graph." } }, "required": [ "id", "initiativeId", "status", "version", "definition" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } } }, "/api/v1/journeys/{journeyId}/fork": { "post": { "operationId": "journeys_create_draft_from_published", "summary": "Fork journey", "description": "Copy a PUBLISHED journey into a fresh editable draft. The live version keeps running until the new draft is published. Use this to edit a live journey safely.", "tags": [ "Journeys" ], "parameters": [ { "name": "journeyId", "in": "path", "required": true, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "minLength": 1, "description": "A published journey id, or the initiative id (resolves to its live journey)." } } ], "responses": { "201": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "id": { "type": "string", "description": "Journey (workflow version) id." }, "initiativeId": { "type": "string", "description": "The initiative this journey belongs to." }, "status": { "type": "string", "enum": [ "DRAFT", "PUBLISHED", "STOPPED" ], "description": "DRAFT (editable), PUBLISHED (live, frozen), or STOPPED (retired)." }, "version": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Version number within the initiative." }, "definition": { "type": "object", "properties": { "id": { "description": "Journey id; carried for round-trip ergonomics. Optional on create.", "type": "string" }, "name": { "type": "string", "minLength": 1, "description": "Journey name." }, "metadata": { "type": "object", "properties": { "initiativeType": { "type": "string" }, "version": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "cancelOnEvents": { "description": "Cancel an in-flight run when any of these events arrive.", "type": "object", "properties": { "eventNames": { "type": "array", "items": { "type": "string" } } }, "required": [ "eventNames" ], "additionalProperties": false }, "environmentId": { "description": "Pinned environment whose non-secret {{env.*}} values HTTP nodes resolve against. Frozen at publish. The server preserves the stored value when a whole-graph update omits it.", "type": "string" } }, "additionalProperties": false, "description": "Optional journey-level metadata." }, "actions": { "minItems": 1, "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "ENTRY" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "description": { "type": "string" }, "triggerType": { "description": "How people enter: manual (added by an operator or API call), segment (on entering a segment), or cdp_event (when an event is received). Defaults to manual.", "type": "string", "enum": [ "manual", "segment", "cdp_event" ] }, "segmentId": { "description": "Segment id — required when triggerType is segment.", "type": "string" }, "segmentName": { "description": "Cached segment display name (optional).", "type": "string" }, "eventName": { "description": "CDP event name — required when triggerType is cdp_event.", "type": "string" }, "maxEnrollments": { "description": "Frequency cap: max enrollments per person within enrollmentWindow. Both-or-neither with enrollmentWindow.", "type": "integer", "minimum": 1, "maximum": 9007199254740991 }, "enrollmentWindow": { "description": "Rolling window for the frequency cap.", "type": "string" } }, "additionalProperties": false, "description": "Trigger node config. Exactly one ENTRY node per journey." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "SEND_MESSAGE" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "templateId": { "description": "Approved WhatsApp template id. Resolve ids from the catalog.", "type": "string" }, "templateName": { "type": "string" }, "channel": { "description": "Send channel. Only whatsapp is live today.", "type": "string", "enum": [ "whatsapp", "sms", "email" ] }, "templateBindings": { "description": "Map of template placeholder → variable reference.", "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "type": "string" } }, "channelId": { "description": "Sending WhatsApp channel (WABA) id. Required before publishing.", "type": "string" }, "sendImmediately": { "description": "Deprecated business-hours gate; prefer a preceding DELAY.", "type": "boolean" } }, "additionalProperties": false, "description": "Sends a WhatsApp template." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "CONVERSATION_BLOCK" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "goal": { "type": "string" }, "maxTimeout": { "description": "How long to wait for a reply before timing out.", "type": "string" }, "mode": { "type": "string", "enum": [ "AGENT", "ESCALATE" ] }, "outputs": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "label": { "type": "string" }, "type": { "type": "string", "enum": [ "string", "number", "date", "boolean", "json" ] }, "description": { "type": "string" }, "builtin": { "type": "boolean" } }, "required": [ "id", "label", "type", "builtin" ], "additionalProperties": false } } }, "additionalProperties": false, "description": "Legacy combined wait + AI conversation block." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "WAIT_FOR_REPLY" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "maxTimeout": { "description": "How long to wait for the first reply before timing out.", "type": "string" } }, "additionalProperties": false, "description": "Waits for the person to reply." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "MANAGE_CONVERSATION" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "mode": { "description": "AGENT (AI-led) or ESCALATE (human handoff). Defaults to AGENT.", "type": "string", "enum": [ "AGENT", "ESCALATE" ] }, "inactivityTimeout": { "description": "Optional custom idle window (e.g. '2h', '30m') that overrides the global inactive-conversation close. Resets on each inbound message; after this much silence the node closes the conversation (routes CLOSED). Hard cap 24h; under 30m is allowed but flagged 'not recommended'. Requires the journey-inactivity-timeout flag.", "type": "string" } }, "additionalProperties": false, "description": "Runs the AI-led conversation." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "DISPATCH_EVENT" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "eventName": { "type": "string", "minLength": 1, "description": "CDP event name to record. Must match the CDP name pattern." }, "properties": { "description": "Literal string values, or { var: path } bindings resolved to typed values at dispatch time.", "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "anyOf": [ { "type": "string" }, { "type": "object", "properties": { "var": { "type": "string" } }, "required": [ "var" ], "additionalProperties": false } ] } }, "description": { "type": "string" } }, "required": [ "eventName" ], "additionalProperties": false, "description": "Records a CDP event for the person." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "DELAY" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "mode": { "description": "How the wait is measured. Defaults to duration.", "type": "string", "enum": [ "duration", "until_date", "until_weekday" ] }, "duration": { "description": "For mode duration.", "type": "string" }, "targetAt": { "description": "ISO 8601 instant, for mode until_date.", "type": "string" }, "weekdays": { "description": "ISO weekdays 1=Mon..7=Sun, for mode until_weekday.", "type": "array", "items": { "type": "integer", "minimum": 1, "maximum": 7 } }, "windowStartMinutes": { "type": "integer", "minimum": 0, "maximum": 1439 }, "windowEndMinutes": { "type": "integer", "minimum": 0, "maximum": 1439 }, "timezone": { "description": "IANA timezone. Load-bearing for until_weekday.", "type": "string" }, "description": { "type": "string" } }, "additionalProperties": false, "description": "Pauses the run." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "DECISION" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "logic": { "type": "string", "enum": [ "AND", "OR" ] }, "conditions": { "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "value" }, "selectionPath": { "type": "string", "description": "Dot-path into the run; must start with one of \"engagement.workflowState.\", \"engagement.extracted.\", \"engagement.nodeOutputs.\" (e.g. engagement.workflowState.totalPrice). customer.*, person.*, attributes.* and engagement.context.* are NOT resolvable here." }, "operator": { "type": "string", "enum": [ "eq", "neq", "gt", "lt", "contains", "isSet" ] }, "value": { "type": "string" } }, "required": [ "kind", "selectionPath", "operator", "value" ], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "event" }, "eventName": { "type": "string" }, "subjectSelectionPath": { "type": "string", "description": "Dot-path into the run; must start with one of \"engagement.workflowState.\", \"engagement.extracted.\", \"engagement.nodeOutputs.\" (e.g. engagement.workflowState.totalPrice). customer.*, person.*, attributes.* and engagement.context.* are NOT resolvable here." }, "occurred": { "type": "boolean" } }, "required": [ "kind", "eventName", "subjectSelectionPath", "occurred" ], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "cdp_predicate" }, "term": { "type": "object", "properties": { "attr": { "type": "string", "minLength": 1, "description": "Typed person column, `attributes.`, or `computed.`. See journeys_condition_catalog for the available attributes." }, "type": { "type": "string", "enum": [ "STRING", "NUMBER", "BOOLEAN", "DATE", "JSON", "ARRAY" ], "description": "CDP attribute type. Determines which `op` values are legal — see journeys_condition_catalog." }, "op": { "type": "string", "minLength": 1, "description": "Segments OperatorEnum value (eq | neq | gt | lt | in_last_n | ...). Must be legal for `type` — see journeys_condition_catalog." }, "value": { "description": "Shape depends on `op`: a plain scalar for eq/neq/gt/lt/starts_with/…, an array for in/not_in/contains/not_contains, {from, to} for between, {amount, unit} for in_last_n/in_next_n/more_than_n_ago/more_than_n_from_now, {minAmount, maxAmount, unit} for between_n_and_m_ago, {daysOffset} for exactly_n_from_today. Omit entirely for is_null/is_not_null.", "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" }, { "type": "array", "items": { "anyOf": [ { "type": "string" }, { "type": "number" } ] } }, { "type": "object", "properties": { "from": { "type": "string" }, "to": { "type": "string" } }, "required": [ "from", "to" ], "additionalProperties": false }, { "type": "object", "properties": { "amount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "amount", "unit" ], "additionalProperties": false }, { "type": "object", "properties": { "minAmount": { "type": "integer", "minimum": 0, "maximum": 9999 }, "maxAmount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "minAmount", "maxAmount", "unit" ], "additionalProperties": false }, { "type": "object", "properties": { "daysOffset": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "rollForward": { "type": "object", "properties": { "fromDow": { "type": "integer", "minimum": 0, "maximum": 6 }, "includeDows": { "minItems": 1, "type": "array", "items": { "type": "integer", "minimum": 0, "maximum": 6 } } }, "required": [ "fromDow", "includeDows" ], "additionalProperties": false } }, "required": [ "daysOffset" ], "additionalProperties": false } ] } }, "required": [ "attr", "type", "op" ], "additionalProperties": false, "description": "A single live person/computed predicate term. See journeys_condition_catalog for its shape and the legal operator/value pairing." } }, "required": [ "kind", "term" ], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "cdp_object" }, "objectType": { "type": "string" }, "matchAttr": { "type": "string" }, "matchSelectionPath": { "type": "string", "description": "Dot-path into the run; must start with one of \"engagement.workflowState.\", \"engagement.extracted.\", \"engagement.nodeOutputs.\" (e.g. engagement.workflowState.totalPrice). customer.*, person.*, attributes.* and engagement.context.* are NOT resolvable here." }, "exists": { "type": "boolean" } }, "required": [ "kind", "objectType", "matchAttr", "matchSelectionPath", "exists" ], "additionalProperties": false } ], "description": "One decision condition." } }, "description": { "type": "string" } }, "required": [ "logic", "conditions" ], "additionalProperties": false, "description": "Two-way branch. Emits YES / NO." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "CASE" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "selectionPath": { "type": "string", "description": "Value to switch on; must start with one of \"attributes.\", \"engagement.extracted.\", \"engagement.nodeOutputs.\" (e.g. attributes.plan_tier)." }, "branches": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable branch id; edge handle is case:." }, "value": { "type": "string", "description": "Value matched. Unique within the node." }, "label": { "type": "string", "minLength": 1, "description": "Required. Names the variant in analytics and on canvas." } }, "required": [ "id", "value", "label" ], "additionalProperties": false }, "description": "Up to 10 branches. A case:default handle is always required." }, "description": { "type": "string" } }, "required": [ "selectionPath", "branches" ], "additionalProperties": false, "description": "N-way switch on a person attribute." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "RANDOM_SPLIT" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "arms": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable arm id; edge handle is split:." }, "weight": { "type": "integer", "minimum": 1, "maximum": 100, "description": "Integer percentage. A node's arms must total 100." }, "label": { "type": "string" } }, "required": [ "id", "weight" ], "additionalProperties": false }, "description": "At least 2 and at most 10 arms whose weights total exactly 100. There is no default handle — every roll lands on a declared arm." }, "description": { "type": "string" } }, "required": [ "arms" ], "additionalProperties": false, "description": "Randomly routes each run down one of N weighted arms." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "HTTP_REQUEST" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "method": { "type": "string", "enum": [ "GET", "POST", "PUT", "PATCH", "DELETE" ], "description": "HTTP method." }, "url": { "type": "string", "minLength": 1, "description": "Target URL. Supports {{variable}} placeholders." }, "headers": { "description": "Request headers as key/value pairs.", "type": "array", "items": { "type": "object", "properties": { "key": { "type": "string" }, "value": { "type": "string" } }, "required": [ "key", "value" ], "additionalProperties": false } }, "body": { "description": "Request body. mode none sends no body.", "type": "object", "properties": { "mode": { "type": "string", "enum": [ "none", "json", "raw" ] }, "content": { "type": "string" }, "contentType": { "type": "string" } }, "required": [ "mode" ], "additionalProperties": false }, "credentialId": { "description": "Deprecated/legacy: HttpCredential row id used to authenticate the request. Prefer credentialKey.", "type": "string" }, "credentialKey": { "description": "Logical credential key; the pinned environment selects the secret.", "type": "string" }, "timeoutMs": { "description": "Request timeout in milliseconds. Max 30000 (30s).", "type": "integer", "exclusiveMinimum": 0, "maximum": 30000 }, "maxAttempts": { "description": "Max attempts including the first. Max 5.", "type": "integer", "exclusiveMinimum": 0, "maximum": 5 }, "documentUrlTtlSeconds": { "description": "TTL (seconds, ≤86400) for presigned engagement.documents URLs this node emits. Default 86400.", "type": "integer", "exclusiveMinimum": 0, "maximum": 86400 } }, "required": [ "method", "url" ], "additionalProperties": false, "description": "Calls an external HTTP endpoint. Emits SUCCESS or FAILED." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "EXIT" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "outcome": { "type": "string" }, "nextInitiativeId": { "description": "Chain into another initiative on exit.", "type": "string" } }, "additionalProperties": false, "description": "Terminal node." } }, "required": [ "id", "kind" ], "additionalProperties": false } ] }, "description": "The nodes. Exactly one ENTRY and at least one EXIT are required to publish." }, "edges": { "type": "array", "items": { "type": "object", "properties": { "from": { "type": "string", "description": "Source node id." }, "to": { "type": "string", "description": "Target node id." }, "sourceHandle": { "type": "string", "description": "The emitted signal that activates this edge (e.g. SENT, REPLIED, YES, case:). A handle may wire to at most one node." }, "metadata": { "type": "object", "properties": { "signalCategory": { "type": "string", "enum": [ "lifecycle", "system" ] }, "signalDescription": { "type": "string" } }, "additionalProperties": false } }, "required": [ "from", "to", "sourceHandle" ], "additionalProperties": false, "description": "A connection: node `from` routes to `to` when it emits `sourceHandle`." }, "description": "The connections between node handles." } }, "required": [ "name", "actions", "edges" ], "additionalProperties": false, "description": "The full journey graph." } }, "required": [ "id", "initiativeId", "status", "version", "definition" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } } }, "/api/v1/journeys/{journeyId}/message-variables": { "get": { "operationId": "journeys_message_variables", "summary": "Message variable catalog", "description": "List the variables a SEND_MESSAGE template binding can reference for a journey — the same set the builder offers, and the authority on what resolves for THIS journey (when docs and this catalog disagree, trust the catalog). customer.* and person.* are offered for every trigger type (person.* is read live at send time from the identity the enrollment named — personExternalId, which event triggers always carry — and only falls back to a phone/email lookup, blank on zero or several matches, for contacts enrolled without a CDP person). The trigger-aware part is participant data: event-triggered journeys get the event payload under engagement.workflowState.* and no engagement.context.*, segment-triggered journeys get segment output columns under engagement.workflowState.*, and manual/CSV enrollment populates engagement.context.*. Bind a template placeholder to one of the returned `path` values (custom person attributes are `person.`, NOT `attributes.` — that is the DECISION/CASE condition syntax). Pass a journey id or its initiative id.", "tags": [ "Journeys" ], "parameters": [ { "name": "journeyId", "in": "path", "required": true, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "minLength": 1, "description": "A journey id, or the initiative id (resolves to its current draft)." } } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "groups": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "label": { "type": "string" }, "description": { "type": "string" }, "variables": { "type": "array", "items": { "type": "object", "properties": { "key": { "type": "string" }, "label": { "type": "string" }, "path": { "type": "string", "description": "Bind a placeholder to this exact value, e.g. customer.name or engagement.workflowState.plan." }, "description": { "type": "string" } }, "required": [ "key", "label", "path" ], "additionalProperties": false } } }, "required": [ "id", "label", "variables" ], "additionalProperties": false } }, "notes": { "description": "Trigger-specific caveats. Present for event-triggered journeys: explains why the person.* and engagement.context.* groups are absent.", "type": "string" } }, "required": [ "groups" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } } }, "/api/v1/journeys/{journeyId}/nodes": { "post": { "operationId": "journeys_add_node", "summary": "Add node", "description": "Add one node to a draft journey. Positions are optional (auto-laid-out). Wire it up separately with journeys_connect_nodes.", "tags": [ "Journeys" ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "node": { "description": "The whole node object ({\"kind\": …, \"id\": …, …}), nested under this key — never its fields at the top level.", "oneOf": [ { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "ENTRY" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "description": { "type": "string" }, "triggerType": { "description": "How people enter: manual (added by an operator or API call), segment (on entering a segment), or cdp_event (when an event is received). Defaults to manual.", "type": "string", "enum": [ "manual", "segment", "cdp_event" ] }, "segmentId": { "description": "Segment id — required when triggerType is segment.", "type": "string" }, "segmentName": { "description": "Cached segment display name (optional).", "type": "string" }, "eventName": { "description": "CDP event name — required when triggerType is cdp_event.", "type": "string" }, "maxEnrollments": { "description": "Frequency cap: max enrollments per person within enrollmentWindow. Both-or-neither with enrollmentWindow.", "type": "integer", "minimum": 1, "maximum": 9007199254740991 }, "enrollmentWindow": { "description": "Rolling window for the frequency cap.", "type": "string" } }, "description": "Trigger node config. Exactly one ENTRY node per journey." } }, "required": [ "id", "kind" ] }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "SEND_MESSAGE" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "templateId": { "description": "Approved WhatsApp template id. Resolve ids from the catalog.", "type": "string" }, "templateName": { "type": "string" }, "channel": { "description": "Send channel. Only whatsapp is live today.", "type": "string", "enum": [ "whatsapp", "sms", "email" ] }, "templateBindings": { "description": "Map of template placeholder → variable reference.", "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "type": "string" } }, "channelId": { "description": "Sending WhatsApp channel (WABA) id. Required before publishing.", "type": "string" }, "sendImmediately": { "description": "Deprecated business-hours gate; prefer a preceding DELAY.", "type": "boolean" } }, "description": "Sends a WhatsApp template." } }, "required": [ "id", "kind" ] }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "CONVERSATION_BLOCK" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "goal": { "type": "string" }, "maxTimeout": { "description": "How long to wait for a reply before timing out.", "type": "string" }, "mode": { "type": "string", "enum": [ "AGENT", "ESCALATE" ] }, "outputs": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "label": { "type": "string" }, "type": { "type": "string", "enum": [ "string", "number", "date", "boolean", "json" ] }, "description": { "type": "string" }, "builtin": { "type": "boolean" } }, "required": [ "id", "label", "type", "builtin" ] } } }, "description": "Legacy combined wait + AI conversation block." } }, "required": [ "id", "kind" ] }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "WAIT_FOR_REPLY" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "maxTimeout": { "description": "How long to wait for the first reply before timing out.", "type": "string" } }, "description": "Waits for the person to reply." } }, "required": [ "id", "kind" ] }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "MANAGE_CONVERSATION" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "mode": { "description": "AGENT (AI-led) or ESCALATE (human handoff). Defaults to AGENT.", "type": "string", "enum": [ "AGENT", "ESCALATE" ] }, "inactivityTimeout": { "description": "Optional custom idle window (e.g. '2h', '30m') that overrides the global inactive-conversation close. Resets on each inbound message; after this much silence the node closes the conversation (routes CLOSED). Hard cap 24h; under 30m is allowed but flagged 'not recommended'. Requires the journey-inactivity-timeout flag.", "type": "string" } }, "description": "Runs the AI-led conversation." } }, "required": [ "id", "kind" ] }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "DISPATCH_EVENT" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "eventName": { "type": "string", "minLength": 1, "description": "CDP event name to record. Must match the CDP name pattern." }, "properties": { "description": "Literal string values, or { var: path } bindings resolved to typed values at dispatch time.", "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "anyOf": [ { "type": "string" }, { "type": "object", "properties": { "var": { "type": "string" } }, "required": [ "var" ] } ] } }, "description": { "type": "string" } }, "required": [ "eventName" ], "description": "Records a CDP event for the person." } }, "required": [ "id", "kind" ] }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "DELAY" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "mode": { "description": "How the wait is measured. Defaults to duration.", "type": "string", "enum": [ "duration", "until_date", "until_weekday" ] }, "duration": { "description": "For mode duration.", "type": "string" }, "targetAt": { "description": "ISO 8601 instant, for mode until_date.", "type": "string" }, "weekdays": { "description": "ISO weekdays 1=Mon..7=Sun, for mode until_weekday.", "type": "array", "items": { "type": "integer", "minimum": 1, "maximum": 7 } }, "windowStartMinutes": { "type": "integer", "minimum": 0, "maximum": 1439 }, "windowEndMinutes": { "type": "integer", "minimum": 0, "maximum": 1439 }, "timezone": { "description": "IANA timezone. Load-bearing for until_weekday.", "type": "string" }, "description": { "type": "string" } }, "description": "Pauses the run." } }, "required": [ "id", "kind" ] }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "DECISION" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "logic": { "type": "string", "enum": [ "AND", "OR" ] }, "conditions": { "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "value" }, "selectionPath": { "type": "string", "description": "Dot-path into the run; must start with one of \"engagement.workflowState.\", \"engagement.extracted.\", \"engagement.nodeOutputs.\" (e.g. engagement.workflowState.totalPrice). customer.*, person.*, attributes.* and engagement.context.* are NOT resolvable here." }, "operator": { "type": "string", "enum": [ "eq", "neq", "gt", "lt", "contains", "isSet" ] }, "value": { "type": "string" } }, "required": [ "kind", "selectionPath", "operator", "value" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "event" }, "eventName": { "type": "string" }, "subjectSelectionPath": { "type": "string", "description": "Dot-path into the run; must start with one of \"engagement.workflowState.\", \"engagement.extracted.\", \"engagement.nodeOutputs.\" (e.g. engagement.workflowState.totalPrice). customer.*, person.*, attributes.* and engagement.context.* are NOT resolvable here." }, "occurred": { "type": "boolean" } }, "required": [ "kind", "eventName", "subjectSelectionPath", "occurred" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "cdp_predicate" }, "term": { "type": "object", "properties": { "attr": { "type": "string", "minLength": 1, "description": "Typed person column, `attributes.`, or `computed.`. See journeys_condition_catalog for the available attributes." }, "type": { "type": "string", "enum": [ "STRING", "NUMBER", "BOOLEAN", "DATE", "JSON", "ARRAY" ], "description": "CDP attribute type. Determines which `op` values are legal — see journeys_condition_catalog." }, "op": { "type": "string", "minLength": 1, "description": "Segments OperatorEnum value (eq | neq | gt | lt | in_last_n | ...). Must be legal for `type` — see journeys_condition_catalog." }, "value": { "description": "Shape depends on `op`: a plain scalar for eq/neq/gt/lt/starts_with/…, an array for in/not_in/contains/not_contains, {from, to} for between, {amount, unit} for in_last_n/in_next_n/more_than_n_ago/more_than_n_from_now, {minAmount, maxAmount, unit} for between_n_and_m_ago, {daysOffset} for exactly_n_from_today. Omit entirely for is_null/is_not_null.", "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" }, { "type": "array", "items": { "anyOf": [ { "type": "string" }, { "type": "number" } ] } }, { "type": "object", "properties": { "from": { "type": "string" }, "to": { "type": "string" } }, "required": [ "from", "to" ] }, { "type": "object", "properties": { "amount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "amount", "unit" ] }, { "type": "object", "properties": { "minAmount": { "type": "integer", "minimum": 0, "maximum": 9999 }, "maxAmount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "minAmount", "maxAmount", "unit" ] }, { "type": "object", "properties": { "daysOffset": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "rollForward": { "type": "object", "properties": { "fromDow": { "type": "integer", "minimum": 0, "maximum": 6 }, "includeDows": { "minItems": 1, "type": "array", "items": { "type": "integer", "minimum": 0, "maximum": 6 } } }, "required": [ "fromDow", "includeDows" ] } }, "required": [ "daysOffset" ] } ] } }, "required": [ "attr", "type", "op" ], "description": "A single live person/computed predicate term. See journeys_condition_catalog for its shape and the legal operator/value pairing." } }, "required": [ "kind", "term" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "cdp_object" }, "objectType": { "type": "string" }, "matchAttr": { "type": "string" }, "matchSelectionPath": { "type": "string", "description": "Dot-path into the run; must start with one of \"engagement.workflowState.\", \"engagement.extracted.\", \"engagement.nodeOutputs.\" (e.g. engagement.workflowState.totalPrice). customer.*, person.*, attributes.* and engagement.context.* are NOT resolvable here." }, "exists": { "type": "boolean" } }, "required": [ "kind", "objectType", "matchAttr", "matchSelectionPath", "exists" ] } ], "description": "One decision condition." } }, "description": { "type": "string" } }, "required": [ "logic", "conditions" ], "description": "Two-way branch. Emits YES / NO." } }, "required": [ "id", "kind" ] }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "CASE" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "selectionPath": { "type": "string", "description": "Value to switch on; must start with one of \"attributes.\", \"engagement.extracted.\", \"engagement.nodeOutputs.\" (e.g. attributes.plan_tier)." }, "branches": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable branch id; edge handle is case:." }, "value": { "type": "string", "description": "Value matched. Unique within the node." }, "label": { "type": "string", "minLength": 1, "description": "Required. Names the variant in analytics and on canvas." } }, "required": [ "id", "value", "label" ] }, "description": "Up to 10 branches. A case:default handle is always required." }, "description": { "type": "string" } }, "required": [ "selectionPath", "branches" ], "description": "N-way switch on a person attribute." } }, "required": [ "id", "kind" ] }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "RANDOM_SPLIT" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "arms": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable arm id; edge handle is split:." }, "weight": { "type": "integer", "minimum": 1, "maximum": 100, "description": "Integer percentage. A node's arms must total 100." }, "label": { "type": "string" } }, "required": [ "id", "weight" ] }, "description": "At least 2 and at most 10 arms whose weights total exactly 100. There is no default handle — every roll lands on a declared arm." }, "description": { "type": "string" } }, "required": [ "arms" ], "description": "Randomly routes each run down one of N weighted arms." } }, "required": [ "id", "kind" ] }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "HTTP_REQUEST" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "method": { "type": "string", "enum": [ "GET", "POST", "PUT", "PATCH", "DELETE" ], "description": "HTTP method." }, "url": { "type": "string", "minLength": 1, "description": "Target URL. Supports {{variable}} placeholders." }, "headers": { "description": "Request headers as key/value pairs.", "type": "array", "items": { "type": "object", "properties": { "key": { "type": "string" }, "value": { "type": "string" } }, "required": [ "key", "value" ] } }, "body": { "description": "Request body. mode none sends no body.", "type": "object", "properties": { "mode": { "type": "string", "enum": [ "none", "json", "raw" ] }, "content": { "type": "string" }, "contentType": { "type": "string" } }, "required": [ "mode" ] }, "credentialId": { "description": "Deprecated/legacy: HttpCredential row id used to authenticate the request. Prefer credentialKey.", "type": "string" }, "credentialKey": { "description": "Logical credential key; the pinned environment selects the secret.", "type": "string" }, "timeoutMs": { "description": "Request timeout in milliseconds. Max 30000 (30s).", "type": "integer", "exclusiveMinimum": 0, "maximum": 30000 }, "maxAttempts": { "description": "Max attempts including the first. Max 5.", "type": "integer", "exclusiveMinimum": 0, "maximum": 5 }, "documentUrlTtlSeconds": { "description": "TTL (seconds, ≤86400) for presigned engagement.documents URLs this node emits. Default 86400.", "type": "integer", "exclusiveMinimum": 0, "maximum": 86400 } }, "required": [ "method", "url" ], "description": "Calls an external HTTP endpoint. Emits SUCCESS or FAILED." } }, "required": [ "id", "kind" ] }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "EXIT" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "outcome": { "type": "string" }, "nextInitiativeId": { "description": "Chain into another initiative on exit.", "type": "string" } }, "description": "Terminal node." } }, "required": [ "id", "kind" ] } ] } }, "required": [ "node" ] } } } }, "parameters": [ { "name": "journeyId", "in": "path", "required": true, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "minLength": 1, "description": "A draft journey id, or the initiative id (resolves to its current draft)." } } ], "responses": { "201": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "id": { "type": "string", "description": "Journey (workflow version) id." }, "initiativeId": { "type": "string", "description": "The initiative this journey belongs to." }, "status": { "type": "string", "enum": [ "DRAFT", "PUBLISHED", "STOPPED" ], "description": "DRAFT (editable), PUBLISHED (live, frozen), or STOPPED (retired)." }, "version": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Version number within the initiative." }, "definition": { "type": "object", "properties": { "id": { "description": "Journey id; carried for round-trip ergonomics. Optional on create.", "type": "string" }, "name": { "type": "string", "minLength": 1, "description": "Journey name." }, "metadata": { "type": "object", "properties": { "initiativeType": { "type": "string" }, "version": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "cancelOnEvents": { "description": "Cancel an in-flight run when any of these events arrive.", "type": "object", "properties": { "eventNames": { "type": "array", "items": { "type": "string" } } }, "required": [ "eventNames" ], "additionalProperties": false }, "environmentId": { "description": "Pinned environment whose non-secret {{env.*}} values HTTP nodes resolve against. Frozen at publish. The server preserves the stored value when a whole-graph update omits it.", "type": "string" } }, "additionalProperties": false, "description": "Optional journey-level metadata." }, "actions": { "minItems": 1, "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "ENTRY" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "description": { "type": "string" }, "triggerType": { "description": "How people enter: manual (added by an operator or API call), segment (on entering a segment), or cdp_event (when an event is received). Defaults to manual.", "type": "string", "enum": [ "manual", "segment", "cdp_event" ] }, "segmentId": { "description": "Segment id — required when triggerType is segment.", "type": "string" }, "segmentName": { "description": "Cached segment display name (optional).", "type": "string" }, "eventName": { "description": "CDP event name — required when triggerType is cdp_event.", "type": "string" }, "maxEnrollments": { "description": "Frequency cap: max enrollments per person within enrollmentWindow. Both-or-neither with enrollmentWindow.", "type": "integer", "minimum": 1, "maximum": 9007199254740991 }, "enrollmentWindow": { "description": "Rolling window for the frequency cap.", "type": "string" } }, "additionalProperties": false, "description": "Trigger node config. Exactly one ENTRY node per journey." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "SEND_MESSAGE" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "templateId": { "description": "Approved WhatsApp template id. Resolve ids from the catalog.", "type": "string" }, "templateName": { "type": "string" }, "channel": { "description": "Send channel. Only whatsapp is live today.", "type": "string", "enum": [ "whatsapp", "sms", "email" ] }, "templateBindings": { "description": "Map of template placeholder → variable reference.", "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "type": "string" } }, "channelId": { "description": "Sending WhatsApp channel (WABA) id. Required before publishing.", "type": "string" }, "sendImmediately": { "description": "Deprecated business-hours gate; prefer a preceding DELAY.", "type": "boolean" } }, "additionalProperties": false, "description": "Sends a WhatsApp template." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "CONVERSATION_BLOCK" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "goal": { "type": "string" }, "maxTimeout": { "description": "How long to wait for a reply before timing out.", "type": "string" }, "mode": { "type": "string", "enum": [ "AGENT", "ESCALATE" ] }, "outputs": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "label": { "type": "string" }, "type": { "type": "string", "enum": [ "string", "number", "date", "boolean", "json" ] }, "description": { "type": "string" }, "builtin": { "type": "boolean" } }, "required": [ "id", "label", "type", "builtin" ], "additionalProperties": false } } }, "additionalProperties": false, "description": "Legacy combined wait + AI conversation block." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "WAIT_FOR_REPLY" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "maxTimeout": { "description": "How long to wait for the first reply before timing out.", "type": "string" } }, "additionalProperties": false, "description": "Waits for the person to reply." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "MANAGE_CONVERSATION" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "mode": { "description": "AGENT (AI-led) or ESCALATE (human handoff). Defaults to AGENT.", "type": "string", "enum": [ "AGENT", "ESCALATE" ] }, "inactivityTimeout": { "description": "Optional custom idle window (e.g. '2h', '30m') that overrides the global inactive-conversation close. Resets on each inbound message; after this much silence the node closes the conversation (routes CLOSED). Hard cap 24h; under 30m is allowed but flagged 'not recommended'. Requires the journey-inactivity-timeout flag.", "type": "string" } }, "additionalProperties": false, "description": "Runs the AI-led conversation." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "DISPATCH_EVENT" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "eventName": { "type": "string", "minLength": 1, "description": "CDP event name to record. Must match the CDP name pattern." }, "properties": { "description": "Literal string values, or { var: path } bindings resolved to typed values at dispatch time.", "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "anyOf": [ { "type": "string" }, { "type": "object", "properties": { "var": { "type": "string" } }, "required": [ "var" ], "additionalProperties": false } ] } }, "description": { "type": "string" } }, "required": [ "eventName" ], "additionalProperties": false, "description": "Records a CDP event for the person." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "DELAY" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "mode": { "description": "How the wait is measured. Defaults to duration.", "type": "string", "enum": [ "duration", "until_date", "until_weekday" ] }, "duration": { "description": "For mode duration.", "type": "string" }, "targetAt": { "description": "ISO 8601 instant, for mode until_date.", "type": "string" }, "weekdays": { "description": "ISO weekdays 1=Mon..7=Sun, for mode until_weekday.", "type": "array", "items": { "type": "integer", "minimum": 1, "maximum": 7 } }, "windowStartMinutes": { "type": "integer", "minimum": 0, "maximum": 1439 }, "windowEndMinutes": { "type": "integer", "minimum": 0, "maximum": 1439 }, "timezone": { "description": "IANA timezone. Load-bearing for until_weekday.", "type": "string" }, "description": { "type": "string" } }, "additionalProperties": false, "description": "Pauses the run." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "DECISION" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "logic": { "type": "string", "enum": [ "AND", "OR" ] }, "conditions": { "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "value" }, "selectionPath": { "type": "string", "description": "Dot-path into the run; must start with one of \"engagement.workflowState.\", \"engagement.extracted.\", \"engagement.nodeOutputs.\" (e.g. engagement.workflowState.totalPrice). customer.*, person.*, attributes.* and engagement.context.* are NOT resolvable here." }, "operator": { "type": "string", "enum": [ "eq", "neq", "gt", "lt", "contains", "isSet" ] }, "value": { "type": "string" } }, "required": [ "kind", "selectionPath", "operator", "value" ], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "event" }, "eventName": { "type": "string" }, "subjectSelectionPath": { "type": "string", "description": "Dot-path into the run; must start with one of \"engagement.workflowState.\", \"engagement.extracted.\", \"engagement.nodeOutputs.\" (e.g. engagement.workflowState.totalPrice). customer.*, person.*, attributes.* and engagement.context.* are NOT resolvable here." }, "occurred": { "type": "boolean" } }, "required": [ "kind", "eventName", "subjectSelectionPath", "occurred" ], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "cdp_predicate" }, "term": { "type": "object", "properties": { "attr": { "type": "string", "minLength": 1, "description": "Typed person column, `attributes.`, or `computed.`. See journeys_condition_catalog for the available attributes." }, "type": { "type": "string", "enum": [ "STRING", "NUMBER", "BOOLEAN", "DATE", "JSON", "ARRAY" ], "description": "CDP attribute type. Determines which `op` values are legal — see journeys_condition_catalog." }, "op": { "type": "string", "minLength": 1, "description": "Segments OperatorEnum value (eq | neq | gt | lt | in_last_n | ...). Must be legal for `type` — see journeys_condition_catalog." }, "value": { "description": "Shape depends on `op`: a plain scalar for eq/neq/gt/lt/starts_with/…, an array for in/not_in/contains/not_contains, {from, to} for between, {amount, unit} for in_last_n/in_next_n/more_than_n_ago/more_than_n_from_now, {minAmount, maxAmount, unit} for between_n_and_m_ago, {daysOffset} for exactly_n_from_today. Omit entirely for is_null/is_not_null.", "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" }, { "type": "array", "items": { "anyOf": [ { "type": "string" }, { "type": "number" } ] } }, { "type": "object", "properties": { "from": { "type": "string" }, "to": { "type": "string" } }, "required": [ "from", "to" ], "additionalProperties": false }, { "type": "object", "properties": { "amount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "amount", "unit" ], "additionalProperties": false }, { "type": "object", "properties": { "minAmount": { "type": "integer", "minimum": 0, "maximum": 9999 }, "maxAmount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "minAmount", "maxAmount", "unit" ], "additionalProperties": false }, { "type": "object", "properties": { "daysOffset": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "rollForward": { "type": "object", "properties": { "fromDow": { "type": "integer", "minimum": 0, "maximum": 6 }, "includeDows": { "minItems": 1, "type": "array", "items": { "type": "integer", "minimum": 0, "maximum": 6 } } }, "required": [ "fromDow", "includeDows" ], "additionalProperties": false } }, "required": [ "daysOffset" ], "additionalProperties": false } ] } }, "required": [ "attr", "type", "op" ], "additionalProperties": false, "description": "A single live person/computed predicate term. See journeys_condition_catalog for its shape and the legal operator/value pairing." } }, "required": [ "kind", "term" ], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "cdp_object" }, "objectType": { "type": "string" }, "matchAttr": { "type": "string" }, "matchSelectionPath": { "type": "string", "description": "Dot-path into the run; must start with one of \"engagement.workflowState.\", \"engagement.extracted.\", \"engagement.nodeOutputs.\" (e.g. engagement.workflowState.totalPrice). customer.*, person.*, attributes.* and engagement.context.* are NOT resolvable here." }, "exists": { "type": "boolean" } }, "required": [ "kind", "objectType", "matchAttr", "matchSelectionPath", "exists" ], "additionalProperties": false } ], "description": "One decision condition." } }, "description": { "type": "string" } }, "required": [ "logic", "conditions" ], "additionalProperties": false, "description": "Two-way branch. Emits YES / NO." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "CASE" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "selectionPath": { "type": "string", "description": "Value to switch on; must start with one of \"attributes.\", \"engagement.extracted.\", \"engagement.nodeOutputs.\" (e.g. attributes.plan_tier)." }, "branches": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable branch id; edge handle is case:." }, "value": { "type": "string", "description": "Value matched. Unique within the node." }, "label": { "type": "string", "minLength": 1, "description": "Required. Names the variant in analytics and on canvas." } }, "required": [ "id", "value", "label" ], "additionalProperties": false }, "description": "Up to 10 branches. A case:default handle is always required." }, "description": { "type": "string" } }, "required": [ "selectionPath", "branches" ], "additionalProperties": false, "description": "N-way switch on a person attribute." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "RANDOM_SPLIT" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "arms": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable arm id; edge handle is split:." }, "weight": { "type": "integer", "minimum": 1, "maximum": 100, "description": "Integer percentage. A node's arms must total 100." }, "label": { "type": "string" } }, "required": [ "id", "weight" ], "additionalProperties": false }, "description": "At least 2 and at most 10 arms whose weights total exactly 100. There is no default handle — every roll lands on a declared arm." }, "description": { "type": "string" } }, "required": [ "arms" ], "additionalProperties": false, "description": "Randomly routes each run down one of N weighted arms." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "HTTP_REQUEST" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "method": { "type": "string", "enum": [ "GET", "POST", "PUT", "PATCH", "DELETE" ], "description": "HTTP method." }, "url": { "type": "string", "minLength": 1, "description": "Target URL. Supports {{variable}} placeholders." }, "headers": { "description": "Request headers as key/value pairs.", "type": "array", "items": { "type": "object", "properties": { "key": { "type": "string" }, "value": { "type": "string" } }, "required": [ "key", "value" ], "additionalProperties": false } }, "body": { "description": "Request body. mode none sends no body.", "type": "object", "properties": { "mode": { "type": "string", "enum": [ "none", "json", "raw" ] }, "content": { "type": "string" }, "contentType": { "type": "string" } }, "required": [ "mode" ], "additionalProperties": false }, "credentialId": { "description": "Deprecated/legacy: HttpCredential row id used to authenticate the request. Prefer credentialKey.", "type": "string" }, "credentialKey": { "description": "Logical credential key; the pinned environment selects the secret.", "type": "string" }, "timeoutMs": { "description": "Request timeout in milliseconds. Max 30000 (30s).", "type": "integer", "exclusiveMinimum": 0, "maximum": 30000 }, "maxAttempts": { "description": "Max attempts including the first. Max 5.", "type": "integer", "exclusiveMinimum": 0, "maximum": 5 }, "documentUrlTtlSeconds": { "description": "TTL (seconds, ≤86400) for presigned engagement.documents URLs this node emits. Default 86400.", "type": "integer", "exclusiveMinimum": 0, "maximum": 86400 } }, "required": [ "method", "url" ], "additionalProperties": false, "description": "Calls an external HTTP endpoint. Emits SUCCESS or FAILED." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "EXIT" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "outcome": { "type": "string" }, "nextInitiativeId": { "description": "Chain into another initiative on exit.", "type": "string" } }, "additionalProperties": false, "description": "Terminal node." } }, "required": [ "id", "kind" ], "additionalProperties": false } ] }, "description": "The nodes. Exactly one ENTRY and at least one EXIT are required to publish." }, "edges": { "type": "array", "items": { "type": "object", "properties": { "from": { "type": "string", "description": "Source node id." }, "to": { "type": "string", "description": "Target node id." }, "sourceHandle": { "type": "string", "description": "The emitted signal that activates this edge (e.g. SENT, REPLIED, YES, case:). A handle may wire to at most one node." }, "metadata": { "type": "object", "properties": { "signalCategory": { "type": "string", "enum": [ "lifecycle", "system" ] }, "signalDescription": { "type": "string" } }, "additionalProperties": false } }, "required": [ "from", "to", "sourceHandle" ], "additionalProperties": false, "description": "A connection: node `from` routes to `to` when it emits `sourceHandle`." }, "description": "The connections between node handles." } }, "required": [ "name", "actions", "edges" ], "additionalProperties": false, "description": "The full journey graph." } }, "required": [ "id", "initiativeId", "status", "version", "definition" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } } }, "/api/v1/journeys/{journeyId}/nodes/{nodeId}": { "delete": { "operationId": "journeys_delete_node", "summary": "Delete node", "description": "Remove one node and every edge connected to it from a draft journey.", "tags": [ "Journeys" ], "parameters": [ { "name": "journeyId", "in": "path", "required": true, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "minLength": 1, "description": "A draft journey id, or the initiative id (resolves to its current draft)." } }, { "name": "nodeId", "in": "path", "required": true, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "minLength": 1, "description": "Node id within the journey." } } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "id": { "type": "string", "description": "Journey (workflow version) id." }, "initiativeId": { "type": "string", "description": "The initiative this journey belongs to." }, "status": { "type": "string", "enum": [ "DRAFT", "PUBLISHED", "STOPPED" ], "description": "DRAFT (editable), PUBLISHED (live, frozen), or STOPPED (retired)." }, "version": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Version number within the initiative." }, "definition": { "type": "object", "properties": { "id": { "description": "Journey id; carried for round-trip ergonomics. Optional on create.", "type": "string" }, "name": { "type": "string", "minLength": 1, "description": "Journey name." }, "metadata": { "type": "object", "properties": { "initiativeType": { "type": "string" }, "version": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "cancelOnEvents": { "description": "Cancel an in-flight run when any of these events arrive.", "type": "object", "properties": { "eventNames": { "type": "array", "items": { "type": "string" } } }, "required": [ "eventNames" ], "additionalProperties": false }, "environmentId": { "description": "Pinned environment whose non-secret {{env.*}} values HTTP nodes resolve against. Frozen at publish. The server preserves the stored value when a whole-graph update omits it.", "type": "string" } }, "additionalProperties": false, "description": "Optional journey-level metadata." }, "actions": { "minItems": 1, "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "ENTRY" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "description": { "type": "string" }, "triggerType": { "description": "How people enter: manual (added by an operator or API call), segment (on entering a segment), or cdp_event (when an event is received). Defaults to manual.", "type": "string", "enum": [ "manual", "segment", "cdp_event" ] }, "segmentId": { "description": "Segment id — required when triggerType is segment.", "type": "string" }, "segmentName": { "description": "Cached segment display name (optional).", "type": "string" }, "eventName": { "description": "CDP event name — required when triggerType is cdp_event.", "type": "string" }, "maxEnrollments": { "description": "Frequency cap: max enrollments per person within enrollmentWindow. Both-or-neither with enrollmentWindow.", "type": "integer", "minimum": 1, "maximum": 9007199254740991 }, "enrollmentWindow": { "description": "Rolling window for the frequency cap.", "type": "string" } }, "additionalProperties": false, "description": "Trigger node config. Exactly one ENTRY node per journey." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "SEND_MESSAGE" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "templateId": { "description": "Approved WhatsApp template id. Resolve ids from the catalog.", "type": "string" }, "templateName": { "type": "string" }, "channel": { "description": "Send channel. Only whatsapp is live today.", "type": "string", "enum": [ "whatsapp", "sms", "email" ] }, "templateBindings": { "description": "Map of template placeholder → variable reference.", "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "type": "string" } }, "channelId": { "description": "Sending WhatsApp channel (WABA) id. Required before publishing.", "type": "string" }, "sendImmediately": { "description": "Deprecated business-hours gate; prefer a preceding DELAY.", "type": "boolean" } }, "additionalProperties": false, "description": "Sends a WhatsApp template." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "CONVERSATION_BLOCK" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "goal": { "type": "string" }, "maxTimeout": { "description": "How long to wait for a reply before timing out.", "type": "string" }, "mode": { "type": "string", "enum": [ "AGENT", "ESCALATE" ] }, "outputs": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "label": { "type": "string" }, "type": { "type": "string", "enum": [ "string", "number", "date", "boolean", "json" ] }, "description": { "type": "string" }, "builtin": { "type": "boolean" } }, "required": [ "id", "label", "type", "builtin" ], "additionalProperties": false } } }, "additionalProperties": false, "description": "Legacy combined wait + AI conversation block." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "WAIT_FOR_REPLY" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "maxTimeout": { "description": "How long to wait for the first reply before timing out.", "type": "string" } }, "additionalProperties": false, "description": "Waits for the person to reply." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "MANAGE_CONVERSATION" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "mode": { "description": "AGENT (AI-led) or ESCALATE (human handoff). Defaults to AGENT.", "type": "string", "enum": [ "AGENT", "ESCALATE" ] }, "inactivityTimeout": { "description": "Optional custom idle window (e.g. '2h', '30m') that overrides the global inactive-conversation close. Resets on each inbound message; after this much silence the node closes the conversation (routes CLOSED). Hard cap 24h; under 30m is allowed but flagged 'not recommended'. Requires the journey-inactivity-timeout flag.", "type": "string" } }, "additionalProperties": false, "description": "Runs the AI-led conversation." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "DISPATCH_EVENT" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "eventName": { "type": "string", "minLength": 1, "description": "CDP event name to record. Must match the CDP name pattern." }, "properties": { "description": "Literal string values, or { var: path } bindings resolved to typed values at dispatch time.", "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "anyOf": [ { "type": "string" }, { "type": "object", "properties": { "var": { "type": "string" } }, "required": [ "var" ], "additionalProperties": false } ] } }, "description": { "type": "string" } }, "required": [ "eventName" ], "additionalProperties": false, "description": "Records a CDP event for the person." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "DELAY" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "mode": { "description": "How the wait is measured. Defaults to duration.", "type": "string", "enum": [ "duration", "until_date", "until_weekday" ] }, "duration": { "description": "For mode duration.", "type": "string" }, "targetAt": { "description": "ISO 8601 instant, for mode until_date.", "type": "string" }, "weekdays": { "description": "ISO weekdays 1=Mon..7=Sun, for mode until_weekday.", "type": "array", "items": { "type": "integer", "minimum": 1, "maximum": 7 } }, "windowStartMinutes": { "type": "integer", "minimum": 0, "maximum": 1439 }, "windowEndMinutes": { "type": "integer", "minimum": 0, "maximum": 1439 }, "timezone": { "description": "IANA timezone. Load-bearing for until_weekday.", "type": "string" }, "description": { "type": "string" } }, "additionalProperties": false, "description": "Pauses the run." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "DECISION" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "logic": { "type": "string", "enum": [ "AND", "OR" ] }, "conditions": { "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "value" }, "selectionPath": { "type": "string", "description": "Dot-path into the run; must start with one of \"engagement.workflowState.\", \"engagement.extracted.\", \"engagement.nodeOutputs.\" (e.g. engagement.workflowState.totalPrice). customer.*, person.*, attributes.* and engagement.context.* are NOT resolvable here." }, "operator": { "type": "string", "enum": [ "eq", "neq", "gt", "lt", "contains", "isSet" ] }, "value": { "type": "string" } }, "required": [ "kind", "selectionPath", "operator", "value" ], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "event" }, "eventName": { "type": "string" }, "subjectSelectionPath": { "type": "string", "description": "Dot-path into the run; must start with one of \"engagement.workflowState.\", \"engagement.extracted.\", \"engagement.nodeOutputs.\" (e.g. engagement.workflowState.totalPrice). customer.*, person.*, attributes.* and engagement.context.* are NOT resolvable here." }, "occurred": { "type": "boolean" } }, "required": [ "kind", "eventName", "subjectSelectionPath", "occurred" ], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "cdp_predicate" }, "term": { "type": "object", "properties": { "attr": { "type": "string", "minLength": 1, "description": "Typed person column, `attributes.`, or `computed.`. See journeys_condition_catalog for the available attributes." }, "type": { "type": "string", "enum": [ "STRING", "NUMBER", "BOOLEAN", "DATE", "JSON", "ARRAY" ], "description": "CDP attribute type. Determines which `op` values are legal — see journeys_condition_catalog." }, "op": { "type": "string", "minLength": 1, "description": "Segments OperatorEnum value (eq | neq | gt | lt | in_last_n | ...). Must be legal for `type` — see journeys_condition_catalog." }, "value": { "description": "Shape depends on `op`: a plain scalar for eq/neq/gt/lt/starts_with/…, an array for in/not_in/contains/not_contains, {from, to} for between, {amount, unit} for in_last_n/in_next_n/more_than_n_ago/more_than_n_from_now, {minAmount, maxAmount, unit} for between_n_and_m_ago, {daysOffset} for exactly_n_from_today. Omit entirely for is_null/is_not_null.", "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" }, { "type": "array", "items": { "anyOf": [ { "type": "string" }, { "type": "number" } ] } }, { "type": "object", "properties": { "from": { "type": "string" }, "to": { "type": "string" } }, "required": [ "from", "to" ], "additionalProperties": false }, { "type": "object", "properties": { "amount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "amount", "unit" ], "additionalProperties": false }, { "type": "object", "properties": { "minAmount": { "type": "integer", "minimum": 0, "maximum": 9999 }, "maxAmount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "minAmount", "maxAmount", "unit" ], "additionalProperties": false }, { "type": "object", "properties": { "daysOffset": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "rollForward": { "type": "object", "properties": { "fromDow": { "type": "integer", "minimum": 0, "maximum": 6 }, "includeDows": { "minItems": 1, "type": "array", "items": { "type": "integer", "minimum": 0, "maximum": 6 } } }, "required": [ "fromDow", "includeDows" ], "additionalProperties": false } }, "required": [ "daysOffset" ], "additionalProperties": false } ] } }, "required": [ "attr", "type", "op" ], "additionalProperties": false, "description": "A single live person/computed predicate term. See journeys_condition_catalog for its shape and the legal operator/value pairing." } }, "required": [ "kind", "term" ], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "cdp_object" }, "objectType": { "type": "string" }, "matchAttr": { "type": "string" }, "matchSelectionPath": { "type": "string", "description": "Dot-path into the run; must start with one of \"engagement.workflowState.\", \"engagement.extracted.\", \"engagement.nodeOutputs.\" (e.g. engagement.workflowState.totalPrice). customer.*, person.*, attributes.* and engagement.context.* are NOT resolvable here." }, "exists": { "type": "boolean" } }, "required": [ "kind", "objectType", "matchAttr", "matchSelectionPath", "exists" ], "additionalProperties": false } ], "description": "One decision condition." } }, "description": { "type": "string" } }, "required": [ "logic", "conditions" ], "additionalProperties": false, "description": "Two-way branch. Emits YES / NO." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "CASE" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "selectionPath": { "type": "string", "description": "Value to switch on; must start with one of \"attributes.\", \"engagement.extracted.\", \"engagement.nodeOutputs.\" (e.g. attributes.plan_tier)." }, "branches": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable branch id; edge handle is case:." }, "value": { "type": "string", "description": "Value matched. Unique within the node." }, "label": { "type": "string", "minLength": 1, "description": "Required. Names the variant in analytics and on canvas." } }, "required": [ "id", "value", "label" ], "additionalProperties": false }, "description": "Up to 10 branches. A case:default handle is always required." }, "description": { "type": "string" } }, "required": [ "selectionPath", "branches" ], "additionalProperties": false, "description": "N-way switch on a person attribute." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "RANDOM_SPLIT" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "arms": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable arm id; edge handle is split:." }, "weight": { "type": "integer", "minimum": 1, "maximum": 100, "description": "Integer percentage. A node's arms must total 100." }, "label": { "type": "string" } }, "required": [ "id", "weight" ], "additionalProperties": false }, "description": "At least 2 and at most 10 arms whose weights total exactly 100. There is no default handle — every roll lands on a declared arm." }, "description": { "type": "string" } }, "required": [ "arms" ], "additionalProperties": false, "description": "Randomly routes each run down one of N weighted arms." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "HTTP_REQUEST" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "method": { "type": "string", "enum": [ "GET", "POST", "PUT", "PATCH", "DELETE" ], "description": "HTTP method." }, "url": { "type": "string", "minLength": 1, "description": "Target URL. Supports {{variable}} placeholders." }, "headers": { "description": "Request headers as key/value pairs.", "type": "array", "items": { "type": "object", "properties": { "key": { "type": "string" }, "value": { "type": "string" } }, "required": [ "key", "value" ], "additionalProperties": false } }, "body": { "description": "Request body. mode none sends no body.", "type": "object", "properties": { "mode": { "type": "string", "enum": [ "none", "json", "raw" ] }, "content": { "type": "string" }, "contentType": { "type": "string" } }, "required": [ "mode" ], "additionalProperties": false }, "credentialId": { "description": "Deprecated/legacy: HttpCredential row id used to authenticate the request. Prefer credentialKey.", "type": "string" }, "credentialKey": { "description": "Logical credential key; the pinned environment selects the secret.", "type": "string" }, "timeoutMs": { "description": "Request timeout in milliseconds. Max 30000 (30s).", "type": "integer", "exclusiveMinimum": 0, "maximum": 30000 }, "maxAttempts": { "description": "Max attempts including the first. Max 5.", "type": "integer", "exclusiveMinimum": 0, "maximum": 5 }, "documentUrlTtlSeconds": { "description": "TTL (seconds, ≤86400) for presigned engagement.documents URLs this node emits. Default 86400.", "type": "integer", "exclusiveMinimum": 0, "maximum": 86400 } }, "required": [ "method", "url" ], "additionalProperties": false, "description": "Calls an external HTTP endpoint. Emits SUCCESS or FAILED." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "EXIT" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "outcome": { "type": "string" }, "nextInitiativeId": { "description": "Chain into another initiative on exit.", "type": "string" } }, "additionalProperties": false, "description": "Terminal node." } }, "required": [ "id", "kind" ], "additionalProperties": false } ] }, "description": "The nodes. Exactly one ENTRY and at least one EXIT are required to publish." }, "edges": { "type": "array", "items": { "type": "object", "properties": { "from": { "type": "string", "description": "Source node id." }, "to": { "type": "string", "description": "Target node id." }, "sourceHandle": { "type": "string", "description": "The emitted signal that activates this edge (e.g. SENT, REPLIED, YES, case:). A handle may wire to at most one node." }, "metadata": { "type": "object", "properties": { "signalCategory": { "type": "string", "enum": [ "lifecycle", "system" ] }, "signalDescription": { "type": "string" } }, "additionalProperties": false } }, "required": [ "from", "to", "sourceHandle" ], "additionalProperties": false, "description": "A connection: node `from` routes to `to` when it emits `sourceHandle`." }, "description": "The connections between node handles." } }, "required": [ "name", "actions", "edges" ], "additionalProperties": false, "description": "The full journey graph." } }, "required": [ "id", "initiativeId", "status", "version", "definition" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } }, "patch": { "operationId": "journeys_update_node", "summary": "Update node", "description": "Update one node's name, position, and/or config (inputs shallow-merge). Use journeys_authoring_catalog for a node kind's input fields.", "tags": [ "Journeys" ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "name": { "description": "New node label.", "type": "string", "minLength": 1 }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ] }, "inputs": { "description": "Config fields to merge into the node's inputs.", "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": {} } } } } } }, "parameters": [ { "name": "journeyId", "in": "path", "required": true, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "minLength": 1, "description": "A draft journey id, or the initiative id (resolves to its current draft)." } }, { "name": "nodeId", "in": "path", "required": true, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "minLength": 1, "description": "Node id within the journey." } } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "id": { "type": "string", "description": "Journey (workflow version) id." }, "initiativeId": { "type": "string", "description": "The initiative this journey belongs to." }, "status": { "type": "string", "enum": [ "DRAFT", "PUBLISHED", "STOPPED" ], "description": "DRAFT (editable), PUBLISHED (live, frozen), or STOPPED (retired)." }, "version": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Version number within the initiative." }, "definition": { "type": "object", "properties": { "id": { "description": "Journey id; carried for round-trip ergonomics. Optional on create.", "type": "string" }, "name": { "type": "string", "minLength": 1, "description": "Journey name." }, "metadata": { "type": "object", "properties": { "initiativeType": { "type": "string" }, "version": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "cancelOnEvents": { "description": "Cancel an in-flight run when any of these events arrive.", "type": "object", "properties": { "eventNames": { "type": "array", "items": { "type": "string" } } }, "required": [ "eventNames" ], "additionalProperties": false }, "environmentId": { "description": "Pinned environment whose non-secret {{env.*}} values HTTP nodes resolve against. Frozen at publish. The server preserves the stored value when a whole-graph update omits it.", "type": "string" } }, "additionalProperties": false, "description": "Optional journey-level metadata." }, "actions": { "minItems": 1, "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "ENTRY" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "description": { "type": "string" }, "triggerType": { "description": "How people enter: manual (added by an operator or API call), segment (on entering a segment), or cdp_event (when an event is received). Defaults to manual.", "type": "string", "enum": [ "manual", "segment", "cdp_event" ] }, "segmentId": { "description": "Segment id — required when triggerType is segment.", "type": "string" }, "segmentName": { "description": "Cached segment display name (optional).", "type": "string" }, "eventName": { "description": "CDP event name — required when triggerType is cdp_event.", "type": "string" }, "maxEnrollments": { "description": "Frequency cap: max enrollments per person within enrollmentWindow. Both-or-neither with enrollmentWindow.", "type": "integer", "minimum": 1, "maximum": 9007199254740991 }, "enrollmentWindow": { "description": "Rolling window for the frequency cap.", "type": "string" } }, "additionalProperties": false, "description": "Trigger node config. Exactly one ENTRY node per journey." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "SEND_MESSAGE" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "templateId": { "description": "Approved WhatsApp template id. Resolve ids from the catalog.", "type": "string" }, "templateName": { "type": "string" }, "channel": { "description": "Send channel. Only whatsapp is live today.", "type": "string", "enum": [ "whatsapp", "sms", "email" ] }, "templateBindings": { "description": "Map of template placeholder → variable reference.", "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "type": "string" } }, "channelId": { "description": "Sending WhatsApp channel (WABA) id. Required before publishing.", "type": "string" }, "sendImmediately": { "description": "Deprecated business-hours gate; prefer a preceding DELAY.", "type": "boolean" } }, "additionalProperties": false, "description": "Sends a WhatsApp template." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "CONVERSATION_BLOCK" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "goal": { "type": "string" }, "maxTimeout": { "description": "How long to wait for a reply before timing out.", "type": "string" }, "mode": { "type": "string", "enum": [ "AGENT", "ESCALATE" ] }, "outputs": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "label": { "type": "string" }, "type": { "type": "string", "enum": [ "string", "number", "date", "boolean", "json" ] }, "description": { "type": "string" }, "builtin": { "type": "boolean" } }, "required": [ "id", "label", "type", "builtin" ], "additionalProperties": false } } }, "additionalProperties": false, "description": "Legacy combined wait + AI conversation block." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "WAIT_FOR_REPLY" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "maxTimeout": { "description": "How long to wait for the first reply before timing out.", "type": "string" } }, "additionalProperties": false, "description": "Waits for the person to reply." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "MANAGE_CONVERSATION" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "mode": { "description": "AGENT (AI-led) or ESCALATE (human handoff). Defaults to AGENT.", "type": "string", "enum": [ "AGENT", "ESCALATE" ] }, "inactivityTimeout": { "description": "Optional custom idle window (e.g. '2h', '30m') that overrides the global inactive-conversation close. Resets on each inbound message; after this much silence the node closes the conversation (routes CLOSED). Hard cap 24h; under 30m is allowed but flagged 'not recommended'. Requires the journey-inactivity-timeout flag.", "type": "string" } }, "additionalProperties": false, "description": "Runs the AI-led conversation." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "DISPATCH_EVENT" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "eventName": { "type": "string", "minLength": 1, "description": "CDP event name to record. Must match the CDP name pattern." }, "properties": { "description": "Literal string values, or { var: path } bindings resolved to typed values at dispatch time.", "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "anyOf": [ { "type": "string" }, { "type": "object", "properties": { "var": { "type": "string" } }, "required": [ "var" ], "additionalProperties": false } ] } }, "description": { "type": "string" } }, "required": [ "eventName" ], "additionalProperties": false, "description": "Records a CDP event for the person." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "DELAY" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "mode": { "description": "How the wait is measured. Defaults to duration.", "type": "string", "enum": [ "duration", "until_date", "until_weekday" ] }, "duration": { "description": "For mode duration.", "type": "string" }, "targetAt": { "description": "ISO 8601 instant, for mode until_date.", "type": "string" }, "weekdays": { "description": "ISO weekdays 1=Mon..7=Sun, for mode until_weekday.", "type": "array", "items": { "type": "integer", "minimum": 1, "maximum": 7 } }, "windowStartMinutes": { "type": "integer", "minimum": 0, "maximum": 1439 }, "windowEndMinutes": { "type": "integer", "minimum": 0, "maximum": 1439 }, "timezone": { "description": "IANA timezone. Load-bearing for until_weekday.", "type": "string" }, "description": { "type": "string" } }, "additionalProperties": false, "description": "Pauses the run." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "DECISION" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "logic": { "type": "string", "enum": [ "AND", "OR" ] }, "conditions": { "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "value" }, "selectionPath": { "type": "string", "description": "Dot-path into the run; must start with one of \"engagement.workflowState.\", \"engagement.extracted.\", \"engagement.nodeOutputs.\" (e.g. engagement.workflowState.totalPrice). customer.*, person.*, attributes.* and engagement.context.* are NOT resolvable here." }, "operator": { "type": "string", "enum": [ "eq", "neq", "gt", "lt", "contains", "isSet" ] }, "value": { "type": "string" } }, "required": [ "kind", "selectionPath", "operator", "value" ], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "event" }, "eventName": { "type": "string" }, "subjectSelectionPath": { "type": "string", "description": "Dot-path into the run; must start with one of \"engagement.workflowState.\", \"engagement.extracted.\", \"engagement.nodeOutputs.\" (e.g. engagement.workflowState.totalPrice). customer.*, person.*, attributes.* and engagement.context.* are NOT resolvable here." }, "occurred": { "type": "boolean" } }, "required": [ "kind", "eventName", "subjectSelectionPath", "occurred" ], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "cdp_predicate" }, "term": { "type": "object", "properties": { "attr": { "type": "string", "minLength": 1, "description": "Typed person column, `attributes.`, or `computed.`. See journeys_condition_catalog for the available attributes." }, "type": { "type": "string", "enum": [ "STRING", "NUMBER", "BOOLEAN", "DATE", "JSON", "ARRAY" ], "description": "CDP attribute type. Determines which `op` values are legal — see journeys_condition_catalog." }, "op": { "type": "string", "minLength": 1, "description": "Segments OperatorEnum value (eq | neq | gt | lt | in_last_n | ...). Must be legal for `type` — see journeys_condition_catalog." }, "value": { "description": "Shape depends on `op`: a plain scalar for eq/neq/gt/lt/starts_with/…, an array for in/not_in/contains/not_contains, {from, to} for between, {amount, unit} for in_last_n/in_next_n/more_than_n_ago/more_than_n_from_now, {minAmount, maxAmount, unit} for between_n_and_m_ago, {daysOffset} for exactly_n_from_today. Omit entirely for is_null/is_not_null.", "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" }, { "type": "array", "items": { "anyOf": [ { "type": "string" }, { "type": "number" } ] } }, { "type": "object", "properties": { "from": { "type": "string" }, "to": { "type": "string" } }, "required": [ "from", "to" ], "additionalProperties": false }, { "type": "object", "properties": { "amount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "amount", "unit" ], "additionalProperties": false }, { "type": "object", "properties": { "minAmount": { "type": "integer", "minimum": 0, "maximum": 9999 }, "maxAmount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "minAmount", "maxAmount", "unit" ], "additionalProperties": false }, { "type": "object", "properties": { "daysOffset": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "rollForward": { "type": "object", "properties": { "fromDow": { "type": "integer", "minimum": 0, "maximum": 6 }, "includeDows": { "minItems": 1, "type": "array", "items": { "type": "integer", "minimum": 0, "maximum": 6 } } }, "required": [ "fromDow", "includeDows" ], "additionalProperties": false } }, "required": [ "daysOffset" ], "additionalProperties": false } ] } }, "required": [ "attr", "type", "op" ], "additionalProperties": false, "description": "A single live person/computed predicate term. See journeys_condition_catalog for its shape and the legal operator/value pairing." } }, "required": [ "kind", "term" ], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "cdp_object" }, "objectType": { "type": "string" }, "matchAttr": { "type": "string" }, "matchSelectionPath": { "type": "string", "description": "Dot-path into the run; must start with one of \"engagement.workflowState.\", \"engagement.extracted.\", \"engagement.nodeOutputs.\" (e.g. engagement.workflowState.totalPrice). customer.*, person.*, attributes.* and engagement.context.* are NOT resolvable here." }, "exists": { "type": "boolean" } }, "required": [ "kind", "objectType", "matchAttr", "matchSelectionPath", "exists" ], "additionalProperties": false } ], "description": "One decision condition." } }, "description": { "type": "string" } }, "required": [ "logic", "conditions" ], "additionalProperties": false, "description": "Two-way branch. Emits YES / NO." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "CASE" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "selectionPath": { "type": "string", "description": "Value to switch on; must start with one of \"attributes.\", \"engagement.extracted.\", \"engagement.nodeOutputs.\" (e.g. attributes.plan_tier)." }, "branches": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable branch id; edge handle is case:." }, "value": { "type": "string", "description": "Value matched. Unique within the node." }, "label": { "type": "string", "minLength": 1, "description": "Required. Names the variant in analytics and on canvas." } }, "required": [ "id", "value", "label" ], "additionalProperties": false }, "description": "Up to 10 branches. A case:default handle is always required." }, "description": { "type": "string" } }, "required": [ "selectionPath", "branches" ], "additionalProperties": false, "description": "N-way switch on a person attribute." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "RANDOM_SPLIT" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "arms": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable arm id; edge handle is split:." }, "weight": { "type": "integer", "minimum": 1, "maximum": 100, "description": "Integer percentage. A node's arms must total 100." }, "label": { "type": "string" } }, "required": [ "id", "weight" ], "additionalProperties": false }, "description": "At least 2 and at most 10 arms whose weights total exactly 100. There is no default handle — every roll lands on a declared arm." }, "description": { "type": "string" } }, "required": [ "arms" ], "additionalProperties": false, "description": "Randomly routes each run down one of N weighted arms." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "HTTP_REQUEST" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "method": { "type": "string", "enum": [ "GET", "POST", "PUT", "PATCH", "DELETE" ], "description": "HTTP method." }, "url": { "type": "string", "minLength": 1, "description": "Target URL. Supports {{variable}} placeholders." }, "headers": { "description": "Request headers as key/value pairs.", "type": "array", "items": { "type": "object", "properties": { "key": { "type": "string" }, "value": { "type": "string" } }, "required": [ "key", "value" ], "additionalProperties": false } }, "body": { "description": "Request body. mode none sends no body.", "type": "object", "properties": { "mode": { "type": "string", "enum": [ "none", "json", "raw" ] }, "content": { "type": "string" }, "contentType": { "type": "string" } }, "required": [ "mode" ], "additionalProperties": false }, "credentialId": { "description": "Deprecated/legacy: HttpCredential row id used to authenticate the request. Prefer credentialKey.", "type": "string" }, "credentialKey": { "description": "Logical credential key; the pinned environment selects the secret.", "type": "string" }, "timeoutMs": { "description": "Request timeout in milliseconds. Max 30000 (30s).", "type": "integer", "exclusiveMinimum": 0, "maximum": 30000 }, "maxAttempts": { "description": "Max attempts including the first. Max 5.", "type": "integer", "exclusiveMinimum": 0, "maximum": 5 }, "documentUrlTtlSeconds": { "description": "TTL (seconds, ≤86400) for presigned engagement.documents URLs this node emits. Default 86400.", "type": "integer", "exclusiveMinimum": 0, "maximum": 86400 } }, "required": [ "method", "url" ], "additionalProperties": false, "description": "Calls an external HTTP endpoint. Emits SUCCESS or FAILED." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "EXIT" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "outcome": { "type": "string" }, "nextInitiativeId": { "description": "Chain into another initiative on exit.", "type": "string" } }, "additionalProperties": false, "description": "Terminal node." } }, "required": [ "id", "kind" ], "additionalProperties": false } ] }, "description": "The nodes. Exactly one ENTRY and at least one EXIT are required to publish." }, "edges": { "type": "array", "items": { "type": "object", "properties": { "from": { "type": "string", "description": "Source node id." }, "to": { "type": "string", "description": "Target node id." }, "sourceHandle": { "type": "string", "description": "The emitted signal that activates this edge (e.g. SENT, REPLIED, YES, case:). A handle may wire to at most one node." }, "metadata": { "type": "object", "properties": { "signalCategory": { "type": "string", "enum": [ "lifecycle", "system" ] }, "signalDescription": { "type": "string" } }, "additionalProperties": false } }, "required": [ "from", "to", "sourceHandle" ], "additionalProperties": false, "description": "A connection: node `from` routes to `to` when it emits `sourceHandle`." }, "description": "The connections between node handles." } }, "required": [ "name", "actions", "edges" ], "additionalProperties": false, "description": "The full journey graph." } }, "required": [ "id", "initiativeId", "status", "version", "definition" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } } }, "/api/v1/journeys/{journeyId}/publish": { "post": { "operationId": "journeys_publish", "summary": "Publish journey", "description": "Publish a draft journey so it goes live and starts enrolling people (this begins real outreach). Validates first and requires confirm: true. The trigger is taken from the ENTRY node. Any previously live version is retired.", "tags": [ "Journeys" ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "confirm": { "default": false, "description": "Must be true to publish. Publishing starts real customer outreach.", "type": "boolean" }, "includeExisting": { "default": false, "description": "For a segment trigger: also enroll people already in the segment (a one-time backfill).", "type": "boolean" } } } } } }, "parameters": [ { "name": "journeyId", "in": "path", "required": true, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "minLength": 1, "description": "A draft journey id, or the initiative id (resolves to its current draft)." } } ], "responses": { "201": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "id": { "type": "string", "description": "Journey (workflow version) id." }, "initiativeId": { "type": "string", "description": "The initiative this journey belongs to." }, "status": { "type": "string", "enum": [ "DRAFT", "PUBLISHED", "STOPPED" ], "description": "DRAFT (editable), PUBLISHED (live, frozen), or STOPPED (retired)." }, "version": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Version number within the initiative." }, "definition": { "type": "object", "properties": { "id": { "description": "Journey id; carried for round-trip ergonomics. Optional on create.", "type": "string" }, "name": { "type": "string", "minLength": 1, "description": "Journey name." }, "metadata": { "type": "object", "properties": { "initiativeType": { "type": "string" }, "version": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "cancelOnEvents": { "description": "Cancel an in-flight run when any of these events arrive.", "type": "object", "properties": { "eventNames": { "type": "array", "items": { "type": "string" } } }, "required": [ "eventNames" ], "additionalProperties": false }, "environmentId": { "description": "Pinned environment whose non-secret {{env.*}} values HTTP nodes resolve against. Frozen at publish. The server preserves the stored value when a whole-graph update omits it.", "type": "string" } }, "additionalProperties": false, "description": "Optional journey-level metadata." }, "actions": { "minItems": 1, "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "ENTRY" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "description": { "type": "string" }, "triggerType": { "description": "How people enter: manual (added by an operator or API call), segment (on entering a segment), or cdp_event (when an event is received). Defaults to manual.", "type": "string", "enum": [ "manual", "segment", "cdp_event" ] }, "segmentId": { "description": "Segment id — required when triggerType is segment.", "type": "string" }, "segmentName": { "description": "Cached segment display name (optional).", "type": "string" }, "eventName": { "description": "CDP event name — required when triggerType is cdp_event.", "type": "string" }, "maxEnrollments": { "description": "Frequency cap: max enrollments per person within enrollmentWindow. Both-or-neither with enrollmentWindow.", "type": "integer", "minimum": 1, "maximum": 9007199254740991 }, "enrollmentWindow": { "description": "Rolling window for the frequency cap.", "type": "string" } }, "additionalProperties": false, "description": "Trigger node config. Exactly one ENTRY node per journey." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "SEND_MESSAGE" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "templateId": { "description": "Approved WhatsApp template id. Resolve ids from the catalog.", "type": "string" }, "templateName": { "type": "string" }, "channel": { "description": "Send channel. Only whatsapp is live today.", "type": "string", "enum": [ "whatsapp", "sms", "email" ] }, "templateBindings": { "description": "Map of template placeholder → variable reference.", "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "type": "string" } }, "channelId": { "description": "Sending WhatsApp channel (WABA) id. Required before publishing.", "type": "string" }, "sendImmediately": { "description": "Deprecated business-hours gate; prefer a preceding DELAY.", "type": "boolean" } }, "additionalProperties": false, "description": "Sends a WhatsApp template." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "CONVERSATION_BLOCK" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "goal": { "type": "string" }, "maxTimeout": { "description": "How long to wait for a reply before timing out.", "type": "string" }, "mode": { "type": "string", "enum": [ "AGENT", "ESCALATE" ] }, "outputs": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "label": { "type": "string" }, "type": { "type": "string", "enum": [ "string", "number", "date", "boolean", "json" ] }, "description": { "type": "string" }, "builtin": { "type": "boolean" } }, "required": [ "id", "label", "type", "builtin" ], "additionalProperties": false } } }, "additionalProperties": false, "description": "Legacy combined wait + AI conversation block." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "WAIT_FOR_REPLY" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "maxTimeout": { "description": "How long to wait for the first reply before timing out.", "type": "string" } }, "additionalProperties": false, "description": "Waits for the person to reply." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "MANAGE_CONVERSATION" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "mode": { "description": "AGENT (AI-led) or ESCALATE (human handoff). Defaults to AGENT.", "type": "string", "enum": [ "AGENT", "ESCALATE" ] }, "inactivityTimeout": { "description": "Optional custom idle window (e.g. '2h', '30m') that overrides the global inactive-conversation close. Resets on each inbound message; after this much silence the node closes the conversation (routes CLOSED). Hard cap 24h; under 30m is allowed but flagged 'not recommended'. Requires the journey-inactivity-timeout flag.", "type": "string" } }, "additionalProperties": false, "description": "Runs the AI-led conversation." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "DISPATCH_EVENT" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "eventName": { "type": "string", "minLength": 1, "description": "CDP event name to record. Must match the CDP name pattern." }, "properties": { "description": "Literal string values, or { var: path } bindings resolved to typed values at dispatch time.", "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "anyOf": [ { "type": "string" }, { "type": "object", "properties": { "var": { "type": "string" } }, "required": [ "var" ], "additionalProperties": false } ] } }, "description": { "type": "string" } }, "required": [ "eventName" ], "additionalProperties": false, "description": "Records a CDP event for the person." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "DELAY" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "mode": { "description": "How the wait is measured. Defaults to duration.", "type": "string", "enum": [ "duration", "until_date", "until_weekday" ] }, "duration": { "description": "For mode duration.", "type": "string" }, "targetAt": { "description": "ISO 8601 instant, for mode until_date.", "type": "string" }, "weekdays": { "description": "ISO weekdays 1=Mon..7=Sun, for mode until_weekday.", "type": "array", "items": { "type": "integer", "minimum": 1, "maximum": 7 } }, "windowStartMinutes": { "type": "integer", "minimum": 0, "maximum": 1439 }, "windowEndMinutes": { "type": "integer", "minimum": 0, "maximum": 1439 }, "timezone": { "description": "IANA timezone. Load-bearing for until_weekday.", "type": "string" }, "description": { "type": "string" } }, "additionalProperties": false, "description": "Pauses the run." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "DECISION" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "logic": { "type": "string", "enum": [ "AND", "OR" ] }, "conditions": { "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "value" }, "selectionPath": { "type": "string", "description": "Dot-path into the run; must start with one of \"engagement.workflowState.\", \"engagement.extracted.\", \"engagement.nodeOutputs.\" (e.g. engagement.workflowState.totalPrice). customer.*, person.*, attributes.* and engagement.context.* are NOT resolvable here." }, "operator": { "type": "string", "enum": [ "eq", "neq", "gt", "lt", "contains", "isSet" ] }, "value": { "type": "string" } }, "required": [ "kind", "selectionPath", "operator", "value" ], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "event" }, "eventName": { "type": "string" }, "subjectSelectionPath": { "type": "string", "description": "Dot-path into the run; must start with one of \"engagement.workflowState.\", \"engagement.extracted.\", \"engagement.nodeOutputs.\" (e.g. engagement.workflowState.totalPrice). customer.*, person.*, attributes.* and engagement.context.* are NOT resolvable here." }, "occurred": { "type": "boolean" } }, "required": [ "kind", "eventName", "subjectSelectionPath", "occurred" ], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "cdp_predicate" }, "term": { "type": "object", "properties": { "attr": { "type": "string", "minLength": 1, "description": "Typed person column, `attributes.`, or `computed.`. See journeys_condition_catalog for the available attributes." }, "type": { "type": "string", "enum": [ "STRING", "NUMBER", "BOOLEAN", "DATE", "JSON", "ARRAY" ], "description": "CDP attribute type. Determines which `op` values are legal — see journeys_condition_catalog." }, "op": { "type": "string", "minLength": 1, "description": "Segments OperatorEnum value (eq | neq | gt | lt | in_last_n | ...). Must be legal for `type` — see journeys_condition_catalog." }, "value": { "description": "Shape depends on `op`: a plain scalar for eq/neq/gt/lt/starts_with/…, an array for in/not_in/contains/not_contains, {from, to} for between, {amount, unit} for in_last_n/in_next_n/more_than_n_ago/more_than_n_from_now, {minAmount, maxAmount, unit} for between_n_and_m_ago, {daysOffset} for exactly_n_from_today. Omit entirely for is_null/is_not_null.", "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" }, { "type": "array", "items": { "anyOf": [ { "type": "string" }, { "type": "number" } ] } }, { "type": "object", "properties": { "from": { "type": "string" }, "to": { "type": "string" } }, "required": [ "from", "to" ], "additionalProperties": false }, { "type": "object", "properties": { "amount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "amount", "unit" ], "additionalProperties": false }, { "type": "object", "properties": { "minAmount": { "type": "integer", "minimum": 0, "maximum": 9999 }, "maxAmount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "minAmount", "maxAmount", "unit" ], "additionalProperties": false }, { "type": "object", "properties": { "daysOffset": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "rollForward": { "type": "object", "properties": { "fromDow": { "type": "integer", "minimum": 0, "maximum": 6 }, "includeDows": { "minItems": 1, "type": "array", "items": { "type": "integer", "minimum": 0, "maximum": 6 } } }, "required": [ "fromDow", "includeDows" ], "additionalProperties": false } }, "required": [ "daysOffset" ], "additionalProperties": false } ] } }, "required": [ "attr", "type", "op" ], "additionalProperties": false, "description": "A single live person/computed predicate term. See journeys_condition_catalog for its shape and the legal operator/value pairing." } }, "required": [ "kind", "term" ], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "cdp_object" }, "objectType": { "type": "string" }, "matchAttr": { "type": "string" }, "matchSelectionPath": { "type": "string", "description": "Dot-path into the run; must start with one of \"engagement.workflowState.\", \"engagement.extracted.\", \"engagement.nodeOutputs.\" (e.g. engagement.workflowState.totalPrice). customer.*, person.*, attributes.* and engagement.context.* are NOT resolvable here." }, "exists": { "type": "boolean" } }, "required": [ "kind", "objectType", "matchAttr", "matchSelectionPath", "exists" ], "additionalProperties": false } ], "description": "One decision condition." } }, "description": { "type": "string" } }, "required": [ "logic", "conditions" ], "additionalProperties": false, "description": "Two-way branch. Emits YES / NO." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "CASE" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "selectionPath": { "type": "string", "description": "Value to switch on; must start with one of \"attributes.\", \"engagement.extracted.\", \"engagement.nodeOutputs.\" (e.g. attributes.plan_tier)." }, "branches": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable branch id; edge handle is case:." }, "value": { "type": "string", "description": "Value matched. Unique within the node." }, "label": { "type": "string", "minLength": 1, "description": "Required. Names the variant in analytics and on canvas." } }, "required": [ "id", "value", "label" ], "additionalProperties": false }, "description": "Up to 10 branches. A case:default handle is always required." }, "description": { "type": "string" } }, "required": [ "selectionPath", "branches" ], "additionalProperties": false, "description": "N-way switch on a person attribute." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "RANDOM_SPLIT" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "arms": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable arm id; edge handle is split:." }, "weight": { "type": "integer", "minimum": 1, "maximum": 100, "description": "Integer percentage. A node's arms must total 100." }, "label": { "type": "string" } }, "required": [ "id", "weight" ], "additionalProperties": false }, "description": "At least 2 and at most 10 arms whose weights total exactly 100. There is no default handle — every roll lands on a declared arm." }, "description": { "type": "string" } }, "required": [ "arms" ], "additionalProperties": false, "description": "Randomly routes each run down one of N weighted arms." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "HTTP_REQUEST" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "method": { "type": "string", "enum": [ "GET", "POST", "PUT", "PATCH", "DELETE" ], "description": "HTTP method." }, "url": { "type": "string", "minLength": 1, "description": "Target URL. Supports {{variable}} placeholders." }, "headers": { "description": "Request headers as key/value pairs.", "type": "array", "items": { "type": "object", "properties": { "key": { "type": "string" }, "value": { "type": "string" } }, "required": [ "key", "value" ], "additionalProperties": false } }, "body": { "description": "Request body. mode none sends no body.", "type": "object", "properties": { "mode": { "type": "string", "enum": [ "none", "json", "raw" ] }, "content": { "type": "string" }, "contentType": { "type": "string" } }, "required": [ "mode" ], "additionalProperties": false }, "credentialId": { "description": "Deprecated/legacy: HttpCredential row id used to authenticate the request. Prefer credentialKey.", "type": "string" }, "credentialKey": { "description": "Logical credential key; the pinned environment selects the secret.", "type": "string" }, "timeoutMs": { "description": "Request timeout in milliseconds. Max 30000 (30s).", "type": "integer", "exclusiveMinimum": 0, "maximum": 30000 }, "maxAttempts": { "description": "Max attempts including the first. Max 5.", "type": "integer", "exclusiveMinimum": 0, "maximum": 5 }, "documentUrlTtlSeconds": { "description": "TTL (seconds, ≤86400) for presigned engagement.documents URLs this node emits. Default 86400.", "type": "integer", "exclusiveMinimum": 0, "maximum": 86400 } }, "required": [ "method", "url" ], "additionalProperties": false, "description": "Calls an external HTTP endpoint. Emits SUCCESS or FAILED." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "EXIT" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "outcome": { "type": "string" }, "nextInitiativeId": { "description": "Chain into another initiative on exit.", "type": "string" } }, "additionalProperties": false, "description": "Terminal node." } }, "required": [ "id", "kind" ], "additionalProperties": false } ] }, "description": "The nodes. Exactly one ENTRY and at least one EXIT are required to publish." }, "edges": { "type": "array", "items": { "type": "object", "properties": { "from": { "type": "string", "description": "Source node id." }, "to": { "type": "string", "description": "Target node id." }, "sourceHandle": { "type": "string", "description": "The emitted signal that activates this edge (e.g. SENT, REPLIED, YES, case:). A handle may wire to at most one node." }, "metadata": { "type": "object", "properties": { "signalCategory": { "type": "string", "enum": [ "lifecycle", "system" ] }, "signalDescription": { "type": "string" } }, "additionalProperties": false } }, "required": [ "from", "to", "sourceHandle" ], "additionalProperties": false, "description": "A connection: node `from` routes to `to` when it emits `sourceHandle`." }, "description": "The connections between node handles." } }, "required": [ "name", "actions", "edges" ], "additionalProperties": false, "description": "The full journey graph." } }, "required": [ "id", "initiativeId", "status", "version", "definition" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } } }, "/api/v1/journeys/{journeyId}/stop": { "post": { "operationId": "journeys_stop", "summary": "Stop journey", "description": "Retire a live journey: no one else is enrolled, and anyone already enrolled who has not been messaged yet is dropped before their message goes out. Conversations already in progress continue normally. Requires confirm: true. This cannot be undone — re-running the campaign means publishing again.", "tags": [ "Journeys" ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "confirm": { "default": false, "description": "Must be true to stop. Stopping halts customer outreach.", "type": "boolean" } } } } } }, "parameters": [ { "name": "journeyId", "in": "path", "required": true, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "minLength": 1, "description": "A published journey id, or the initiative id (resolves to its live journey)." } } ], "responses": { "201": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "id": { "type": "string", "description": "Journey (workflow version) id." }, "initiativeId": { "type": "string", "description": "The initiative this journey belongs to." }, "status": { "type": "string", "enum": [ "DRAFT", "PUBLISHED", "STOPPED" ], "description": "DRAFT (editable), PUBLISHED (live, frozen), or STOPPED (retired)." }, "version": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Version number within the initiative." }, "definition": { "type": "object", "properties": { "id": { "description": "Journey id; carried for round-trip ergonomics. Optional on create.", "type": "string" }, "name": { "type": "string", "minLength": 1, "description": "Journey name." }, "metadata": { "type": "object", "properties": { "initiativeType": { "type": "string" }, "version": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "cancelOnEvents": { "description": "Cancel an in-flight run when any of these events arrive.", "type": "object", "properties": { "eventNames": { "type": "array", "items": { "type": "string" } } }, "required": [ "eventNames" ], "additionalProperties": false }, "environmentId": { "description": "Pinned environment whose non-secret {{env.*}} values HTTP nodes resolve against. Frozen at publish. The server preserves the stored value when a whole-graph update omits it.", "type": "string" } }, "additionalProperties": false, "description": "Optional journey-level metadata." }, "actions": { "minItems": 1, "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "ENTRY" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "description": { "type": "string" }, "triggerType": { "description": "How people enter: manual (added by an operator or API call), segment (on entering a segment), or cdp_event (when an event is received). Defaults to manual.", "type": "string", "enum": [ "manual", "segment", "cdp_event" ] }, "segmentId": { "description": "Segment id — required when triggerType is segment.", "type": "string" }, "segmentName": { "description": "Cached segment display name (optional).", "type": "string" }, "eventName": { "description": "CDP event name — required when triggerType is cdp_event.", "type": "string" }, "maxEnrollments": { "description": "Frequency cap: max enrollments per person within enrollmentWindow. Both-or-neither with enrollmentWindow.", "type": "integer", "minimum": 1, "maximum": 9007199254740991 }, "enrollmentWindow": { "description": "Rolling window for the frequency cap.", "type": "string" } }, "additionalProperties": false, "description": "Trigger node config. Exactly one ENTRY node per journey." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "SEND_MESSAGE" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "templateId": { "description": "Approved WhatsApp template id. Resolve ids from the catalog.", "type": "string" }, "templateName": { "type": "string" }, "channel": { "description": "Send channel. Only whatsapp is live today.", "type": "string", "enum": [ "whatsapp", "sms", "email" ] }, "templateBindings": { "description": "Map of template placeholder → variable reference.", "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "type": "string" } }, "channelId": { "description": "Sending WhatsApp channel (WABA) id. Required before publishing.", "type": "string" }, "sendImmediately": { "description": "Deprecated business-hours gate; prefer a preceding DELAY.", "type": "boolean" } }, "additionalProperties": false, "description": "Sends a WhatsApp template." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "CONVERSATION_BLOCK" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "goal": { "type": "string" }, "maxTimeout": { "description": "How long to wait for a reply before timing out.", "type": "string" }, "mode": { "type": "string", "enum": [ "AGENT", "ESCALATE" ] }, "outputs": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "label": { "type": "string" }, "type": { "type": "string", "enum": [ "string", "number", "date", "boolean", "json" ] }, "description": { "type": "string" }, "builtin": { "type": "boolean" } }, "required": [ "id", "label", "type", "builtin" ], "additionalProperties": false } } }, "additionalProperties": false, "description": "Legacy combined wait + AI conversation block." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "WAIT_FOR_REPLY" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "maxTimeout": { "description": "How long to wait for the first reply before timing out.", "type": "string" } }, "additionalProperties": false, "description": "Waits for the person to reply." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "MANAGE_CONVERSATION" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "mode": { "description": "AGENT (AI-led) or ESCALATE (human handoff). Defaults to AGENT.", "type": "string", "enum": [ "AGENT", "ESCALATE" ] }, "inactivityTimeout": { "description": "Optional custom idle window (e.g. '2h', '30m') that overrides the global inactive-conversation close. Resets on each inbound message; after this much silence the node closes the conversation (routes CLOSED). Hard cap 24h; under 30m is allowed but flagged 'not recommended'. Requires the journey-inactivity-timeout flag.", "type": "string" } }, "additionalProperties": false, "description": "Runs the AI-led conversation." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "DISPATCH_EVENT" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "eventName": { "type": "string", "minLength": 1, "description": "CDP event name to record. Must match the CDP name pattern." }, "properties": { "description": "Literal string values, or { var: path } bindings resolved to typed values at dispatch time.", "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "anyOf": [ { "type": "string" }, { "type": "object", "properties": { "var": { "type": "string" } }, "required": [ "var" ], "additionalProperties": false } ] } }, "description": { "type": "string" } }, "required": [ "eventName" ], "additionalProperties": false, "description": "Records a CDP event for the person." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "DELAY" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "mode": { "description": "How the wait is measured. Defaults to duration.", "type": "string", "enum": [ "duration", "until_date", "until_weekday" ] }, "duration": { "description": "For mode duration.", "type": "string" }, "targetAt": { "description": "ISO 8601 instant, for mode until_date.", "type": "string" }, "weekdays": { "description": "ISO weekdays 1=Mon..7=Sun, for mode until_weekday.", "type": "array", "items": { "type": "integer", "minimum": 1, "maximum": 7 } }, "windowStartMinutes": { "type": "integer", "minimum": 0, "maximum": 1439 }, "windowEndMinutes": { "type": "integer", "minimum": 0, "maximum": 1439 }, "timezone": { "description": "IANA timezone. Load-bearing for until_weekday.", "type": "string" }, "description": { "type": "string" } }, "additionalProperties": false, "description": "Pauses the run." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "DECISION" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "logic": { "type": "string", "enum": [ "AND", "OR" ] }, "conditions": { "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "value" }, "selectionPath": { "type": "string", "description": "Dot-path into the run; must start with one of \"engagement.workflowState.\", \"engagement.extracted.\", \"engagement.nodeOutputs.\" (e.g. engagement.workflowState.totalPrice). customer.*, person.*, attributes.* and engagement.context.* are NOT resolvable here." }, "operator": { "type": "string", "enum": [ "eq", "neq", "gt", "lt", "contains", "isSet" ] }, "value": { "type": "string" } }, "required": [ "kind", "selectionPath", "operator", "value" ], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "event" }, "eventName": { "type": "string" }, "subjectSelectionPath": { "type": "string", "description": "Dot-path into the run; must start with one of \"engagement.workflowState.\", \"engagement.extracted.\", \"engagement.nodeOutputs.\" (e.g. engagement.workflowState.totalPrice). customer.*, person.*, attributes.* and engagement.context.* are NOT resolvable here." }, "occurred": { "type": "boolean" } }, "required": [ "kind", "eventName", "subjectSelectionPath", "occurred" ], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "cdp_predicate" }, "term": { "type": "object", "properties": { "attr": { "type": "string", "minLength": 1, "description": "Typed person column, `attributes.`, or `computed.`. See journeys_condition_catalog for the available attributes." }, "type": { "type": "string", "enum": [ "STRING", "NUMBER", "BOOLEAN", "DATE", "JSON", "ARRAY" ], "description": "CDP attribute type. Determines which `op` values are legal — see journeys_condition_catalog." }, "op": { "type": "string", "minLength": 1, "description": "Segments OperatorEnum value (eq | neq | gt | lt | in_last_n | ...). Must be legal for `type` — see journeys_condition_catalog." }, "value": { "description": "Shape depends on `op`: a plain scalar for eq/neq/gt/lt/starts_with/…, an array for in/not_in/contains/not_contains, {from, to} for between, {amount, unit} for in_last_n/in_next_n/more_than_n_ago/more_than_n_from_now, {minAmount, maxAmount, unit} for between_n_and_m_ago, {daysOffset} for exactly_n_from_today. Omit entirely for is_null/is_not_null.", "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" }, { "type": "array", "items": { "anyOf": [ { "type": "string" }, { "type": "number" } ] } }, { "type": "object", "properties": { "from": { "type": "string" }, "to": { "type": "string" } }, "required": [ "from", "to" ], "additionalProperties": false }, { "type": "object", "properties": { "amount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "amount", "unit" ], "additionalProperties": false }, { "type": "object", "properties": { "minAmount": { "type": "integer", "minimum": 0, "maximum": 9999 }, "maxAmount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "minAmount", "maxAmount", "unit" ], "additionalProperties": false }, { "type": "object", "properties": { "daysOffset": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "rollForward": { "type": "object", "properties": { "fromDow": { "type": "integer", "minimum": 0, "maximum": 6 }, "includeDows": { "minItems": 1, "type": "array", "items": { "type": "integer", "minimum": 0, "maximum": 6 } } }, "required": [ "fromDow", "includeDows" ], "additionalProperties": false } }, "required": [ "daysOffset" ], "additionalProperties": false } ] } }, "required": [ "attr", "type", "op" ], "additionalProperties": false, "description": "A single live person/computed predicate term. See journeys_condition_catalog for its shape and the legal operator/value pairing." } }, "required": [ "kind", "term" ], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "cdp_object" }, "objectType": { "type": "string" }, "matchAttr": { "type": "string" }, "matchSelectionPath": { "type": "string", "description": "Dot-path into the run; must start with one of \"engagement.workflowState.\", \"engagement.extracted.\", \"engagement.nodeOutputs.\" (e.g. engagement.workflowState.totalPrice). customer.*, person.*, attributes.* and engagement.context.* are NOT resolvable here." }, "exists": { "type": "boolean" } }, "required": [ "kind", "objectType", "matchAttr", "matchSelectionPath", "exists" ], "additionalProperties": false } ], "description": "One decision condition." } }, "description": { "type": "string" } }, "required": [ "logic", "conditions" ], "additionalProperties": false, "description": "Two-way branch. Emits YES / NO." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "CASE" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "selectionPath": { "type": "string", "description": "Value to switch on; must start with one of \"attributes.\", \"engagement.extracted.\", \"engagement.nodeOutputs.\" (e.g. attributes.plan_tier)." }, "branches": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable branch id; edge handle is case:." }, "value": { "type": "string", "description": "Value matched. Unique within the node." }, "label": { "type": "string", "minLength": 1, "description": "Required. Names the variant in analytics and on canvas." } }, "required": [ "id", "value", "label" ], "additionalProperties": false }, "description": "Up to 10 branches. A case:default handle is always required." }, "description": { "type": "string" } }, "required": [ "selectionPath", "branches" ], "additionalProperties": false, "description": "N-way switch on a person attribute." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "RANDOM_SPLIT" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "arms": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable arm id; edge handle is split:." }, "weight": { "type": "integer", "minimum": 1, "maximum": 100, "description": "Integer percentage. A node's arms must total 100." }, "label": { "type": "string" } }, "required": [ "id", "weight" ], "additionalProperties": false }, "description": "At least 2 and at most 10 arms whose weights total exactly 100. There is no default handle — every roll lands on a declared arm." }, "description": { "type": "string" } }, "required": [ "arms" ], "additionalProperties": false, "description": "Randomly routes each run down one of N weighted arms." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "HTTP_REQUEST" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "method": { "type": "string", "enum": [ "GET", "POST", "PUT", "PATCH", "DELETE" ], "description": "HTTP method." }, "url": { "type": "string", "minLength": 1, "description": "Target URL. Supports {{variable}} placeholders." }, "headers": { "description": "Request headers as key/value pairs.", "type": "array", "items": { "type": "object", "properties": { "key": { "type": "string" }, "value": { "type": "string" } }, "required": [ "key", "value" ], "additionalProperties": false } }, "body": { "description": "Request body. mode none sends no body.", "type": "object", "properties": { "mode": { "type": "string", "enum": [ "none", "json", "raw" ] }, "content": { "type": "string" }, "contentType": { "type": "string" } }, "required": [ "mode" ], "additionalProperties": false }, "credentialId": { "description": "Deprecated/legacy: HttpCredential row id used to authenticate the request. Prefer credentialKey.", "type": "string" }, "credentialKey": { "description": "Logical credential key; the pinned environment selects the secret.", "type": "string" }, "timeoutMs": { "description": "Request timeout in milliseconds. Max 30000 (30s).", "type": "integer", "exclusiveMinimum": 0, "maximum": 30000 }, "maxAttempts": { "description": "Max attempts including the first. Max 5.", "type": "integer", "exclusiveMinimum": 0, "maximum": 5 }, "documentUrlTtlSeconds": { "description": "TTL (seconds, ≤86400) for presigned engagement.documents URLs this node emits. Default 86400.", "type": "integer", "exclusiveMinimum": 0, "maximum": 86400 } }, "required": [ "method", "url" ], "additionalProperties": false, "description": "Calls an external HTTP endpoint. Emits SUCCESS or FAILED." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "EXIT" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "outcome": { "type": "string" }, "nextInitiativeId": { "description": "Chain into another initiative on exit.", "type": "string" } }, "additionalProperties": false, "description": "Terminal node." } }, "required": [ "id", "kind" ], "additionalProperties": false } ] }, "description": "The nodes. Exactly one ENTRY and at least one EXIT are required to publish." }, "edges": { "type": "array", "items": { "type": "object", "properties": { "from": { "type": "string", "description": "Source node id." }, "to": { "type": "string", "description": "Target node id." }, "sourceHandle": { "type": "string", "description": "The emitted signal that activates this edge (e.g. SENT, REPLIED, YES, case:). A handle may wire to at most one node." }, "metadata": { "type": "object", "properties": { "signalCategory": { "type": "string", "enum": [ "lifecycle", "system" ] }, "signalDescription": { "type": "string" } }, "additionalProperties": false } }, "required": [ "from", "to", "sourceHandle" ], "additionalProperties": false, "description": "A connection: node `from` routes to `to` when it emits `sourceHandle`." }, "description": "The connections between node handles." } }, "required": [ "name", "actions", "edges" ], "additionalProperties": false, "description": "The full journey graph." } }, "required": [ "id", "initiativeId", "status", "version", "definition" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } } }, "/api/v1/journeys/{journeyId}/trigger": { "patch": { "operationId": "journeys_set_trigger", "summary": "Set trigger", "description": "Configure how people enter the journey by updating its ENTRY node: manual, segment (needs segmentId), or cdp_event (needs eventName), with an optional frequency cap.", "tags": [ "Journeys" ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "triggerType": { "type": "string", "enum": [ "manual", "segment", "cdp_event" ], "description": "How people enter the journey." }, "segmentId": { "description": "Required for segment triggers. The segment's `id` (from segments_list / segments_get) — NOT its slug.", "type": "string" }, "segmentName": { "type": "string" }, "eventName": { "description": "Required for cdp_event triggers.", "type": "string" }, "maxEnrollments": { "description": "Frequency cap; both-or-neither with enrollmentWindow.", "type": "integer", "minimum": 1, "maximum": 9007199254740991 }, "enrollmentWindow": { "description": "Frequency-cap window, e.g. '7d'.", "type": "string" } }, "required": [ "triggerType" ] } } } }, "parameters": [ { "name": "journeyId", "in": "path", "required": true, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "minLength": 1, "description": "A draft journey id, or the initiative id (resolves to its current draft)." } } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "id": { "type": "string", "description": "Journey (workflow version) id." }, "initiativeId": { "type": "string", "description": "The initiative this journey belongs to." }, "status": { "type": "string", "enum": [ "DRAFT", "PUBLISHED", "STOPPED" ], "description": "DRAFT (editable), PUBLISHED (live, frozen), or STOPPED (retired)." }, "version": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Version number within the initiative." }, "definition": { "type": "object", "properties": { "id": { "description": "Journey id; carried for round-trip ergonomics. Optional on create.", "type": "string" }, "name": { "type": "string", "minLength": 1, "description": "Journey name." }, "metadata": { "type": "object", "properties": { "initiativeType": { "type": "string" }, "version": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "cancelOnEvents": { "description": "Cancel an in-flight run when any of these events arrive.", "type": "object", "properties": { "eventNames": { "type": "array", "items": { "type": "string" } } }, "required": [ "eventNames" ], "additionalProperties": false }, "environmentId": { "description": "Pinned environment whose non-secret {{env.*}} values HTTP nodes resolve against. Frozen at publish. The server preserves the stored value when a whole-graph update omits it.", "type": "string" } }, "additionalProperties": false, "description": "Optional journey-level metadata." }, "actions": { "minItems": 1, "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "ENTRY" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "description": { "type": "string" }, "triggerType": { "description": "How people enter: manual (added by an operator or API call), segment (on entering a segment), or cdp_event (when an event is received). Defaults to manual.", "type": "string", "enum": [ "manual", "segment", "cdp_event" ] }, "segmentId": { "description": "Segment id — required when triggerType is segment.", "type": "string" }, "segmentName": { "description": "Cached segment display name (optional).", "type": "string" }, "eventName": { "description": "CDP event name — required when triggerType is cdp_event.", "type": "string" }, "maxEnrollments": { "description": "Frequency cap: max enrollments per person within enrollmentWindow. Both-or-neither with enrollmentWindow.", "type": "integer", "minimum": 1, "maximum": 9007199254740991 }, "enrollmentWindow": { "description": "Rolling window for the frequency cap.", "type": "string" } }, "additionalProperties": false, "description": "Trigger node config. Exactly one ENTRY node per journey." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "SEND_MESSAGE" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "templateId": { "description": "Approved WhatsApp template id. Resolve ids from the catalog.", "type": "string" }, "templateName": { "type": "string" }, "channel": { "description": "Send channel. Only whatsapp is live today.", "type": "string", "enum": [ "whatsapp", "sms", "email" ] }, "templateBindings": { "description": "Map of template placeholder → variable reference.", "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "type": "string" } }, "channelId": { "description": "Sending WhatsApp channel (WABA) id. Required before publishing.", "type": "string" }, "sendImmediately": { "description": "Deprecated business-hours gate; prefer a preceding DELAY.", "type": "boolean" } }, "additionalProperties": false, "description": "Sends a WhatsApp template." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "CONVERSATION_BLOCK" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "goal": { "type": "string" }, "maxTimeout": { "description": "How long to wait for a reply before timing out.", "type": "string" }, "mode": { "type": "string", "enum": [ "AGENT", "ESCALATE" ] }, "outputs": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "label": { "type": "string" }, "type": { "type": "string", "enum": [ "string", "number", "date", "boolean", "json" ] }, "description": { "type": "string" }, "builtin": { "type": "boolean" } }, "required": [ "id", "label", "type", "builtin" ], "additionalProperties": false } } }, "additionalProperties": false, "description": "Legacy combined wait + AI conversation block." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "WAIT_FOR_REPLY" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "maxTimeout": { "description": "How long to wait for the first reply before timing out.", "type": "string" } }, "additionalProperties": false, "description": "Waits for the person to reply." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "MANAGE_CONVERSATION" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "mode": { "description": "AGENT (AI-led) or ESCALATE (human handoff). Defaults to AGENT.", "type": "string", "enum": [ "AGENT", "ESCALATE" ] }, "inactivityTimeout": { "description": "Optional custom idle window (e.g. '2h', '30m') that overrides the global inactive-conversation close. Resets on each inbound message; after this much silence the node closes the conversation (routes CLOSED). Hard cap 24h; under 30m is allowed but flagged 'not recommended'. Requires the journey-inactivity-timeout flag.", "type": "string" } }, "additionalProperties": false, "description": "Runs the AI-led conversation." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "DISPATCH_EVENT" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "eventName": { "type": "string", "minLength": 1, "description": "CDP event name to record. Must match the CDP name pattern." }, "properties": { "description": "Literal string values, or { var: path } bindings resolved to typed values at dispatch time.", "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "anyOf": [ { "type": "string" }, { "type": "object", "properties": { "var": { "type": "string" } }, "required": [ "var" ], "additionalProperties": false } ] } }, "description": { "type": "string" } }, "required": [ "eventName" ], "additionalProperties": false, "description": "Records a CDP event for the person." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "DELAY" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "mode": { "description": "How the wait is measured. Defaults to duration.", "type": "string", "enum": [ "duration", "until_date", "until_weekday" ] }, "duration": { "description": "For mode duration.", "type": "string" }, "targetAt": { "description": "ISO 8601 instant, for mode until_date.", "type": "string" }, "weekdays": { "description": "ISO weekdays 1=Mon..7=Sun, for mode until_weekday.", "type": "array", "items": { "type": "integer", "minimum": 1, "maximum": 7 } }, "windowStartMinutes": { "type": "integer", "minimum": 0, "maximum": 1439 }, "windowEndMinutes": { "type": "integer", "minimum": 0, "maximum": 1439 }, "timezone": { "description": "IANA timezone. Load-bearing for until_weekday.", "type": "string" }, "description": { "type": "string" } }, "additionalProperties": false, "description": "Pauses the run." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "DECISION" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "logic": { "type": "string", "enum": [ "AND", "OR" ] }, "conditions": { "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "value" }, "selectionPath": { "type": "string", "description": "Dot-path into the run; must start with one of \"engagement.workflowState.\", \"engagement.extracted.\", \"engagement.nodeOutputs.\" (e.g. engagement.workflowState.totalPrice). customer.*, person.*, attributes.* and engagement.context.* are NOT resolvable here." }, "operator": { "type": "string", "enum": [ "eq", "neq", "gt", "lt", "contains", "isSet" ] }, "value": { "type": "string" } }, "required": [ "kind", "selectionPath", "operator", "value" ], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "event" }, "eventName": { "type": "string" }, "subjectSelectionPath": { "type": "string", "description": "Dot-path into the run; must start with one of \"engagement.workflowState.\", \"engagement.extracted.\", \"engagement.nodeOutputs.\" (e.g. engagement.workflowState.totalPrice). customer.*, person.*, attributes.* and engagement.context.* are NOT resolvable here." }, "occurred": { "type": "boolean" } }, "required": [ "kind", "eventName", "subjectSelectionPath", "occurred" ], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "cdp_predicate" }, "term": { "type": "object", "properties": { "attr": { "type": "string", "minLength": 1, "description": "Typed person column, `attributes.`, or `computed.`. See journeys_condition_catalog for the available attributes." }, "type": { "type": "string", "enum": [ "STRING", "NUMBER", "BOOLEAN", "DATE", "JSON", "ARRAY" ], "description": "CDP attribute type. Determines which `op` values are legal — see journeys_condition_catalog." }, "op": { "type": "string", "minLength": 1, "description": "Segments OperatorEnum value (eq | neq | gt | lt | in_last_n | ...). Must be legal for `type` — see journeys_condition_catalog." }, "value": { "description": "Shape depends on `op`: a plain scalar for eq/neq/gt/lt/starts_with/…, an array for in/not_in/contains/not_contains, {from, to} for between, {amount, unit} for in_last_n/in_next_n/more_than_n_ago/more_than_n_from_now, {minAmount, maxAmount, unit} for between_n_and_m_ago, {daysOffset} for exactly_n_from_today. Omit entirely for is_null/is_not_null.", "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" }, { "type": "array", "items": { "anyOf": [ { "type": "string" }, { "type": "number" } ] } }, { "type": "object", "properties": { "from": { "type": "string" }, "to": { "type": "string" } }, "required": [ "from", "to" ], "additionalProperties": false }, { "type": "object", "properties": { "amount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "amount", "unit" ], "additionalProperties": false }, { "type": "object", "properties": { "minAmount": { "type": "integer", "minimum": 0, "maximum": 9999 }, "maxAmount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "minAmount", "maxAmount", "unit" ], "additionalProperties": false }, { "type": "object", "properties": { "daysOffset": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "rollForward": { "type": "object", "properties": { "fromDow": { "type": "integer", "minimum": 0, "maximum": 6 }, "includeDows": { "minItems": 1, "type": "array", "items": { "type": "integer", "minimum": 0, "maximum": 6 } } }, "required": [ "fromDow", "includeDows" ], "additionalProperties": false } }, "required": [ "daysOffset" ], "additionalProperties": false } ] } }, "required": [ "attr", "type", "op" ], "additionalProperties": false, "description": "A single live person/computed predicate term. See journeys_condition_catalog for its shape and the legal operator/value pairing." } }, "required": [ "kind", "term" ], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "cdp_object" }, "objectType": { "type": "string" }, "matchAttr": { "type": "string" }, "matchSelectionPath": { "type": "string", "description": "Dot-path into the run; must start with one of \"engagement.workflowState.\", \"engagement.extracted.\", \"engagement.nodeOutputs.\" (e.g. engagement.workflowState.totalPrice). customer.*, person.*, attributes.* and engagement.context.* are NOT resolvable here." }, "exists": { "type": "boolean" } }, "required": [ "kind", "objectType", "matchAttr", "matchSelectionPath", "exists" ], "additionalProperties": false } ], "description": "One decision condition." } }, "description": { "type": "string" } }, "required": [ "logic", "conditions" ], "additionalProperties": false, "description": "Two-way branch. Emits YES / NO." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "CASE" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "selectionPath": { "type": "string", "description": "Value to switch on; must start with one of \"attributes.\", \"engagement.extracted.\", \"engagement.nodeOutputs.\" (e.g. attributes.plan_tier)." }, "branches": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable branch id; edge handle is case:." }, "value": { "type": "string", "description": "Value matched. Unique within the node." }, "label": { "type": "string", "minLength": 1, "description": "Required. Names the variant in analytics and on canvas." } }, "required": [ "id", "value", "label" ], "additionalProperties": false }, "description": "Up to 10 branches. A case:default handle is always required." }, "description": { "type": "string" } }, "required": [ "selectionPath", "branches" ], "additionalProperties": false, "description": "N-way switch on a person attribute." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "RANDOM_SPLIT" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "arms": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable arm id; edge handle is split:." }, "weight": { "type": "integer", "minimum": 1, "maximum": 100, "description": "Integer percentage. A node's arms must total 100." }, "label": { "type": "string" } }, "required": [ "id", "weight" ], "additionalProperties": false }, "description": "At least 2 and at most 10 arms whose weights total exactly 100. There is no default handle — every roll lands on a declared arm." }, "description": { "type": "string" } }, "required": [ "arms" ], "additionalProperties": false, "description": "Randomly routes each run down one of N weighted arms." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "HTTP_REQUEST" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "method": { "type": "string", "enum": [ "GET", "POST", "PUT", "PATCH", "DELETE" ], "description": "HTTP method." }, "url": { "type": "string", "minLength": 1, "description": "Target URL. Supports {{variable}} placeholders." }, "headers": { "description": "Request headers as key/value pairs.", "type": "array", "items": { "type": "object", "properties": { "key": { "type": "string" }, "value": { "type": "string" } }, "required": [ "key", "value" ], "additionalProperties": false } }, "body": { "description": "Request body. mode none sends no body.", "type": "object", "properties": { "mode": { "type": "string", "enum": [ "none", "json", "raw" ] }, "content": { "type": "string" }, "contentType": { "type": "string" } }, "required": [ "mode" ], "additionalProperties": false }, "credentialId": { "description": "Deprecated/legacy: HttpCredential row id used to authenticate the request. Prefer credentialKey.", "type": "string" }, "credentialKey": { "description": "Logical credential key; the pinned environment selects the secret.", "type": "string" }, "timeoutMs": { "description": "Request timeout in milliseconds. Max 30000 (30s).", "type": "integer", "exclusiveMinimum": 0, "maximum": 30000 }, "maxAttempts": { "description": "Max attempts including the first. Max 5.", "type": "integer", "exclusiveMinimum": 0, "maximum": 5 }, "documentUrlTtlSeconds": { "description": "TTL (seconds, ≤86400) for presigned engagement.documents URLs this node emits. Default 86400.", "type": "integer", "exclusiveMinimum": 0, "maximum": 86400 } }, "required": [ "method", "url" ], "additionalProperties": false, "description": "Calls an external HTTP endpoint. Emits SUCCESS or FAILED." } }, "required": [ "id", "kind" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "EXIT" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "additionalProperties": false, "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "outcome": { "type": "string" }, "nextInitiativeId": { "description": "Chain into another initiative on exit.", "type": "string" } }, "additionalProperties": false, "description": "Terminal node." } }, "required": [ "id", "kind" ], "additionalProperties": false } ] }, "description": "The nodes. Exactly one ENTRY and at least one EXIT are required to publish." }, "edges": { "type": "array", "items": { "type": "object", "properties": { "from": { "type": "string", "description": "Source node id." }, "to": { "type": "string", "description": "Target node id." }, "sourceHandle": { "type": "string", "description": "The emitted signal that activates this edge (e.g. SENT, REPLIED, YES, case:). A handle may wire to at most one node." }, "metadata": { "type": "object", "properties": { "signalCategory": { "type": "string", "enum": [ "lifecycle", "system" ] }, "signalDescription": { "type": "string" } }, "additionalProperties": false } }, "required": [ "from", "to", "sourceHandle" ], "additionalProperties": false, "description": "A connection: node `from` routes to `to` when it emits `sourceHandle`." }, "description": "The connections between node handles." } }, "required": [ "name", "actions", "edges" ], "additionalProperties": false, "description": "The full journey graph." } }, "required": [ "id", "initiativeId", "status", "version", "definition" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } } }, "/api/v1/journeys/catalog": { "get": { "operationId": "journeys_authoring_catalog", "summary": "Node catalog", "description": "Describes every journey node kind — its inputs, its output handles (the signals it can emit), and the rules for connecting nodes. Read this before building or editing a journey.", "tags": [ "Journeys" ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "kinds": { "type": "array", "items": { "type": "object", "properties": { "kind": { "type": "string" }, "group": { "type": "string", "enum": [ "trigger", "action", "logic", "terminal" ] }, "description": { "type": "string" }, "outputHandles": { "type": "array", "items": { "type": "string" } }, "dynamicHandles": { "type": "string" }, "inputs": { "type": "array", "items": { "type": "object", "properties": { "name": { "type": "string" }, "type": { "type": "string" }, "required": { "type": "boolean" }, "description": { "type": "string" } }, "required": [ "name", "type", "required", "description" ], "additionalProperties": false } } }, "required": [ "kind", "group", "description", "outputHandles", "inputs" ], "additionalProperties": false } }, "graphRules": { "type": "array", "items": { "type": "string" } } }, "required": [ "kinds", "graphRules" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } } }, "/api/v1/journeys/condition-catalog": { "get": { "operationId": "journeys_condition_catalog", "summary": "Condition catalog", "description": "List the person attributes and computed attributes available for DECISION and CASE CONDITIONS, plus the custom object types. Attribute tokens are ready to use as condition selection paths (e.g. attributes.plan, computed.ltv). NOTE: these `attributes.*` tokens are ONLY for DECISION/CASE conditions — SEND_MESSAGE template bindings use a different syntax (`person.`); call journeys_message_variables for those. Also describes the cdp_predicate DECISION condition term shape: which `op` values are legal per attribute `type` (operatorsByType), and which `value` shape each `op` expects (cdpPredicateValueShapes).", "tags": [ "Journeys" ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "person": { "type": "array", "items": { "type": "object", "properties": { "attr": { "type": "string" }, "label": { "type": "string" }, "type": { "type": "string" } }, "required": [ "attr", "label", "type" ], "additionalProperties": false } }, "computed": { "type": "array", "items": { "type": "object", "properties": { "attr": { "type": "string" }, "label": { "type": "string" }, "type": { "type": "string" } }, "required": [ "attr", "label", "type" ], "additionalProperties": false } }, "objectTypes": { "type": "array", "items": { "type": "object", "properties": { "name": { "type": "string" }, "displayName": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "required": [ "name", "displayName" ], "additionalProperties": false } }, "operatorsByType": { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "type": "array", "items": { "type": "string" } }, "description": "Legal `op` values for a cdp_predicate condition term, keyed by its `type`." }, "cdpPredicateValueShapes": { "type": "string", "description": "Explains a cdp_predicate term's fields and the value shape each `op` expects." } }, "required": [ "person", "computed", "objectTypes", "operatorsByType", "cdpPredicateValueShapes" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } } }, "/api/v1/journeys/event-catalog": { "get": { "operationId": "journeys_event_catalog", "summary": "Event catalog", "description": "List the CDP event names seen for your organization. Use these for a cdp_event trigger, a DISPATCH_EVENT node, or an event-based DECISION condition.", "tags": [ "Journeys" ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "data": { "type": "array", "items": { "type": "object", "properties": { "name": { "type": "string" }, "description": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "required": [ "name", "description" ], "additionalProperties": false } } }, "required": [ "data" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } } }, "/api/v1/journeys/message-channels": { "get": { "operationId": "journeys_message_channels", "summary": "List message channels", "description": "List the WhatsApp channels a SEND_MESSAGE node can send from. Use a channel id as channelId on the node and to look up its approved templates.", "tags": [ "Journeys" ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "data": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "phoneNumber": { "type": "string" }, "isPrimary": { "type": "boolean" } }, "required": [ "id", "name", "phoneNumber", "isPrimary" ], "additionalProperties": false } } }, "required": [ "data" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } } }, "/api/v1/journeys/message-templates": { "get": { "operationId": "journeys_message_templates", "summary": "List message templates", "description": "List the approved WhatsApp templates a SEND_MESSAGE node can use from a given channel. A template belongs to one channel account, so pass the same channelId you pin on the node.", "tags": [ "Journeys" ], "parameters": [ { "name": "channelId", "in": "query", "required": true, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "minLength": 1, "description": "Channel id from journeys_message_channels." } } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "data": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "friendlyName": { "type": "string" }, "category": { "type": "string" }, "contentType": { "type": "string" } }, "required": [ "id", "friendlyName", "category", "contentType" ], "additionalProperties": false } } }, "required": [ "data" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } } }, "/api/v1/journeys/validate": { "post": { "operationId": "journeys_validate", "summary": "Validate journey", "description": "Dry-run the publish checks against a journey graph without saving. Pass a `journeyId` to validate the stored draft, or a `definition` to validate a graph as sent (exactly one of the two). Returns whether it is valid and the list of issues (errors block publishing; warnings are advisory). Use it to iterate a draft to valid before publishing in the app.", "tags": [ "Journeys" ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "journeyId": { "description": "Validate the stored draft: a draft journey id, or the initiative id (resolves to its current draft). Exactly one of journeyId or definition.", "type": "string", "minLength": 1 }, "definition": { "description": "Validate this graph as sent, without loading anything. Exactly one of journeyId or definition.", "type": "object", "properties": { "id": { "description": "Journey id; carried for round-trip ergonomics. Optional on create.", "type": "string" }, "name": { "type": "string", "minLength": 1, "description": "Journey name." }, "metadata": { "type": "object", "properties": { "initiativeType": { "type": "string" }, "version": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "cancelOnEvents": { "description": "Cancel an in-flight run when any of these events arrive.", "type": "object", "properties": { "eventNames": { "type": "array", "items": { "type": "string" } } }, "required": [ "eventNames" ] }, "environmentId": { "description": "Pinned environment whose non-secret {{env.*}} values HTTP nodes resolve against. Frozen at publish. The server preserves the stored value when a whole-graph update omits it.", "type": "string" } }, "description": "Optional journey-level metadata." }, "actions": { "minItems": 1, "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "ENTRY" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "description": { "type": "string" }, "triggerType": { "description": "How people enter: manual (added by an operator or API call), segment (on entering a segment), or cdp_event (when an event is received). Defaults to manual.", "type": "string", "enum": [ "manual", "segment", "cdp_event" ] }, "segmentId": { "description": "Segment id — required when triggerType is segment.", "type": "string" }, "segmentName": { "description": "Cached segment display name (optional).", "type": "string" }, "eventName": { "description": "CDP event name — required when triggerType is cdp_event.", "type": "string" }, "maxEnrollments": { "description": "Frequency cap: max enrollments per person within enrollmentWindow. Both-or-neither with enrollmentWindow.", "type": "integer", "minimum": 1, "maximum": 9007199254740991 }, "enrollmentWindow": { "description": "Rolling window for the frequency cap.", "type": "string" } }, "description": "Trigger node config. Exactly one ENTRY node per journey." } }, "required": [ "id", "kind" ] }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "SEND_MESSAGE" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "templateId": { "description": "Approved WhatsApp template id. Resolve ids from the catalog.", "type": "string" }, "templateName": { "type": "string" }, "channel": { "description": "Send channel. Only whatsapp is live today.", "type": "string", "enum": [ "whatsapp", "sms", "email" ] }, "templateBindings": { "description": "Map of template placeholder → variable reference.", "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "type": "string" } }, "channelId": { "description": "Sending WhatsApp channel (WABA) id. Required before publishing.", "type": "string" }, "sendImmediately": { "description": "Deprecated business-hours gate; prefer a preceding DELAY.", "type": "boolean" } }, "description": "Sends a WhatsApp template." } }, "required": [ "id", "kind" ] }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "CONVERSATION_BLOCK" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "goal": { "type": "string" }, "maxTimeout": { "description": "How long to wait for a reply before timing out.", "type": "string" }, "mode": { "type": "string", "enum": [ "AGENT", "ESCALATE" ] }, "outputs": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "label": { "type": "string" }, "type": { "type": "string", "enum": [ "string", "number", "date", "boolean", "json" ] }, "description": { "type": "string" }, "builtin": { "type": "boolean" } }, "required": [ "id", "label", "type", "builtin" ] } } }, "description": "Legacy combined wait + AI conversation block." } }, "required": [ "id", "kind" ] }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "WAIT_FOR_REPLY" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "maxTimeout": { "description": "How long to wait for the first reply before timing out.", "type": "string" } }, "description": "Waits for the person to reply." } }, "required": [ "id", "kind" ] }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "MANAGE_CONVERSATION" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "mode": { "description": "AGENT (AI-led) or ESCALATE (human handoff). Defaults to AGENT.", "type": "string", "enum": [ "AGENT", "ESCALATE" ] }, "inactivityTimeout": { "description": "Optional custom idle window (e.g. '2h', '30m') that overrides the global inactive-conversation close. Resets on each inbound message; after this much silence the node closes the conversation (routes CLOSED). Hard cap 24h; under 30m is allowed but flagged 'not recommended'. Requires the journey-inactivity-timeout flag.", "type": "string" } }, "description": "Runs the AI-led conversation." } }, "required": [ "id", "kind" ] }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "DISPATCH_EVENT" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "eventName": { "type": "string", "minLength": 1, "description": "CDP event name to record. Must match the CDP name pattern." }, "properties": { "description": "Literal string values, or { var: path } bindings resolved to typed values at dispatch time.", "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "anyOf": [ { "type": "string" }, { "type": "object", "properties": { "var": { "type": "string" } }, "required": [ "var" ] } ] } }, "description": { "type": "string" } }, "required": [ "eventName" ], "description": "Records a CDP event for the person." } }, "required": [ "id", "kind" ] }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "DELAY" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "mode": { "description": "How the wait is measured. Defaults to duration.", "type": "string", "enum": [ "duration", "until_date", "until_weekday" ] }, "duration": { "description": "For mode duration.", "type": "string" }, "targetAt": { "description": "ISO 8601 instant, for mode until_date.", "type": "string" }, "weekdays": { "description": "ISO weekdays 1=Mon..7=Sun, for mode until_weekday.", "type": "array", "items": { "type": "integer", "minimum": 1, "maximum": 7 } }, "windowStartMinutes": { "type": "integer", "minimum": 0, "maximum": 1439 }, "windowEndMinutes": { "type": "integer", "minimum": 0, "maximum": 1439 }, "timezone": { "description": "IANA timezone. Load-bearing for until_weekday.", "type": "string" }, "description": { "type": "string" } }, "description": "Pauses the run." } }, "required": [ "id", "kind" ] }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "DECISION" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "logic": { "type": "string", "enum": [ "AND", "OR" ] }, "conditions": { "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "value" }, "selectionPath": { "type": "string", "description": "Dot-path into the run; must start with one of \"engagement.workflowState.\", \"engagement.extracted.\", \"engagement.nodeOutputs.\" (e.g. engagement.workflowState.totalPrice). customer.*, person.*, attributes.* and engagement.context.* are NOT resolvable here." }, "operator": { "type": "string", "enum": [ "eq", "neq", "gt", "lt", "contains", "isSet" ] }, "value": { "type": "string" } }, "required": [ "kind", "selectionPath", "operator", "value" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "event" }, "eventName": { "type": "string" }, "subjectSelectionPath": { "type": "string", "description": "Dot-path into the run; must start with one of \"engagement.workflowState.\", \"engagement.extracted.\", \"engagement.nodeOutputs.\" (e.g. engagement.workflowState.totalPrice). customer.*, person.*, attributes.* and engagement.context.* are NOT resolvable here." }, "occurred": { "type": "boolean" } }, "required": [ "kind", "eventName", "subjectSelectionPath", "occurred" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "cdp_predicate" }, "term": { "type": "object", "properties": { "attr": { "type": "string", "minLength": 1, "description": "Typed person column, `attributes.`, or `computed.`. See journeys_condition_catalog for the available attributes." }, "type": { "type": "string", "enum": [ "STRING", "NUMBER", "BOOLEAN", "DATE", "JSON", "ARRAY" ], "description": "CDP attribute type. Determines which `op` values are legal — see journeys_condition_catalog." }, "op": { "type": "string", "minLength": 1, "description": "Segments OperatorEnum value (eq | neq | gt | lt | in_last_n | ...). Must be legal for `type` — see journeys_condition_catalog." }, "value": { "description": "Shape depends on `op`: a plain scalar for eq/neq/gt/lt/starts_with/…, an array for in/not_in/contains/not_contains, {from, to} for between, {amount, unit} for in_last_n/in_next_n/more_than_n_ago/more_than_n_from_now, {minAmount, maxAmount, unit} for between_n_and_m_ago, {daysOffset} for exactly_n_from_today. Omit entirely for is_null/is_not_null.", "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" }, { "type": "array", "items": { "anyOf": [ { "type": "string" }, { "type": "number" } ] } }, { "type": "object", "properties": { "from": { "type": "string" }, "to": { "type": "string" } }, "required": [ "from", "to" ] }, { "type": "object", "properties": { "amount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "amount", "unit" ] }, { "type": "object", "properties": { "minAmount": { "type": "integer", "minimum": 0, "maximum": 9999 }, "maxAmount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "minAmount", "maxAmount", "unit" ] }, { "type": "object", "properties": { "daysOffset": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "rollForward": { "type": "object", "properties": { "fromDow": { "type": "integer", "minimum": 0, "maximum": 6 }, "includeDows": { "minItems": 1, "type": "array", "items": { "type": "integer", "minimum": 0, "maximum": 6 } } }, "required": [ "fromDow", "includeDows" ] } }, "required": [ "daysOffset" ] } ] } }, "required": [ "attr", "type", "op" ], "description": "A single live person/computed predicate term. See journeys_condition_catalog for its shape and the legal operator/value pairing." } }, "required": [ "kind", "term" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "cdp_object" }, "objectType": { "type": "string" }, "matchAttr": { "type": "string" }, "matchSelectionPath": { "type": "string", "description": "Dot-path into the run; must start with one of \"engagement.workflowState.\", \"engagement.extracted.\", \"engagement.nodeOutputs.\" (e.g. engagement.workflowState.totalPrice). customer.*, person.*, attributes.* and engagement.context.* are NOT resolvable here." }, "exists": { "type": "boolean" } }, "required": [ "kind", "objectType", "matchAttr", "matchSelectionPath", "exists" ] } ], "description": "One decision condition." } }, "description": { "type": "string" } }, "required": [ "logic", "conditions" ], "description": "Two-way branch. Emits YES / NO." } }, "required": [ "id", "kind" ] }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "CASE" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "selectionPath": { "type": "string", "description": "Value to switch on; must start with one of \"attributes.\", \"engagement.extracted.\", \"engagement.nodeOutputs.\" (e.g. attributes.plan_tier)." }, "branches": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable branch id; edge handle is case:." }, "value": { "type": "string", "description": "Value matched. Unique within the node." }, "label": { "type": "string", "minLength": 1, "description": "Required. Names the variant in analytics and on canvas." } }, "required": [ "id", "value", "label" ] }, "description": "Up to 10 branches. A case:default handle is always required." }, "description": { "type": "string" } }, "required": [ "selectionPath", "branches" ], "description": "N-way switch on a person attribute." } }, "required": [ "id", "kind" ] }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "RANDOM_SPLIT" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "arms": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable arm id; edge handle is split:." }, "weight": { "type": "integer", "minimum": 1, "maximum": 100, "description": "Integer percentage. A node's arms must total 100." }, "label": { "type": "string" } }, "required": [ "id", "weight" ] }, "description": "At least 2 and at most 10 arms whose weights total exactly 100. There is no default handle — every roll lands on a declared arm." }, "description": { "type": "string" } }, "required": [ "arms" ], "description": "Randomly routes each run down one of N weighted arms." } }, "required": [ "id", "kind" ] }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "HTTP_REQUEST" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "method": { "type": "string", "enum": [ "GET", "POST", "PUT", "PATCH", "DELETE" ], "description": "HTTP method." }, "url": { "type": "string", "minLength": 1, "description": "Target URL. Supports {{variable}} placeholders." }, "headers": { "description": "Request headers as key/value pairs.", "type": "array", "items": { "type": "object", "properties": { "key": { "type": "string" }, "value": { "type": "string" } }, "required": [ "key", "value" ] } }, "body": { "description": "Request body. mode none sends no body.", "type": "object", "properties": { "mode": { "type": "string", "enum": [ "none", "json", "raw" ] }, "content": { "type": "string" }, "contentType": { "type": "string" } }, "required": [ "mode" ] }, "credentialId": { "description": "Deprecated/legacy: HttpCredential row id used to authenticate the request. Prefer credentialKey.", "type": "string" }, "credentialKey": { "description": "Logical credential key; the pinned environment selects the secret.", "type": "string" }, "timeoutMs": { "description": "Request timeout in milliseconds. Max 30000 (30s).", "type": "integer", "exclusiveMinimum": 0, "maximum": 30000 }, "maxAttempts": { "description": "Max attempts including the first. Max 5.", "type": "integer", "exclusiveMinimum": 0, "maximum": 5 }, "documentUrlTtlSeconds": { "description": "TTL (seconds, ≤86400) for presigned engagement.documents URLs this node emits. Default 86400.", "type": "integer", "exclusiveMinimum": 0, "maximum": 86400 } }, "required": [ "method", "url" ], "description": "Calls an external HTTP endpoint. Emits SUCCESS or FAILED." } }, "required": [ "id", "kind" ] }, { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Node id, unique within the journey." }, "kind": { "type": "string", "const": "EXIT" }, "name": { "type": "string", "minLength": 1, "description": "The label shown on the canvas. Required before publishing." }, "position": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": [ "x", "y" ], "description": "Explicit canvas position. Omit it and the server auto-lays-out the graph top-down; only set it to preserve a hand-arranged layout." }, "inputs": { "type": "object", "properties": { "outcome": { "type": "string" }, "nextInitiativeId": { "description": "Chain into another initiative on exit.", "type": "string" } }, "description": "Terminal node." } }, "required": [ "id", "kind" ] } ] }, "description": "The nodes. Exactly one ENTRY and at least one EXIT are required to publish." }, "edges": { "type": "array", "items": { "type": "object", "properties": { "from": { "type": "string", "description": "Source node id." }, "to": { "type": "string", "description": "Target node id." }, "sourceHandle": { "type": "string", "description": "The emitted signal that activates this edge (e.g. SENT, REPLIED, YES, case:). A handle may wire to at most one node." }, "metadata": { "type": "object", "properties": { "signalCategory": { "type": "string", "enum": [ "lifecycle", "system" ] }, "signalDescription": { "type": "string" } } } }, "required": [ "from", "to", "sourceHandle" ], "description": "A connection: node `from` routes to `to` when it emits `sourceHandle`." }, "description": "The connections between node handles." } }, "required": [ "name", "actions", "edges" ] } } } } } }, "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "valid": { "type": "boolean", "description": "True when there are no error-severity issues." }, "issues": { "type": "array", "items": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable issue code." }, "severity": { "type": "string", "enum": [ "error", "warning" ], "description": "error blocks publishing; warning is advisory." }, "nodeId": { "description": "The node this issue is about, if any.", "type": "string" }, "message": { "type": "string", "description": "Plain-English explanation." } }, "required": [ "code", "severity", "message" ], "additionalProperties": false } } }, "required": [ "valid", "issues" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } } }, "/api/v1/segments": { "get": { "operationId": "segments_list", "summary": "List segments", "description": "List the organization's active segments, newest first. Archived segments are excluded.", "tags": [ "Segments" ], "parameters": [ { "name": "limit", "in": "query", "required": false, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "default": 100, "description": "Max items to return, 1-1000 (default 100).", "type": "integer", "minimum": 1, "maximum": 1000 } }, { "name": "cursor", "in": "query", "required": false, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "description": "Opaque pagination token from a previous response's `next_cursor`. Omit for the first page.", "type": "string" } } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "data": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable internal identifier. Pass this wherever a segment reference is stored — e.g. a journey trigger's segmentId." }, "slug": { "type": "string", "description": "Unique identifier within your organization." }, "name": { "type": "string" }, "description": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "evaluationCadence": { "type": "string", "enum": [ "REACTIVE_ONLY", "HOURLY", "DAILY" ], "description": "How often the segment is re-evaluated. REACTIVE_ONLY segments only change when evaluated explicitly." }, "memberCount": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Live count of currently active members." }, "lastEvaluatedAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "ISO 8601 timestamp; null if the segment has never evaluated." }, "createdAt": { "type": "string", "description": "ISO 8601 timestamp." } }, "required": [ "id", "slug", "name", "description", "evaluationCadence", "memberCount", "lastEvaluatedAt", "createdAt" ], "additionalProperties": false } }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Opaque cursor for the next page; null on the last page." } }, "required": [ "data", "next_cursor" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } }, "post": { "operationId": "segments_create", "summary": "Create a segment", "description": "Create a segment from a filter expression. It starts empty until evaluated. Validate and preview the filter first.", "tags": [ "Segments" ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "name": { "type": "string", "minLength": 1, "maxLength": 120, "description": "Display name." }, "slug": { "type": "string", "minLength": 1, "maxLength": 64, "pattern": "^[a-z0-9]+(-[a-z0-9]+)*$", "description": "Permanent identifier, lowercase-kebab-case, unique in your organization. Cannot be changed after creation." }, "description": { "anyOf": [ { "type": "string", "maxLength": 1024 }, { "type": "null" } ] }, "filterExpression": { "description": "The audience filter: a tree of predicates over person attributes, related data, and events. Discover valid `attr` tokens and operators with segments_catalog (GET /api/v1/segments/catalog).", "type": "object", "properties": { "kind": { "type": "string", "const": "person" }, "op": { "type": "string", "enum": [ "AND", "OR" ] }, "predicates": { "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "has_relationship" }, "connector": { "type": "string", "enum": [ "AND", "OR" ] }, "customObjectType": { "type": "string", "minLength": 1 }, "attributeFilters": { "type": "array", "items": { "type": "object", "properties": { "attr": { "type": "string" }, "path": { "minItems": 1, "maxItems": 5, "type": "array", "items": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*$" } }, "type": { "type": "string", "enum": [ "STRING", "NUMBER", "BOOLEAN", "DATE", "JSON", "ARRAY" ] }, "op": { "type": "string", "enum": [ "eq", "neq", "in", "not_in", "contains", "not_contains", "starts_with", "ends_with", "gt", "gte", "lt", "lte", "on", "before", "after", "between", "in_last_n", "in_next_n", "more_than_n_ago", "more_than_n_from_now", "between_n_and_m_ago", "exactly_n_from_today", "is_null", "is_not_null" ] }, "value": { "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" }, { "type": "array", "items": { "anyOf": [ { "type": "string" }, { "type": "number" } ] } }, { "type": "object", "properties": { "from": { "type": "string" }, "to": { "type": "string" } }, "required": [ "from", "to" ] }, { "type": "object", "properties": { "amount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "amount", "unit" ] }, { "type": "object", "properties": { "minAmount": { "type": "integer", "minimum": 0, "maximum": 9999 }, "maxAmount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "minAmount", "maxAmount", "unit" ] }, { "type": "object", "properties": { "daysOffset": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "rollForward": { "type": "object", "properties": { "fromDow": { "type": "integer", "minimum": 0, "maximum": 6 }, "includeDows": { "minItems": 1, "type": "array", "items": { "type": "integer", "minimum": 0, "maximum": 6 } } }, "required": [ "fromDow", "includeDows" ] } }, "required": [ "daysOffset" ] } ] } }, "required": [ "attr", "type", "op" ] } }, "path": { "minItems": 1, "maxItems": 3, "type": "array", "items": { "type": "object", "properties": { "customObjectType": { "type": "string", "minLength": 1 }, "direction": { "type": "string", "enum": [ "parent_to_child", "child_to_parent" ] }, "relationshipType": { "type": "string", "minLength": 1 }, "attributeFilters": { "type": "array", "items": { "type": "object", "properties": { "attr": { "type": "string" }, "path": { "minItems": 1, "maxItems": 5, "type": "array", "items": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*$" } }, "type": { "type": "string", "enum": [ "STRING", "NUMBER", "BOOLEAN", "DATE", "JSON", "ARRAY" ] }, "op": { "type": "string", "enum": [ "eq", "neq", "in", "not_in", "contains", "not_contains", "starts_with", "ends_with", "gt", "gte", "lt", "lte", "on", "before", "after", "between", "in_last_n", "in_next_n", "more_than_n_ago", "more_than_n_from_now", "between_n_and_m_ago", "exactly_n_from_today", "is_null", "is_not_null" ] }, "value": { "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" }, { "type": "array", "items": { "anyOf": [ { "type": "string" }, { "type": "number" } ] } }, { "type": "object", "properties": { "from": { "type": "string" }, "to": { "type": "string" } }, "required": [ "from", "to" ] }, { "type": "object", "properties": { "amount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "amount", "unit" ] }, { "type": "object", "properties": { "minAmount": { "type": "integer", "minimum": 0, "maximum": 9999 }, "maxAmount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "minAmount", "maxAmount", "unit" ] }, { "type": "object", "properties": { "daysOffset": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "rollForward": { "type": "object", "properties": { "fromDow": { "type": "integer", "minimum": 0, "maximum": 6 }, "includeDows": { "minItems": 1, "type": "array", "items": { "type": "integer", "minimum": 0, "maximum": 6 } } }, "required": [ "fromDow", "includeDows" ] } }, "required": [ "daysOffset" ] } ] } }, "required": [ "attr", "type", "op" ] } } }, "required": [ "customObjectType", "attributeFilters" ] } }, "exists": { "description": "Polarity of the relationship match. Absent or true = HAS the relationship (EXISTS). false = does NOT have it (NOT EXISTS): no related object satisfies this card, which INCLUDES people who have no such object at all. Conditions are allowed and apply inside the negation — \"has no order with status=completed\" matches people whose orders are all non-completed AND people with zero orders. To exclude the latter, add a second positive card for the same relationship.", "type": "boolean" } }, "required": [ "kind", "customObjectType", "attributeFilters" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "person_attribute" }, "connector": { "type": "string", "enum": [ "AND", "OR" ] }, "attr": { "type": "string" }, "path": { "minItems": 1, "maxItems": 5, "type": "array", "items": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*$" } }, "type": { "type": "string", "enum": [ "STRING", "NUMBER", "BOOLEAN", "DATE", "JSON", "ARRAY" ] }, "op": { "type": "string", "enum": [ "eq", "neq", "in", "not_in", "contains", "not_contains", "starts_with", "ends_with", "gt", "gte", "lt", "lte", "on", "before", "after", "between", "in_last_n", "in_next_n", "more_than_n_ago", "more_than_n_from_now", "between_n_and_m_ago", "exactly_n_from_today", "is_null", "is_not_null" ] }, "value": { "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" }, { "type": "array", "items": { "anyOf": [ { "type": "string" }, { "type": "number" } ] } }, { "type": "object", "properties": { "from": { "type": "string" }, "to": { "type": "string" } }, "required": [ "from", "to" ] }, { "type": "object", "properties": { "amount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "amount", "unit" ] }, { "type": "object", "properties": { "minAmount": { "type": "integer", "minimum": 0, "maximum": 9999 }, "maxAmount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "minAmount", "maxAmount", "unit" ] }, { "type": "object", "properties": { "daysOffset": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "rollForward": { "type": "object", "properties": { "fromDow": { "type": "integer", "minimum": 0, "maximum": 6 }, "includeDows": { "minItems": 1, "type": "array", "items": { "type": "integer", "minimum": 0, "maximum": 6 } } }, "required": [ "fromDow", "includeDows" ] } }, "required": [ "daysOffset" ] } ] } }, "required": [ "kind", "attr", "type", "op" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "person_group" }, "connector": { "type": "string", "enum": [ "AND", "OR" ] }, "filters": { "minItems": 1, "type": "array", "items": { "type": "object", "properties": { "attr": { "type": "string" }, "path": { "minItems": 1, "maxItems": 5, "type": "array", "items": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*$" } }, "type": { "type": "string", "enum": [ "STRING", "NUMBER", "BOOLEAN", "DATE", "JSON", "ARRAY" ] }, "op": { "type": "string", "enum": [ "eq", "neq", "in", "not_in", "contains", "not_contains", "starts_with", "ends_with", "gt", "gte", "lt", "lte", "on", "before", "after", "between", "in_last_n", "in_next_n", "more_than_n_ago", "more_than_n_from_now", "between_n_and_m_ago", "exactly_n_from_today", "is_null", "is_not_null" ] }, "value": { "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" }, { "type": "array", "items": { "anyOf": [ { "type": "string" }, { "type": "number" } ] } }, { "type": "object", "properties": { "from": { "type": "string" }, "to": { "type": "string" } }, "required": [ "from", "to" ] }, { "type": "object", "properties": { "amount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "amount", "unit" ] }, { "type": "object", "properties": { "minAmount": { "type": "integer", "minimum": 0, "maximum": 9999 }, "maxAmount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "minAmount", "maxAmount", "unit" ] }, { "type": "object", "properties": { "daysOffset": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "rollForward": { "type": "object", "properties": { "fromDow": { "type": "integer", "minimum": 0, "maximum": 6 }, "includeDows": { "minItems": 1, "type": "array", "items": { "type": "integer", "minimum": 0, "maximum": 6 } } }, "required": [ "fromDow", "includeDows" ] } }, "required": [ "daysOffset" ] } ] } }, "required": [ "attr", "type", "op" ] } } }, "required": [ "kind", "filters" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "event" }, "connector": { "type": "string", "enum": [ "AND", "OR" ] }, "eventName": { "type": "string", "minLength": 1 }, "occurred": { "type": "boolean" }, "propertyFilters": { "minItems": 1, "type": "array", "items": { "type": "object", "properties": { "key": { "type": "string", "minLength": 1 }, "path": { "minItems": 1, "maxItems": 5, "type": "array", "items": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*$" } }, "type": { "type": "string", "enum": [ "STRING", "NUMBER", "BOOLEAN", "DATE", "JSON", "ARRAY" ] }, "op": { "type": "string", "enum": [ "eq", "neq", "in", "not_in", "contains", "not_contains", "starts_with", "ends_with", "gt", "gte", "lt", "lte", "on", "before", "after", "between", "in_last_n", "in_next_n", "more_than_n_ago", "more_than_n_from_now", "between_n_and_m_ago", "exactly_n_from_today", "is_null", "is_not_null" ] }, "value": { "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" }, { "type": "array", "items": { "anyOf": [ { "type": "string" }, { "type": "number" } ] } }, { "type": "object", "properties": { "from": { "type": "string" }, "to": { "type": "string" } }, "required": [ "from", "to" ] }, { "type": "object", "properties": { "amount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "amount", "unit" ] }, { "type": "object", "properties": { "minAmount": { "type": "integer", "minimum": 0, "maximum": 9999 }, "maxAmount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "minAmount", "maxAmount", "unit" ] }, { "type": "object", "properties": { "daysOffset": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "rollForward": { "type": "object", "properties": { "fromDow": { "type": "integer", "minimum": 0, "maximum": 6 }, "includeDows": { "minItems": 1, "type": "array", "items": { "type": "integer", "minimum": 0, "maximum": 6 } } }, "required": [ "fromDow", "includeDows" ] } }, "required": [ "daysOffset" ] } ] } }, "required": [ "key", "type", "op" ] } }, "window": { "type": "object", "properties": { "op": { "type": "string", "enum": [ "in_last_n", "more_than_n_ago", "between_n_and_m_ago", "between", "before", "after", "on" ] }, "value": { "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" }, { "type": "array", "items": { "anyOf": [ { "type": "string" }, { "type": "number" } ] } }, { "type": "object", "properties": { "from": { "type": "string" }, "to": { "type": "string" } }, "required": [ "from", "to" ] }, { "type": "object", "properties": { "amount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "amount", "unit" ] }, { "type": "object", "properties": { "minAmount": { "type": "integer", "minimum": 0, "maximum": 9999 }, "maxAmount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "minAmount", "maxAmount", "unit" ] }, { "type": "object", "properties": { "daysOffset": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "rollForward": { "type": "object", "properties": { "fromDow": { "type": "integer", "minimum": 0, "maximum": 6 }, "includeDows": { "minItems": 1, "type": "array", "items": { "type": "integer", "minimum": 0, "maximum": 6 } } }, "required": [ "fromDow", "includeDows" ] } }, "required": [ "daysOffset" ] } ] } }, "required": [ "op" ] } }, "required": [ "kind", "eventName", "occurred" ] } ] } } }, "required": [ "kind", "op", "predicates" ] }, "evaluationCadence": { "default": "REACTIVE_ONLY", "description": "How often the segment re-evaluates. Defaults to REACTIVE_ONLY — evaluate on demand with segments_evaluate.", "type": "string", "enum": [ "REACTIVE_ONLY", "HOURLY", "DAILY" ] }, "dailyEvaluationHour": { "description": "For DAILY cadence: the hour (0-23, in your organization timezone) the segment evaluates.", "anyOf": [ { "type": "integer", "minimum": 0, "maximum": 23 }, { "type": "null" } ] }, "skipWeekendEvaluation": { "description": "When true, the segment is not evaluated on weekends.", "type": "boolean" }, "outputColumns": { "description": "Optional extra columns to project for each member when the segment feeds downstream automations.", "type": "object", "properties": { "person": { "type": "object", "properties": { "columns": { "maxItems": 7, "type": "array", "items": { "type": "string", "enum": [ "firstName", "lastName", "email", "phoneNumber", "externalId", "status", "createdAt" ] } }, "attributes": { "maxItems": 64, "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 120 } } }, "additionalProperties": false }, "customObjects": { "maxItems": 16, "type": "array", "items": { "type": "object", "properties": { "typeName": { "type": "string", "minLength": 1, "maxLength": 120 }, "attributes": { "minItems": 1, "maxItems": 64, "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 120 } }, "path": { "minItems": 1, "maxItems": 3, "type": "array", "items": { "type": "object", "properties": { "customObjectType": { "type": "string", "minLength": 1 }, "direction": { "type": "string", "enum": [ "parent_to_child", "child_to_parent" ] }, "relationshipType": { "type": "string", "minLength": 1 }, "attributeFilters": { "type": "array", "items": { "type": "object", "properties": { "attr": { "type": "string" }, "path": { "minItems": 1, "maxItems": 5, "type": "array", "items": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*$" } }, "type": { "type": "string", "enum": [ "STRING", "NUMBER", "BOOLEAN", "DATE", "JSON", "ARRAY" ] }, "op": { "type": "string", "enum": [ "eq", "neq", "in", "not_in", "contains", "not_contains", "starts_with", "ends_with", "gt", "gte", "lt", "lte", "on", "before", "after", "between", "in_last_n", "in_next_n", "more_than_n_ago", "more_than_n_from_now", "between_n_and_m_ago", "exactly_n_from_today", "is_null", "is_not_null" ] }, "value": { "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" }, { "type": "array", "items": { "anyOf": [ { "type": "string" }, { "type": "number" } ] } }, { "type": "object", "properties": { "from": { "type": "string" }, "to": { "type": "string" } }, "required": [ "from", "to" ] }, { "type": "object", "properties": { "amount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "amount", "unit" ] }, { "type": "object", "properties": { "minAmount": { "type": "integer", "minimum": 0, "maximum": 9999 }, "maxAmount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "minAmount", "maxAmount", "unit" ] }, { "type": "object", "properties": { "daysOffset": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "rollForward": { "type": "object", "properties": { "fromDow": { "type": "integer", "minimum": 0, "maximum": 6 }, "includeDows": { "minItems": 1, "type": "array", "items": { "type": "integer", "minimum": 0, "maximum": 6 } } }, "required": [ "fromDow", "includeDows" ] } }, "required": [ "daysOffset" ] } ] } }, "required": [ "attr", "type", "op" ] } } }, "required": [ "customObjectType", "attributeFilters" ] } }, "orderBy": { "type": "object", "properties": { "attribute": { "type": "string", "minLength": 1, "maxLength": 120 }, "direction": { "default": "desc", "type": "string", "enum": [ "asc", "desc" ] } }, "required": [ "attribute" ], "additionalProperties": false } }, "required": [ "typeName", "attributes" ], "additionalProperties": false } }, "computed": { "maxItems": 32, "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 120 } } }, "additionalProperties": false } }, "required": [ "name", "slug", "filterExpression" ] } } } }, "responses": { "201": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "id": { "type": "string", "description": "Stable internal identifier. Pass this wherever a segment reference is stored — e.g. a journey trigger's segmentId." }, "slug": { "type": "string", "description": "Unique identifier within your organization." }, "name": { "type": "string" }, "description": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "evaluationCadence": { "type": "string", "enum": [ "REACTIVE_ONLY", "HOURLY", "DAILY" ], "description": "How often the segment is re-evaluated. REACTIVE_ONLY segments only change when evaluated explicitly." }, "memberCount": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Live count of currently active members." }, "lastEvaluatedAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "ISO 8601 timestamp; null if the segment has never evaluated." }, "createdAt": { "type": "string", "description": "ISO 8601 timestamp." } }, "required": [ "id", "slug", "name", "description", "evaluationCadence", "memberCount", "lastEvaluatedAt", "createdAt" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } } }, "/api/v1/segments/{slug}": { "delete": { "operationId": "segments_delete", "summary": "Delete a segment", "description": "Remove a segment. It disappears from all lists and its journey triggers are disconnected. Idempotent.", "tags": [ "Segments" ], "parameters": [ { "name": "slug", "in": "path", "required": true, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "minLength": 1, "description": "The segment slug, as returned by segments_list." } } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "removed": { "type": "boolean", "description": "True when this call removed the segment; false when it was already gone." } }, "required": [ "removed" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } }, "get": { "operationId": "segments_get", "summary": "Get a segment", "description": "Get one segment by slug, with a live member count.", "tags": [ "Segments" ], "parameters": [ { "name": "slug", "in": "path", "required": true, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "minLength": 1, "description": "The segment slug, as returned by segments_list." } } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "id": { "type": "string", "description": "Stable internal identifier. Pass this wherever a segment reference is stored — e.g. a journey trigger's segmentId." }, "slug": { "type": "string", "description": "Unique identifier within your organization." }, "name": { "type": "string" }, "description": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "evaluationCadence": { "type": "string", "enum": [ "REACTIVE_ONLY", "HOURLY", "DAILY" ], "description": "How often the segment is re-evaluated. REACTIVE_ONLY segments only change when evaluated explicitly." }, "memberCount": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Live count of currently active members." }, "lastEvaluatedAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "ISO 8601 timestamp; null if the segment has never evaluated." }, "createdAt": { "type": "string", "description": "ISO 8601 timestamp." } }, "required": [ "id", "slug", "name", "description", "evaluationCadence", "memberCount", "lastEvaluatedAt", "createdAt" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } }, "patch": { "operationId": "segments_update", "summary": "Update a segment", "description": "Update a segment in place; the slug is permanent. Changing the filter doesn't re-evaluate membership until the next evaluation.", "tags": [ "Segments" ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "name": { "description": "Display name.", "type": "string", "minLength": 1, "maxLength": 120 }, "description": { "anyOf": [ { "type": "string", "maxLength": 1024 }, { "type": "null" } ] }, "filterExpression": { "description": "The audience filter: a tree of predicates over person attributes, related data, and events. Discover valid `attr` tokens and operators with segments_catalog (GET /api/v1/segments/catalog).", "type": "object", "properties": { "kind": { "type": "string", "const": "person" }, "op": { "type": "string", "enum": [ "AND", "OR" ] }, "predicates": { "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "has_relationship" }, "connector": { "type": "string", "enum": [ "AND", "OR" ] }, "customObjectType": { "type": "string", "minLength": 1 }, "attributeFilters": { "type": "array", "items": { "type": "object", "properties": { "attr": { "type": "string" }, "path": { "minItems": 1, "maxItems": 5, "type": "array", "items": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*$" } }, "type": { "type": "string", "enum": [ "STRING", "NUMBER", "BOOLEAN", "DATE", "JSON", "ARRAY" ] }, "op": { "type": "string", "enum": [ "eq", "neq", "in", "not_in", "contains", "not_contains", "starts_with", "ends_with", "gt", "gte", "lt", "lte", "on", "before", "after", "between", "in_last_n", "in_next_n", "more_than_n_ago", "more_than_n_from_now", "between_n_and_m_ago", "exactly_n_from_today", "is_null", "is_not_null" ] }, "value": { "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" }, { "type": "array", "items": { "anyOf": [ { "type": "string" }, { "type": "number" } ] } }, { "type": "object", "properties": { "from": { "type": "string" }, "to": { "type": "string" } }, "required": [ "from", "to" ] }, { "type": "object", "properties": { "amount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "amount", "unit" ] }, { "type": "object", "properties": { "minAmount": { "type": "integer", "minimum": 0, "maximum": 9999 }, "maxAmount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "minAmount", "maxAmount", "unit" ] }, { "type": "object", "properties": { "daysOffset": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "rollForward": { "type": "object", "properties": { "fromDow": { "type": "integer", "minimum": 0, "maximum": 6 }, "includeDows": { "minItems": 1, "type": "array", "items": { "type": "integer", "minimum": 0, "maximum": 6 } } }, "required": [ "fromDow", "includeDows" ] } }, "required": [ "daysOffset" ] } ] } }, "required": [ "attr", "type", "op" ] } }, "path": { "minItems": 1, "maxItems": 3, "type": "array", "items": { "type": "object", "properties": { "customObjectType": { "type": "string", "minLength": 1 }, "direction": { "type": "string", "enum": [ "parent_to_child", "child_to_parent" ] }, "relationshipType": { "type": "string", "minLength": 1 }, "attributeFilters": { "type": "array", "items": { "type": "object", "properties": { "attr": { "type": "string" }, "path": { "minItems": 1, "maxItems": 5, "type": "array", "items": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*$" } }, "type": { "type": "string", "enum": [ "STRING", "NUMBER", "BOOLEAN", "DATE", "JSON", "ARRAY" ] }, "op": { "type": "string", "enum": [ "eq", "neq", "in", "not_in", "contains", "not_contains", "starts_with", "ends_with", "gt", "gte", "lt", "lte", "on", "before", "after", "between", "in_last_n", "in_next_n", "more_than_n_ago", "more_than_n_from_now", "between_n_and_m_ago", "exactly_n_from_today", "is_null", "is_not_null" ] }, "value": { "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" }, { "type": "array", "items": { "anyOf": [ { "type": "string" }, { "type": "number" } ] } }, { "type": "object", "properties": { "from": { "type": "string" }, "to": { "type": "string" } }, "required": [ "from", "to" ] }, { "type": "object", "properties": { "amount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "amount", "unit" ] }, { "type": "object", "properties": { "minAmount": { "type": "integer", "minimum": 0, "maximum": 9999 }, "maxAmount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "minAmount", "maxAmount", "unit" ] }, { "type": "object", "properties": { "daysOffset": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "rollForward": { "type": "object", "properties": { "fromDow": { "type": "integer", "minimum": 0, "maximum": 6 }, "includeDows": { "minItems": 1, "type": "array", "items": { "type": "integer", "minimum": 0, "maximum": 6 } } }, "required": [ "fromDow", "includeDows" ] } }, "required": [ "daysOffset" ] } ] } }, "required": [ "attr", "type", "op" ] } } }, "required": [ "customObjectType", "attributeFilters" ] } }, "exists": { "description": "Polarity of the relationship match. Absent or true = HAS the relationship (EXISTS). false = does NOT have it (NOT EXISTS): no related object satisfies this card, which INCLUDES people who have no such object at all. Conditions are allowed and apply inside the negation — \"has no order with status=completed\" matches people whose orders are all non-completed AND people with zero orders. To exclude the latter, add a second positive card for the same relationship.", "type": "boolean" } }, "required": [ "kind", "customObjectType", "attributeFilters" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "person_attribute" }, "connector": { "type": "string", "enum": [ "AND", "OR" ] }, "attr": { "type": "string" }, "path": { "minItems": 1, "maxItems": 5, "type": "array", "items": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*$" } }, "type": { "type": "string", "enum": [ "STRING", "NUMBER", "BOOLEAN", "DATE", "JSON", "ARRAY" ] }, "op": { "type": "string", "enum": [ "eq", "neq", "in", "not_in", "contains", "not_contains", "starts_with", "ends_with", "gt", "gte", "lt", "lte", "on", "before", "after", "between", "in_last_n", "in_next_n", "more_than_n_ago", "more_than_n_from_now", "between_n_and_m_ago", "exactly_n_from_today", "is_null", "is_not_null" ] }, "value": { "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" }, { "type": "array", "items": { "anyOf": [ { "type": "string" }, { "type": "number" } ] } }, { "type": "object", "properties": { "from": { "type": "string" }, "to": { "type": "string" } }, "required": [ "from", "to" ] }, { "type": "object", "properties": { "amount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "amount", "unit" ] }, { "type": "object", "properties": { "minAmount": { "type": "integer", "minimum": 0, "maximum": 9999 }, "maxAmount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "minAmount", "maxAmount", "unit" ] }, { "type": "object", "properties": { "daysOffset": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "rollForward": { "type": "object", "properties": { "fromDow": { "type": "integer", "minimum": 0, "maximum": 6 }, "includeDows": { "minItems": 1, "type": "array", "items": { "type": "integer", "minimum": 0, "maximum": 6 } } }, "required": [ "fromDow", "includeDows" ] } }, "required": [ "daysOffset" ] } ] } }, "required": [ "kind", "attr", "type", "op" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "person_group" }, "connector": { "type": "string", "enum": [ "AND", "OR" ] }, "filters": { "minItems": 1, "type": "array", "items": { "type": "object", "properties": { "attr": { "type": "string" }, "path": { "minItems": 1, "maxItems": 5, "type": "array", "items": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*$" } }, "type": { "type": "string", "enum": [ "STRING", "NUMBER", "BOOLEAN", "DATE", "JSON", "ARRAY" ] }, "op": { "type": "string", "enum": [ "eq", "neq", "in", "not_in", "contains", "not_contains", "starts_with", "ends_with", "gt", "gte", "lt", "lte", "on", "before", "after", "between", "in_last_n", "in_next_n", "more_than_n_ago", "more_than_n_from_now", "between_n_and_m_ago", "exactly_n_from_today", "is_null", "is_not_null" ] }, "value": { "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" }, { "type": "array", "items": { "anyOf": [ { "type": "string" }, { "type": "number" } ] } }, { "type": "object", "properties": { "from": { "type": "string" }, "to": { "type": "string" } }, "required": [ "from", "to" ] }, { "type": "object", "properties": { "amount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "amount", "unit" ] }, { "type": "object", "properties": { "minAmount": { "type": "integer", "minimum": 0, "maximum": 9999 }, "maxAmount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "minAmount", "maxAmount", "unit" ] }, { "type": "object", "properties": { "daysOffset": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "rollForward": { "type": "object", "properties": { "fromDow": { "type": "integer", "minimum": 0, "maximum": 6 }, "includeDows": { "minItems": 1, "type": "array", "items": { "type": "integer", "minimum": 0, "maximum": 6 } } }, "required": [ "fromDow", "includeDows" ] } }, "required": [ "daysOffset" ] } ] } }, "required": [ "attr", "type", "op" ] } } }, "required": [ "kind", "filters" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "event" }, "connector": { "type": "string", "enum": [ "AND", "OR" ] }, "eventName": { "type": "string", "minLength": 1 }, "occurred": { "type": "boolean" }, "propertyFilters": { "minItems": 1, "type": "array", "items": { "type": "object", "properties": { "key": { "type": "string", "minLength": 1 }, "path": { "minItems": 1, "maxItems": 5, "type": "array", "items": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*$" } }, "type": { "type": "string", "enum": [ "STRING", "NUMBER", "BOOLEAN", "DATE", "JSON", "ARRAY" ] }, "op": { "type": "string", "enum": [ "eq", "neq", "in", "not_in", "contains", "not_contains", "starts_with", "ends_with", "gt", "gte", "lt", "lte", "on", "before", "after", "between", "in_last_n", "in_next_n", "more_than_n_ago", "more_than_n_from_now", "between_n_and_m_ago", "exactly_n_from_today", "is_null", "is_not_null" ] }, "value": { "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" }, { "type": "array", "items": { "anyOf": [ { "type": "string" }, { "type": "number" } ] } }, { "type": "object", "properties": { "from": { "type": "string" }, "to": { "type": "string" } }, "required": [ "from", "to" ] }, { "type": "object", "properties": { "amount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "amount", "unit" ] }, { "type": "object", "properties": { "minAmount": { "type": "integer", "minimum": 0, "maximum": 9999 }, "maxAmount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "minAmount", "maxAmount", "unit" ] }, { "type": "object", "properties": { "daysOffset": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "rollForward": { "type": "object", "properties": { "fromDow": { "type": "integer", "minimum": 0, "maximum": 6 }, "includeDows": { "minItems": 1, "type": "array", "items": { "type": "integer", "minimum": 0, "maximum": 6 } } }, "required": [ "fromDow", "includeDows" ] } }, "required": [ "daysOffset" ] } ] } }, "required": [ "key", "type", "op" ] } }, "window": { "type": "object", "properties": { "op": { "type": "string", "enum": [ "in_last_n", "more_than_n_ago", "between_n_and_m_ago", "between", "before", "after", "on" ] }, "value": { "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" }, { "type": "array", "items": { "anyOf": [ { "type": "string" }, { "type": "number" } ] } }, { "type": "object", "properties": { "from": { "type": "string" }, "to": { "type": "string" } }, "required": [ "from", "to" ] }, { "type": "object", "properties": { "amount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "amount", "unit" ] }, { "type": "object", "properties": { "minAmount": { "type": "integer", "minimum": 0, "maximum": 9999 }, "maxAmount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "minAmount", "maxAmount", "unit" ] }, { "type": "object", "properties": { "daysOffset": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "rollForward": { "type": "object", "properties": { "fromDow": { "type": "integer", "minimum": 0, "maximum": 6 }, "includeDows": { "minItems": 1, "type": "array", "items": { "type": "integer", "minimum": 0, "maximum": 6 } } }, "required": [ "fromDow", "includeDows" ] } }, "required": [ "daysOffset" ] } ] } }, "required": [ "op" ] } }, "required": [ "kind", "eventName", "occurred" ] } ] } } }, "required": [ "kind", "op", "predicates" ] }, "evaluationCadence": { "description": "How often the segment re-evaluates.", "type": "string", "enum": [ "REACTIVE_ONLY", "HOURLY", "DAILY" ] }, "dailyEvaluationHour": { "description": "For DAILY cadence: the hour (0-23, in your organization timezone) the segment evaluates. Set null to clear.", "anyOf": [ { "type": "integer", "minimum": 0, "maximum": 23 }, { "type": "null" } ] }, "skipWeekendEvaluation": { "description": "When true, the segment is not evaluated on weekends.", "type": "boolean" }, "outputColumns": { "description": "Optional extra columns to project for each member when the segment feeds downstream automations.", "type": "object", "properties": { "person": { "type": "object", "properties": { "columns": { "maxItems": 7, "type": "array", "items": { "type": "string", "enum": [ "firstName", "lastName", "email", "phoneNumber", "externalId", "status", "createdAt" ] } }, "attributes": { "maxItems": 64, "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 120 } } }, "additionalProperties": false }, "customObjects": { "maxItems": 16, "type": "array", "items": { "type": "object", "properties": { "typeName": { "type": "string", "minLength": 1, "maxLength": 120 }, "attributes": { "minItems": 1, "maxItems": 64, "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 120 } }, "path": { "minItems": 1, "maxItems": 3, "type": "array", "items": { "type": "object", "properties": { "customObjectType": { "type": "string", "minLength": 1 }, "direction": { "type": "string", "enum": [ "parent_to_child", "child_to_parent" ] }, "relationshipType": { "type": "string", "minLength": 1 }, "attributeFilters": { "type": "array", "items": { "type": "object", "properties": { "attr": { "type": "string" }, "path": { "minItems": 1, "maxItems": 5, "type": "array", "items": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*$" } }, "type": { "type": "string", "enum": [ "STRING", "NUMBER", "BOOLEAN", "DATE", "JSON", "ARRAY" ] }, "op": { "type": "string", "enum": [ "eq", "neq", "in", "not_in", "contains", "not_contains", "starts_with", "ends_with", "gt", "gte", "lt", "lte", "on", "before", "after", "between", "in_last_n", "in_next_n", "more_than_n_ago", "more_than_n_from_now", "between_n_and_m_ago", "exactly_n_from_today", "is_null", "is_not_null" ] }, "value": { "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" }, { "type": "array", "items": { "anyOf": [ { "type": "string" }, { "type": "number" } ] } }, { "type": "object", "properties": { "from": { "type": "string" }, "to": { "type": "string" } }, "required": [ "from", "to" ] }, { "type": "object", "properties": { "amount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "amount", "unit" ] }, { "type": "object", "properties": { "minAmount": { "type": "integer", "minimum": 0, "maximum": 9999 }, "maxAmount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "minAmount", "maxAmount", "unit" ] }, { "type": "object", "properties": { "daysOffset": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "rollForward": { "type": "object", "properties": { "fromDow": { "type": "integer", "minimum": 0, "maximum": 6 }, "includeDows": { "minItems": 1, "type": "array", "items": { "type": "integer", "minimum": 0, "maximum": 6 } } }, "required": [ "fromDow", "includeDows" ] } }, "required": [ "daysOffset" ] } ] } }, "required": [ "attr", "type", "op" ] } } }, "required": [ "customObjectType", "attributeFilters" ] } }, "orderBy": { "type": "object", "properties": { "attribute": { "type": "string", "minLength": 1, "maxLength": 120 }, "direction": { "default": "desc", "type": "string", "enum": [ "asc", "desc" ] } }, "required": [ "attribute" ], "additionalProperties": false } }, "required": [ "typeName", "attributes" ], "additionalProperties": false } }, "computed": { "maxItems": 32, "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 120 } } }, "additionalProperties": false } } } } } }, "parameters": [ { "name": "slug", "in": "path", "required": true, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "minLength": 1, "description": "The segment slug, as returned by segments_list." } } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "id": { "type": "string", "description": "Stable internal identifier. Pass this wherever a segment reference is stored — e.g. a journey trigger's segmentId." }, "slug": { "type": "string", "description": "Unique identifier within your organization." }, "name": { "type": "string" }, "description": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "evaluationCadence": { "type": "string", "enum": [ "REACTIVE_ONLY", "HOURLY", "DAILY" ], "description": "How often the segment is re-evaluated. REACTIVE_ONLY segments only change when evaluated explicitly." }, "memberCount": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Live count of currently active members." }, "lastEvaluatedAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "ISO 8601 timestamp; null if the segment has never evaluated." }, "createdAt": { "type": "string", "description": "ISO 8601 timestamp." } }, "required": [ "id", "slug", "name", "description", "evaluationCadence", "memberCount", "lastEvaluatedAt", "createdAt" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } } }, "/api/v1/segments/{slug}/evaluate": { "post": { "operationId": "segments_evaluate", "summary": "Evaluate a segment now", "description": "Re-evaluate a segment's membership now instead of waiting for its cadence. Runs synchronously; can take a while for large organizations.", "tags": [ "Segments" ], "parameters": [ { "name": "slug", "in": "path", "required": true, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "minLength": 1, "description": "The segment slug, as returned by segments_list." } } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "entrants": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "People added to the segment by this evaluation." }, "leavers": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "People removed from the segment by this evaluation." }, "total": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Total active members after this evaluation." } }, "required": [ "entrants", "leavers", "total" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } } }, "/api/v1/segments/{slug}/members": { "get": { "operationId": "segments_members_list", "summary": "List segment members", "description": "List a segment's active members, newest first.", "tags": [ "Segments" ], "parameters": [ { "name": "slug", "in": "path", "required": true, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "minLength": 1, "description": "The segment slug, as returned by segments_list." } }, { "name": "limit", "in": "query", "required": false, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "default": 100, "description": "Max items to return, 1-1000 (default 100).", "type": "integer", "minimum": 1, "maximum": 1000 } }, { "name": "cursor", "in": "query", "required": false, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "description": "Opaque pagination token from a previous response's `next_cursor`. Omit for the first page.", "type": "string" } } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "data": { "type": "array", "items": { "type": "object", "properties": { "name": { "type": "string", "description": "First and last name joined; empty string if unknown." }, "phoneNumber": { "type": "string", "description": "E.164 phone number; empty string if none." }, "externalId": { "type": "string", "description": "Your unique identifier for the person." }, "email": { "type": "string", "description": "Empty string if none." }, "enteredAt": { "type": "string", "description": "ISO 8601 timestamp of when the person entered the segment." } }, "required": [ "name", "phoneNumber", "externalId", "email", "enteredAt" ], "additionalProperties": false } }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Opaque cursor for the next page; null on the last page." } }, "required": [ "data", "next_cursor" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } } }, "/api/v1/segments/catalog": { "get": { "operationId": "segments_catalog", "summary": "Get the segment filter catalog", "description": "Everything filterable in your organization — person attributes, related data, and computed variables — with the token and operators to use for each. Read this first when building a filter.", "tags": [ "Segments" ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "personAttributes": { "type": "array", "items": { "type": "object", "properties": { "attr": { "type": "string", "description": "The exact token to place in a predicate's `attr` field." }, "type": { "type": "string", "enum": [ "STRING", "NUMBER", "BOOLEAN", "DATE", "JSON", "ARRAY" ] }, "operators": { "type": "array", "items": { "type": "string" }, "description": "Operators valid for this type. Empty for JSON/ARRAY containers — drill into a leaf with `path` first." }, "description": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "required": [ "attr", "type", "operators", "description" ], "additionalProperties": false }, "description": "Person columns and custom person attributes." }, "computedVariables": { "type": "array", "items": { "type": "object", "properties": { "attr": { "type": "string", "description": "The exact token to place in a predicate's `attr` field." }, "type": { "type": "string", "enum": [ "STRING", "NUMBER", "BOOLEAN", "DATE", "JSON", "ARRAY" ] }, "operators": { "type": "array", "items": { "type": "string" }, "description": "Operators valid for this type. Empty for JSON/ARRAY containers — drill into a leaf with `path` first." }, "description": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "label": { "type": "string", "description": "Human-readable label." }, "group": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Grouping label for display." } }, "required": [ "attr", "type", "operators", "description", "label", "group" ], "additionalProperties": false } }, "customObjectTypes": { "type": "array", "items": { "type": "object", "properties": { "name": { "type": "string" }, "displayName": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "attributes": { "type": "array", "items": { "type": "object", "properties": { "attr": { "type": "string", "description": "The exact token to place in a predicate's `attr` field." }, "type": { "type": "string", "enum": [ "STRING", "NUMBER", "BOOLEAN", "DATE", "JSON", "ARRAY" ] }, "operators": { "type": "array", "items": { "type": "string" }, "description": "Operators valid for this type. Empty for JSON/ARRAY containers — drill into a leaf with `path` first." }, "description": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "required": [ "attr", "type", "operators", "description" ], "additionalProperties": false } } }, "required": [ "name", "displayName", "attributes" ], "additionalProperties": false } }, "reachableObjects": { "type": "array", "items": { "type": "object", "properties": { "typeName": { "type": "string" }, "paths": { "type": "array", "items": { "type": "array", "items": { "type": "object", "properties": { "customObjectType": { "type": "string" }, "direction": { "type": "string", "enum": [ "parent_to_child", "child_to_parent" ] }, "relationshipType": { "type": "string" }, "attributeFilters": { "type": "array", "items": {}, "description": "Conditions on this hop, in the same shape as a `has_relationship` `attributeFilters` entry." } }, "required": [ "customObjectType", "attributeFilters" ], "additionalProperties": false } } } }, "required": [ "typeName", "paths" ], "additionalProperties": false, "description": "A related-data type reachable from a person, with every distinct hop-path to it. Use one of the paths as a `has_relationship` predicate `path`." } }, "operatorReference": { "type": "array", "items": { "type": "object", "properties": { "operator": { "type": "string" }, "takesValue": { "type": "boolean", "description": "Whether the operator expects a `value`." }, "valueShape": { "type": "string", "enum": [ "none", "scalar", "list", "date", "dateRange", "relativeWindow", "relativeRange", "dateOffset" ], "description": "The shape the operator's `value` must take." }, "description": { "type": "string" } }, "required": [ "operator", "takesValue", "valueShape", "description" ], "additionalProperties": false } } }, "required": [ "personAttributes", "computedVariables", "customObjectTypes", "reachableObjects", "operatorReference" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } } }, "/api/v1/segments/preview": { "post": { "operationId": "segments_preview", "summary": "Preview a segment filter", "description": "Count how many people currently match a filter, without saving. Use it to check the audience before saving a segment.", "tags": [ "Segments" ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "filterExpression": { "description": "The audience filter: a tree of predicates over person attributes, related data, and events. Discover valid `attr` tokens and operators with segments_catalog (GET /api/v1/segments/catalog).", "type": "object", "properties": { "kind": { "type": "string", "const": "person" }, "op": { "type": "string", "enum": [ "AND", "OR" ] }, "predicates": { "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "has_relationship" }, "connector": { "type": "string", "enum": [ "AND", "OR" ] }, "customObjectType": { "type": "string", "minLength": 1 }, "attributeFilters": { "type": "array", "items": { "type": "object", "properties": { "attr": { "type": "string" }, "path": { "minItems": 1, "maxItems": 5, "type": "array", "items": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*$" } }, "type": { "type": "string", "enum": [ "STRING", "NUMBER", "BOOLEAN", "DATE", "JSON", "ARRAY" ] }, "op": { "type": "string", "enum": [ "eq", "neq", "in", "not_in", "contains", "not_contains", "starts_with", "ends_with", "gt", "gte", "lt", "lte", "on", "before", "after", "between", "in_last_n", "in_next_n", "more_than_n_ago", "more_than_n_from_now", "between_n_and_m_ago", "exactly_n_from_today", "is_null", "is_not_null" ] }, "value": { "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" }, { "type": "array", "items": { "anyOf": [ { "type": "string" }, { "type": "number" } ] } }, { "type": "object", "properties": { "from": { "type": "string" }, "to": { "type": "string" } }, "required": [ "from", "to" ] }, { "type": "object", "properties": { "amount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "amount", "unit" ] }, { "type": "object", "properties": { "minAmount": { "type": "integer", "minimum": 0, "maximum": 9999 }, "maxAmount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "minAmount", "maxAmount", "unit" ] }, { "type": "object", "properties": { "daysOffset": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "rollForward": { "type": "object", "properties": { "fromDow": { "type": "integer", "minimum": 0, "maximum": 6 }, "includeDows": { "minItems": 1, "type": "array", "items": { "type": "integer", "minimum": 0, "maximum": 6 } } }, "required": [ "fromDow", "includeDows" ] } }, "required": [ "daysOffset" ] } ] } }, "required": [ "attr", "type", "op" ] } }, "path": { "minItems": 1, "maxItems": 3, "type": "array", "items": { "type": "object", "properties": { "customObjectType": { "type": "string", "minLength": 1 }, "direction": { "type": "string", "enum": [ "parent_to_child", "child_to_parent" ] }, "relationshipType": { "type": "string", "minLength": 1 }, "attributeFilters": { "type": "array", "items": { "type": "object", "properties": { "attr": { "type": "string" }, "path": { "minItems": 1, "maxItems": 5, "type": "array", "items": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*$" } }, "type": { "type": "string", "enum": [ "STRING", "NUMBER", "BOOLEAN", "DATE", "JSON", "ARRAY" ] }, "op": { "type": "string", "enum": [ "eq", "neq", "in", "not_in", "contains", "not_contains", "starts_with", "ends_with", "gt", "gte", "lt", "lte", "on", "before", "after", "between", "in_last_n", "in_next_n", "more_than_n_ago", "more_than_n_from_now", "between_n_and_m_ago", "exactly_n_from_today", "is_null", "is_not_null" ] }, "value": { "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" }, { "type": "array", "items": { "anyOf": [ { "type": "string" }, { "type": "number" } ] } }, { "type": "object", "properties": { "from": { "type": "string" }, "to": { "type": "string" } }, "required": [ "from", "to" ] }, { "type": "object", "properties": { "amount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "amount", "unit" ] }, { "type": "object", "properties": { "minAmount": { "type": "integer", "minimum": 0, "maximum": 9999 }, "maxAmount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "minAmount", "maxAmount", "unit" ] }, { "type": "object", "properties": { "daysOffset": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "rollForward": { "type": "object", "properties": { "fromDow": { "type": "integer", "minimum": 0, "maximum": 6 }, "includeDows": { "minItems": 1, "type": "array", "items": { "type": "integer", "minimum": 0, "maximum": 6 } } }, "required": [ "fromDow", "includeDows" ] } }, "required": [ "daysOffset" ] } ] } }, "required": [ "attr", "type", "op" ] } } }, "required": [ "customObjectType", "attributeFilters" ] } }, "exists": { "description": "Polarity of the relationship match. Absent or true = HAS the relationship (EXISTS). false = does NOT have it (NOT EXISTS): no related object satisfies this card, which INCLUDES people who have no such object at all. Conditions are allowed and apply inside the negation — \"has no order with status=completed\" matches people whose orders are all non-completed AND people with zero orders. To exclude the latter, add a second positive card for the same relationship.", "type": "boolean" } }, "required": [ "kind", "customObjectType", "attributeFilters" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "person_attribute" }, "connector": { "type": "string", "enum": [ "AND", "OR" ] }, "attr": { "type": "string" }, "path": { "minItems": 1, "maxItems": 5, "type": "array", "items": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*$" } }, "type": { "type": "string", "enum": [ "STRING", "NUMBER", "BOOLEAN", "DATE", "JSON", "ARRAY" ] }, "op": { "type": "string", "enum": [ "eq", "neq", "in", "not_in", "contains", "not_contains", "starts_with", "ends_with", "gt", "gte", "lt", "lte", "on", "before", "after", "between", "in_last_n", "in_next_n", "more_than_n_ago", "more_than_n_from_now", "between_n_and_m_ago", "exactly_n_from_today", "is_null", "is_not_null" ] }, "value": { "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" }, { "type": "array", "items": { "anyOf": [ { "type": "string" }, { "type": "number" } ] } }, { "type": "object", "properties": { "from": { "type": "string" }, "to": { "type": "string" } }, "required": [ "from", "to" ] }, { "type": "object", "properties": { "amount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "amount", "unit" ] }, { "type": "object", "properties": { "minAmount": { "type": "integer", "minimum": 0, "maximum": 9999 }, "maxAmount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "minAmount", "maxAmount", "unit" ] }, { "type": "object", "properties": { "daysOffset": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "rollForward": { "type": "object", "properties": { "fromDow": { "type": "integer", "minimum": 0, "maximum": 6 }, "includeDows": { "minItems": 1, "type": "array", "items": { "type": "integer", "minimum": 0, "maximum": 6 } } }, "required": [ "fromDow", "includeDows" ] } }, "required": [ "daysOffset" ] } ] } }, "required": [ "kind", "attr", "type", "op" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "person_group" }, "connector": { "type": "string", "enum": [ "AND", "OR" ] }, "filters": { "minItems": 1, "type": "array", "items": { "type": "object", "properties": { "attr": { "type": "string" }, "path": { "minItems": 1, "maxItems": 5, "type": "array", "items": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*$" } }, "type": { "type": "string", "enum": [ "STRING", "NUMBER", "BOOLEAN", "DATE", "JSON", "ARRAY" ] }, "op": { "type": "string", "enum": [ "eq", "neq", "in", "not_in", "contains", "not_contains", "starts_with", "ends_with", "gt", "gte", "lt", "lte", "on", "before", "after", "between", "in_last_n", "in_next_n", "more_than_n_ago", "more_than_n_from_now", "between_n_and_m_ago", "exactly_n_from_today", "is_null", "is_not_null" ] }, "value": { "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" }, { "type": "array", "items": { "anyOf": [ { "type": "string" }, { "type": "number" } ] } }, { "type": "object", "properties": { "from": { "type": "string" }, "to": { "type": "string" } }, "required": [ "from", "to" ] }, { "type": "object", "properties": { "amount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "amount", "unit" ] }, { "type": "object", "properties": { "minAmount": { "type": "integer", "minimum": 0, "maximum": 9999 }, "maxAmount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "minAmount", "maxAmount", "unit" ] }, { "type": "object", "properties": { "daysOffset": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "rollForward": { "type": "object", "properties": { "fromDow": { "type": "integer", "minimum": 0, "maximum": 6 }, "includeDows": { "minItems": 1, "type": "array", "items": { "type": "integer", "minimum": 0, "maximum": 6 } } }, "required": [ "fromDow", "includeDows" ] } }, "required": [ "daysOffset" ] } ] } }, "required": [ "attr", "type", "op" ] } } }, "required": [ "kind", "filters" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "event" }, "connector": { "type": "string", "enum": [ "AND", "OR" ] }, "eventName": { "type": "string", "minLength": 1 }, "occurred": { "type": "boolean" }, "propertyFilters": { "minItems": 1, "type": "array", "items": { "type": "object", "properties": { "key": { "type": "string", "minLength": 1 }, "path": { "minItems": 1, "maxItems": 5, "type": "array", "items": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*$" } }, "type": { "type": "string", "enum": [ "STRING", "NUMBER", "BOOLEAN", "DATE", "JSON", "ARRAY" ] }, "op": { "type": "string", "enum": [ "eq", "neq", "in", "not_in", "contains", "not_contains", "starts_with", "ends_with", "gt", "gte", "lt", "lte", "on", "before", "after", "between", "in_last_n", "in_next_n", "more_than_n_ago", "more_than_n_from_now", "between_n_and_m_ago", "exactly_n_from_today", "is_null", "is_not_null" ] }, "value": { "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" }, { "type": "array", "items": { "anyOf": [ { "type": "string" }, { "type": "number" } ] } }, { "type": "object", "properties": { "from": { "type": "string" }, "to": { "type": "string" } }, "required": [ "from", "to" ] }, { "type": "object", "properties": { "amount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "amount", "unit" ] }, { "type": "object", "properties": { "minAmount": { "type": "integer", "minimum": 0, "maximum": 9999 }, "maxAmount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "minAmount", "maxAmount", "unit" ] }, { "type": "object", "properties": { "daysOffset": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "rollForward": { "type": "object", "properties": { "fromDow": { "type": "integer", "minimum": 0, "maximum": 6 }, "includeDows": { "minItems": 1, "type": "array", "items": { "type": "integer", "minimum": 0, "maximum": 6 } } }, "required": [ "fromDow", "includeDows" ] } }, "required": [ "daysOffset" ] } ] } }, "required": [ "key", "type", "op" ] } }, "window": { "type": "object", "properties": { "op": { "type": "string", "enum": [ "in_last_n", "more_than_n_ago", "between_n_and_m_ago", "between", "before", "after", "on" ] }, "value": { "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" }, { "type": "array", "items": { "anyOf": [ { "type": "string" }, { "type": "number" } ] } }, { "type": "object", "properties": { "from": { "type": "string" }, "to": { "type": "string" } }, "required": [ "from", "to" ] }, { "type": "object", "properties": { "amount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "amount", "unit" ] }, { "type": "object", "properties": { "minAmount": { "type": "integer", "minimum": 0, "maximum": 9999 }, "maxAmount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "minAmount", "maxAmount", "unit" ] }, { "type": "object", "properties": { "daysOffset": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "rollForward": { "type": "object", "properties": { "fromDow": { "type": "integer", "minimum": 0, "maximum": 6 }, "includeDows": { "minItems": 1, "type": "array", "items": { "type": "integer", "minimum": 0, "maximum": 6 } } }, "required": [ "fromDow", "includeDows" ] } }, "required": [ "daysOffset" ] } ] } }, "required": [ "op" ] } }, "required": [ "kind", "eventName", "occurred" ] } ] } } }, "required": [ "kind", "op", "predicates" ] } }, "required": [ "filterExpression" ] } } } }, "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "count": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "People currently matching the filter (capped when huge)." } }, "required": [ "count" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } } }, "/api/v1/segments/validate": { "post": { "operationId": "segments_validate", "summary": "Validate a segment filter", "description": "Dry-run a filter expression against your live catalog — nothing is saved. Returns whether it's valid, or the field to fix.", "tags": [ "Segments" ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "filterExpression": { "description": "The audience filter: a tree of predicates over person attributes, related data, and events. Discover valid `attr` tokens and operators with segments_catalog (GET /api/v1/segments/catalog).", "type": "object", "properties": { "kind": { "type": "string", "const": "person" }, "op": { "type": "string", "enum": [ "AND", "OR" ] }, "predicates": { "type": "array", "items": { "oneOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "has_relationship" }, "connector": { "type": "string", "enum": [ "AND", "OR" ] }, "customObjectType": { "type": "string", "minLength": 1 }, "attributeFilters": { "type": "array", "items": { "type": "object", "properties": { "attr": { "type": "string" }, "path": { "minItems": 1, "maxItems": 5, "type": "array", "items": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*$" } }, "type": { "type": "string", "enum": [ "STRING", "NUMBER", "BOOLEAN", "DATE", "JSON", "ARRAY" ] }, "op": { "type": "string", "enum": [ "eq", "neq", "in", "not_in", "contains", "not_contains", "starts_with", "ends_with", "gt", "gte", "lt", "lte", "on", "before", "after", "between", "in_last_n", "in_next_n", "more_than_n_ago", "more_than_n_from_now", "between_n_and_m_ago", "exactly_n_from_today", "is_null", "is_not_null" ] }, "value": { "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" }, { "type": "array", "items": { "anyOf": [ { "type": "string" }, { "type": "number" } ] } }, { "type": "object", "properties": { "from": { "type": "string" }, "to": { "type": "string" } }, "required": [ "from", "to" ] }, { "type": "object", "properties": { "amount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "amount", "unit" ] }, { "type": "object", "properties": { "minAmount": { "type": "integer", "minimum": 0, "maximum": 9999 }, "maxAmount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "minAmount", "maxAmount", "unit" ] }, { "type": "object", "properties": { "daysOffset": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "rollForward": { "type": "object", "properties": { "fromDow": { "type": "integer", "minimum": 0, "maximum": 6 }, "includeDows": { "minItems": 1, "type": "array", "items": { "type": "integer", "minimum": 0, "maximum": 6 } } }, "required": [ "fromDow", "includeDows" ] } }, "required": [ "daysOffset" ] } ] } }, "required": [ "attr", "type", "op" ] } }, "path": { "minItems": 1, "maxItems": 3, "type": "array", "items": { "type": "object", "properties": { "customObjectType": { "type": "string", "minLength": 1 }, "direction": { "type": "string", "enum": [ "parent_to_child", "child_to_parent" ] }, "relationshipType": { "type": "string", "minLength": 1 }, "attributeFilters": { "type": "array", "items": { "type": "object", "properties": { "attr": { "type": "string" }, "path": { "minItems": 1, "maxItems": 5, "type": "array", "items": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*$" } }, "type": { "type": "string", "enum": [ "STRING", "NUMBER", "BOOLEAN", "DATE", "JSON", "ARRAY" ] }, "op": { "type": "string", "enum": [ "eq", "neq", "in", "not_in", "contains", "not_contains", "starts_with", "ends_with", "gt", "gte", "lt", "lte", "on", "before", "after", "between", "in_last_n", "in_next_n", "more_than_n_ago", "more_than_n_from_now", "between_n_and_m_ago", "exactly_n_from_today", "is_null", "is_not_null" ] }, "value": { "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" }, { "type": "array", "items": { "anyOf": [ { "type": "string" }, { "type": "number" } ] } }, { "type": "object", "properties": { "from": { "type": "string" }, "to": { "type": "string" } }, "required": [ "from", "to" ] }, { "type": "object", "properties": { "amount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "amount", "unit" ] }, { "type": "object", "properties": { "minAmount": { "type": "integer", "minimum": 0, "maximum": 9999 }, "maxAmount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "minAmount", "maxAmount", "unit" ] }, { "type": "object", "properties": { "daysOffset": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "rollForward": { "type": "object", "properties": { "fromDow": { "type": "integer", "minimum": 0, "maximum": 6 }, "includeDows": { "minItems": 1, "type": "array", "items": { "type": "integer", "minimum": 0, "maximum": 6 } } }, "required": [ "fromDow", "includeDows" ] } }, "required": [ "daysOffset" ] } ] } }, "required": [ "attr", "type", "op" ] } } }, "required": [ "customObjectType", "attributeFilters" ] } }, "exists": { "description": "Polarity of the relationship match. Absent or true = HAS the relationship (EXISTS). false = does NOT have it (NOT EXISTS): no related object satisfies this card, which INCLUDES people who have no such object at all. Conditions are allowed and apply inside the negation — \"has no order with status=completed\" matches people whose orders are all non-completed AND people with zero orders. To exclude the latter, add a second positive card for the same relationship.", "type": "boolean" } }, "required": [ "kind", "customObjectType", "attributeFilters" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "person_attribute" }, "connector": { "type": "string", "enum": [ "AND", "OR" ] }, "attr": { "type": "string" }, "path": { "minItems": 1, "maxItems": 5, "type": "array", "items": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*$" } }, "type": { "type": "string", "enum": [ "STRING", "NUMBER", "BOOLEAN", "DATE", "JSON", "ARRAY" ] }, "op": { "type": "string", "enum": [ "eq", "neq", "in", "not_in", "contains", "not_contains", "starts_with", "ends_with", "gt", "gte", "lt", "lte", "on", "before", "after", "between", "in_last_n", "in_next_n", "more_than_n_ago", "more_than_n_from_now", "between_n_and_m_ago", "exactly_n_from_today", "is_null", "is_not_null" ] }, "value": { "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" }, { "type": "array", "items": { "anyOf": [ { "type": "string" }, { "type": "number" } ] } }, { "type": "object", "properties": { "from": { "type": "string" }, "to": { "type": "string" } }, "required": [ "from", "to" ] }, { "type": "object", "properties": { "amount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "amount", "unit" ] }, { "type": "object", "properties": { "minAmount": { "type": "integer", "minimum": 0, "maximum": 9999 }, "maxAmount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "minAmount", "maxAmount", "unit" ] }, { "type": "object", "properties": { "daysOffset": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "rollForward": { "type": "object", "properties": { "fromDow": { "type": "integer", "minimum": 0, "maximum": 6 }, "includeDows": { "minItems": 1, "type": "array", "items": { "type": "integer", "minimum": 0, "maximum": 6 } } }, "required": [ "fromDow", "includeDows" ] } }, "required": [ "daysOffset" ] } ] } }, "required": [ "kind", "attr", "type", "op" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "person_group" }, "connector": { "type": "string", "enum": [ "AND", "OR" ] }, "filters": { "minItems": 1, "type": "array", "items": { "type": "object", "properties": { "attr": { "type": "string" }, "path": { "minItems": 1, "maxItems": 5, "type": "array", "items": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*$" } }, "type": { "type": "string", "enum": [ "STRING", "NUMBER", "BOOLEAN", "DATE", "JSON", "ARRAY" ] }, "op": { "type": "string", "enum": [ "eq", "neq", "in", "not_in", "contains", "not_contains", "starts_with", "ends_with", "gt", "gte", "lt", "lte", "on", "before", "after", "between", "in_last_n", "in_next_n", "more_than_n_ago", "more_than_n_from_now", "between_n_and_m_ago", "exactly_n_from_today", "is_null", "is_not_null" ] }, "value": { "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" }, { "type": "array", "items": { "anyOf": [ { "type": "string" }, { "type": "number" } ] } }, { "type": "object", "properties": { "from": { "type": "string" }, "to": { "type": "string" } }, "required": [ "from", "to" ] }, { "type": "object", "properties": { "amount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "amount", "unit" ] }, { "type": "object", "properties": { "minAmount": { "type": "integer", "minimum": 0, "maximum": 9999 }, "maxAmount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "minAmount", "maxAmount", "unit" ] }, { "type": "object", "properties": { "daysOffset": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "rollForward": { "type": "object", "properties": { "fromDow": { "type": "integer", "minimum": 0, "maximum": 6 }, "includeDows": { "minItems": 1, "type": "array", "items": { "type": "integer", "minimum": 0, "maximum": 6 } } }, "required": [ "fromDow", "includeDows" ] } }, "required": [ "daysOffset" ] } ] } }, "required": [ "attr", "type", "op" ] } } }, "required": [ "kind", "filters" ] }, { "type": "object", "properties": { "kind": { "type": "string", "const": "event" }, "connector": { "type": "string", "enum": [ "AND", "OR" ] }, "eventName": { "type": "string", "minLength": 1 }, "occurred": { "type": "boolean" }, "propertyFilters": { "minItems": 1, "type": "array", "items": { "type": "object", "properties": { "key": { "type": "string", "minLength": 1 }, "path": { "minItems": 1, "maxItems": 5, "type": "array", "items": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*$" } }, "type": { "type": "string", "enum": [ "STRING", "NUMBER", "BOOLEAN", "DATE", "JSON", "ARRAY" ] }, "op": { "type": "string", "enum": [ "eq", "neq", "in", "not_in", "contains", "not_contains", "starts_with", "ends_with", "gt", "gte", "lt", "lte", "on", "before", "after", "between", "in_last_n", "in_next_n", "more_than_n_ago", "more_than_n_from_now", "between_n_and_m_ago", "exactly_n_from_today", "is_null", "is_not_null" ] }, "value": { "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" }, { "type": "array", "items": { "anyOf": [ { "type": "string" }, { "type": "number" } ] } }, { "type": "object", "properties": { "from": { "type": "string" }, "to": { "type": "string" } }, "required": [ "from", "to" ] }, { "type": "object", "properties": { "amount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "amount", "unit" ] }, { "type": "object", "properties": { "minAmount": { "type": "integer", "minimum": 0, "maximum": 9999 }, "maxAmount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "minAmount", "maxAmount", "unit" ] }, { "type": "object", "properties": { "daysOffset": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "rollForward": { "type": "object", "properties": { "fromDow": { "type": "integer", "minimum": 0, "maximum": 6 }, "includeDows": { "minItems": 1, "type": "array", "items": { "type": "integer", "minimum": 0, "maximum": 6 } } }, "required": [ "fromDow", "includeDows" ] } }, "required": [ "daysOffset" ] } ] } }, "required": [ "key", "type", "op" ] } }, "window": { "type": "object", "properties": { "op": { "type": "string", "enum": [ "in_last_n", "more_than_n_ago", "between_n_and_m_ago", "between", "before", "after", "on" ] }, "value": { "anyOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" }, { "type": "array", "items": { "anyOf": [ { "type": "string" }, { "type": "number" } ] } }, { "type": "object", "properties": { "from": { "type": "string" }, "to": { "type": "string" } }, "required": [ "from", "to" ] }, { "type": "object", "properties": { "amount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "amount", "unit" ] }, { "type": "object", "properties": { "minAmount": { "type": "integer", "minimum": 0, "maximum": 9999 }, "maxAmount": { "type": "integer", "minimum": 1, "maximum": 9999 }, "unit": { "type": "string", "enum": [ "days", "weeks", "months" ] } }, "required": [ "minAmount", "maxAmount", "unit" ] }, { "type": "object", "properties": { "daysOffset": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "rollForward": { "type": "object", "properties": { "fromDow": { "type": "integer", "minimum": 0, "maximum": 6 }, "includeDows": { "minItems": 1, "type": "array", "items": { "type": "integer", "minimum": 0, "maximum": 6 } } }, "required": [ "fromDow", "includeDows" ] } }, "required": [ "daysOffset" ] } ] } }, "required": [ "op" ] } }, "required": [ "kind", "eventName", "occurred" ] } ] } } }, "required": [ "kind", "op", "predicates" ] } }, "required": [ "filterExpression" ] } } } }, "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "valid": { "type": "boolean", "description": "Always true when the filter is valid." } }, "required": [ "valid" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } } }, "/api/v1/templates": { "get": { "operationId": "templates_list", "summary": "List templates", "description": "List your WhatsApp templates and each one's approval status. Reviews are async (~24–48h) — re-read to see updates.", "tags": [ "WhatsApp templates" ], "parameters": [ { "name": "status", "in": "query", "required": false, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "enum": [ "DRAFT", "PENDING", "APPROVED", "REJECTED" ] } }, { "name": "category", "in": "query", "required": false, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "enum": [ "UTILITY", "MARKETING", "AUTHENTICATION" ] } }, { "name": "contentType", "in": "query", "required": false, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "enum": [ "TEXT", "MEDIA", "QUICK_REPLY", "CALL_TO_ACTION", "CARD" ] } } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "data": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Template id." }, "name": { "type": "string", "description": "Template name (unique per WhatsApp number)." }, "language": { "type": "string", "description": "WhatsApp language code the template was created for, e.g. `es_MX`." }, "category": { "type": "string", "enum": [ "UTILITY", "MARKETING", "AUTHENTICATION" ] }, "contentType": { "type": "string", "enum": [ "TEXT", "MEDIA", "QUICK_REPLY", "CALL_TO_ACTION", "CARD" ] }, "content": { "description": "The message content (shape per `contentType`)." }, "variables": { "anyOf": [ { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "type": "string" } }, { "type": "null" } ], "description": "Example values for `{{1}}`-style placeholders." }, "phoneNumbers": { "type": "array", "items": { "type": "string" }, "description": "WhatsApp numbers this template can be sent from." }, "status": { "type": "string", "enum": [ "DRAFT", "PENDING", "APPROVED", "REJECTED" ], "description": "DRAFT (not yet submitted), PENDING (in WhatsApp review, typically 24-48h), APPROVED, or REJECTED (see rejectionReason)." }, "rejectionReason": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "createdAt": { "type": "string", "description": "ISO 8601 timestamp." }, "updatedAt": { "type": "string", "description": "ISO 8601 timestamp." } }, "required": [ "id", "name", "language", "category", "contentType", "content", "variables", "phoneNumbers", "status", "rejectionReason", "createdAt", "updatedAt" ], "additionalProperties": false } }, "next_cursor": { "type": "null" } }, "required": [ "data", "next_cursor" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } }, "post": { "operationId": "templates_create", "summary": "Create template", "description": "Create a WhatsApp template and submit it for WhatsApp approval, which is asynchronous (~24–48h). Example (TEXT): `{ \"name\": \"order_shipped\", \"language\": \"es\", \"category\": \"UTILITY\", \"contentType\": \"TEXT\", \"content\": { \"body\": \"Hola {{1}}, tu pedido ya salió.\" }, \"variables\": { \"1\": \"Ana\" } }`. Example with buttons (CALL_TO_ACTION): `{ \"name\": \"order_shipped_cta\", \"language\": \"es\", \"category\": \"UTILITY\", \"contentType\": \"CALL_TO_ACTION\", \"content\": { \"body\": \"Hola {{1}}, tu pedido ya salió.\", \"actions\": [{ \"type\": \"URL\", \"title\": \"Ver pedido\", \"url\": \"https://example.com/orders/{{2}}\" }] }, \"variables\": { \"1\": \"Ana\", \"2\": \"12345\" } }`. Example with reply buttons (QUICK_REPLY): `{ \"name\": \"order_feedback\", \"language\": \"es\", \"category\": \"UTILITY\", \"contentType\": \"QUICK_REPLY\", \"content\": { \"body\": \"¿Te gustó tu compra?\", \"actions\": [{ \"title\": \"Sí\", \"id\": \"yes\" }, { \"title\": \"No\", \"id\": \"no\" }] } }`. Example with a header and image (CARD): `{ \"name\": \"order_shipped_card\", \"language\": \"es\", \"category\": \"UTILITY\", \"contentType\": \"CARD\", \"content\": { \"headerType\": \"media\", \"mediaUrl\": \"https://example.com/banner.jpg\", \"body\": \"Hola {{1}}, tu pedido ya salió.\", \"footer\": \"Gracias por tu compra\", \"actions\": [{ \"type\": \"URL\", \"title\": \"Ver pedido\", \"url\": \"https://example.com/orders/{{2}}\" }] }, \"variables\": { \"1\": \"Ana\", \"2\": \"12345\" } }`. Example that is only an image (MEDIA): the image URL goes in `content.media` (an array), NOT in a variable — `{ \"name\": \"promo_verano\", \"language\": \"es\", \"category\": \"MARKETING\", \"contentType\": \"MEDIA\", \"content\": { \"media\": [\"https://example.com/promo.png\"], \"body\": \"¡Hola {{1}}! Aprovecha nuestra promo de verano.\" }, \"variables\": { \"1\": \"Ana\" } }`.", "tags": [ "WhatsApp templates" ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "name": { "type": "string", "minLength": 1, "maxLength": 255, "description": "Template name, unique per WhatsApp number." }, "language": { "type": "string", "minLength": 2, "maxLength": 10, "description": "WhatsApp language code, e.g. `es`, `en`. A regional variant like `es_MX` or `en_US` is normalized to its base code." }, "category": { "type": "string", "enum": [ "UTILITY", "MARKETING", "AUTHENTICATION" ] }, "contentType": { "type": "string", "enum": [ "TEXT", "MEDIA", "QUICK_REPLY", "CALL_TO_ACTION", "CARD" ] }, "content": { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": {}, "description": "Message content. Shape depends on `contentType`: TEXT `{ body }`; MEDIA `{ body?, media: [url] }`; QUICK_REPLY `{ body, actions: [{ title, id }] }`; CALL_TO_ACTION `{ body, actions: [{ type: URL|PHONE_NUMBER, title, url|phone }] }`; CARD `{ headerType, headerText|mediaUrl, body, footer?, actions? }`. Use `{{1}}`, `{{2}}`… for variables. Example (TEXT): `{ \"body\": \"Hola {{1}}, tu pedido está en camino\" }`. Example (CALL_TO_ACTION, adds a button): `{ \"body\": \"Hola {{1}}, tu pedido está en camino\", \"actions\": [{ \"type\": \"URL\", \"title\": \"Ver pedido\", \"url\": \"https://example.com/orders/{{2}}\" }] }`. Example (QUICK_REPLY, adds reply buttons): `{ \"body\": \"¿Te gustó tu compra?\", \"actions\": [{ \"title\": \"Sí\", \"id\": \"yes\" }, { \"title\": \"No\", \"id\": \"no\" }] }`. Example (CARD, header + optional footer/button): `{ \"headerType\": \"text\", \"headerText\": \"Pedido en camino\", \"body\": \"Hola {{1}}, tu pedido ya salió.\", \"footer\": \"Gracias por tu compra\", \"actions\": [{ \"type\": \"URL\", \"title\": \"Ver pedido\", \"url\": \"https://example.com/orders/{{2}}\" }] }`." }, "variables": { "description": "Example values for placeholders, e.g. `{ \"1\": \"Ana\" }` for `{{1}}`. Required for every placeholder used.", "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "type": "string" } }, "phoneNumbers": { "description": "WhatsApp numbers (E.164) to create the template for. Omit to use the first active number connected to your organization.", "minItems": 1, "type": "array", "items": { "type": "string", "minLength": 1 } } }, "required": [ "name", "language", "category", "contentType", "content" ] } } } }, "responses": { "201": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "data": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Template id." }, "name": { "type": "string", "description": "Template name (unique per WhatsApp number)." }, "language": { "type": "string", "description": "WhatsApp language code the template was created for, e.g. `es_MX`." }, "category": { "type": "string", "enum": [ "UTILITY", "MARKETING", "AUTHENTICATION" ] }, "contentType": { "type": "string", "enum": [ "TEXT", "MEDIA", "QUICK_REPLY", "CALL_TO_ACTION", "CARD" ] }, "content": { "description": "The message content (shape per `contentType`)." }, "variables": { "anyOf": [ { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "type": "string" } }, { "type": "null" } ], "description": "Example values for `{{1}}`-style placeholders." }, "phoneNumbers": { "type": "array", "items": { "type": "string" }, "description": "WhatsApp numbers this template can be sent from." }, "status": { "type": "string", "enum": [ "DRAFT", "PENDING", "APPROVED", "REJECTED" ], "description": "DRAFT (not yet submitted), PENDING (in WhatsApp review, typically 24-48h), APPROVED, or REJECTED (see rejectionReason)." }, "rejectionReason": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "createdAt": { "type": "string", "description": "ISO 8601 timestamp." }, "updatedAt": { "type": "string", "description": "ISO 8601 timestamp." } }, "required": [ "id", "name", "language", "category", "contentType", "content", "variables", "phoneNumbers", "status", "rejectionReason", "createdAt", "updatedAt" ], "additionalProperties": false }, "description": "The created template(s) — one per WhatsApp account backing the chosen numbers." } }, "required": [ "data" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } } }, "/api/v1/templates/{id}": { "get": { "operationId": "templates_get", "summary": "Get template", "description": "Get one WhatsApp template by id, including its approval status and any rejection reason.", "tags": [ "WhatsApp templates" ], "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "minLength": 1, "description": "Template id." } } ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "id": { "type": "string", "description": "Template id." }, "name": { "type": "string", "description": "Template name (unique per WhatsApp number)." }, "language": { "type": "string", "description": "WhatsApp language code the template was created for, e.g. `es_MX`." }, "category": { "type": "string", "enum": [ "UTILITY", "MARKETING", "AUTHENTICATION" ] }, "contentType": { "type": "string", "enum": [ "TEXT", "MEDIA", "QUICK_REPLY", "CALL_TO_ACTION", "CARD" ] }, "content": { "description": "The message content (shape per `contentType`)." }, "variables": { "anyOf": [ { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "type": "string" } }, { "type": "null" } ], "description": "Example values for `{{1}}`-style placeholders." }, "phoneNumbers": { "type": "array", "items": { "type": "string" }, "description": "WhatsApp numbers this template can be sent from." }, "status": { "type": "string", "enum": [ "DRAFT", "PENDING", "APPROVED", "REJECTED" ], "description": "DRAFT (not yet submitted), PENDING (in WhatsApp review, typically 24-48h), APPROVED, or REJECTED (see rejectionReason)." }, "rejectionReason": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "createdAt": { "type": "string", "description": "ISO 8601 timestamp." }, "updatedAt": { "type": "string", "description": "ISO 8601 timestamp." } }, "required": [ "id", "name", "language", "category", "contentType", "content", "variables", "phoneNumbers", "status", "rejectionReason", "createdAt", "updatedAt" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } } }, "/api/v1/whatsapp-numbers": { "get": { "operationId": "whatsapp_numbers_list", "summary": "List numbers", "description": "List the WhatsApp numbers connected to your organization. Use them when creating templates.", "tags": [ "WhatsApp templates" ], "responses": { "200": { "description": "Success", "content": { "application/json": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "data": { "type": "array", "items": { "type": "object", "properties": { "phoneNumber": { "type": "string", "description": "E.164 format, e.g. +5215512345678." }, "displayName": { "type": "string" }, "status": { "type": "string", "description": "ONLINE means ready to send and receive messages." } }, "required": [ "phoneNumber", "displayName", "status" ], "additionalProperties": false } }, "next_cursor": { "type": "null" } }, "required": [ "data", "next_cursor" ], "additionalProperties": false } } } }, "400": { "description": "Validation failed or the request cannot proceed.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Missing, malformed, or revoked API key.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "404": { "description": "The resource does not exist in this organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "409": { "description": "Conflicts with the current state (duplicates, wrong lifecycle state).", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "422": { "description": "The request is well-formed but semantically invalid.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "429": { "description": "Rate limit exceeded — retry after `Retry-After`.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "503": { "description": "Transient error — retry with a narrower request.", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code (snake_case)." }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } } } } } }, "components": { "securitySchemes": { "bearerAuth": { "type": "http", "scheme": "bearer", "description": "Organization API key, sent as `Authorization: Bearer boom_org_...`." } }, "schemas": { "Error": { "type": "object", "required": [ "error" ], "properties": { "error": { "type": "string" }, "suggestions": { "type": "array", "items": { "type": "string" }, "description": "Fuzzy-matched alternatives (on unknown-type 404s)." } } } }, "parameters": { "Limit": { "name": "limit", "in": "query", "required": false, "schema": { "type": "integer", "default": 100, "minimum": 1, "maximum": 1000 }, "description": "Page size. Defaults to 100, max 1000." }, "Cursor": { "name": "cursor", "in": "query", "required": false, "schema": { "type": "string" }, "description": "Opaque pagination cursor from a prior response's `next_cursor`. Omit for the first page." } }, "responses": { "BadRequest": { "description": "Invalid Content-Type, malformed JSON, or schema validation failure", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "example": { "error": "Invalid JSON body" } } } }, "Unauthorized": { "description": "Missing or invalid API key", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "example": { "error": "Missing or malformed Authorization header" } } } }, "RateLimited": { "description": "Rate limit exceeded (1000 requests/minute per key). See Retry-After and X-RateLimit-* headers.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "example": { "error": "Rate limit exceeded" } } } }, "ServerError": { "description": "Unexpected server error (never leaks internals)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "example": { "error": "Internal server error" } } } } } } }