From 171ff230f5d27ec7cc4700c039318ffb265984bf Mon Sep 17 00:00:00 2001 From: Rajeh Taher Date: Tue, 8 Sep 2026 04:13:12 +0300 Subject: [PATCH 1/8] feat(sdk): add typed BanSafe resources --- CHANGELOG.md | 6 + README.md | 10 +- contracts/drafts/bansafe/README.md | 10 + contracts/drafts/bansafe/coverage.json | 199 + .../drafts/bansafe/openapi.messaging.json | 31823 ++++++++++++++++ .../drafts/bansafe/openapi.platform.json | 27456 +++++++++++++ contracts/drafts/bansafe/source.json | 17 + packages/typescript/README.md | 42 + packages/typescript/src/index.ts | 88 + packages/typescript/src/platform/bansafe.ts | 186 + packages/typescript/src/platform/client.ts | 3 + packages/typescript/src/platform/projects.ts | 128 + packages/typescript/src/platform/sessions.ts | 26 + packages/typescript/src/platform/types.ts | 544 + .../typescript/test/bansafe-contract.test.ts | 101 + packages/typescript/test/bansafe.test.ts | 214 + 16 files changed, 60851 insertions(+), 2 deletions(-) create mode 100644 contracts/drafts/bansafe/README.md create mode 100644 contracts/drafts/bansafe/coverage.json create mode 100644 contracts/drafts/bansafe/openapi.messaging.json create mode 100644 contracts/drafts/bansafe/openapi.platform.json create mode 100644 contracts/drafts/bansafe/source.json create mode 100644 packages/typescript/src/platform/bansafe.ts create mode 100644 packages/typescript/test/bansafe-contract.test.ts create mode 100644 packages/typescript/test/bansafe.test.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index fd92dfd..3576547 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ ## Unreleased +- Added typed BanSafe Health, telemetry, collection, findings, enforcement, + incidents, claims, and Health action reads to `PlatformClient.banSafe`. + Project and session resources now cover Safe Mode, warm-up, Ban Insurance + evidence, and Health policy settings. Dashboard-only finding acknowledgement + and appeals remain outside the server-key client. + - Keep call controls and media available after a failed reject or hangup, with a localized retry message in React and custom elements. diff --git a/README.md b/README.md index 14c5347..71a75e7 100644 --- a/README.md +++ b/README.md @@ -158,9 +158,15 @@ The handwritten Platform resources in this milestone are: - `projectTokens`: list token metadata for an explicit project - `billing`: retrieve balance and currency, inspect usage meters, list transactions and tier pricing, and update low-balance reminders -- `projects`: list, create, request production enrollment, approve, and cancel +- `banSafe`: inspect Health, telemetry collection, signal definitions, findings, + restrictions, incidents, claims, and Health action history; report and retract + customer incidents +- `projects`: list, create, request production enrollment, approve, and cancel; + retrieve and update Safe Mode, warm-up, Ban Insurance evidence, and Health + policy settings - `sessions`: list, stop or delete one session, stop or delete a bounded batch, - set tier override, and create a testing session + set tier override, create a testing session, and retrieve or update the + session Safe Mode override - `widgetSettings`: retrieve organization or project Connect widget settings and update the exact saved configuration fields - `campaigns`: list, create, retrieve, update, delete, lifecycle actions, diff --git a/contracts/drafts/bansafe/README.md b/contracts/drafts/bansafe/README.md new file mode 100644 index 0000000..6101625 --- /dev/null +++ b/contracts/drafts/bansafe/README.md @@ -0,0 +1,10 @@ +# BanSafe draft contracts + +These files are byte-identical copies of the BanSafe implementation worktree +specs at the hashes recorded in `source.json`. The source tree contains +uncommitted API work on top of `sourceBaseCommit`, so these snapshots do not +claim a merged Polymorfa source revision or published SDK parity. + +The canonical files under `contracts/` and their coverage ledger stay pinned to +the last merged source revision. Replace that pin only after the API changes +land at one exact commit and the coverage ledger has been reconciled. diff --git a/contracts/drafts/bansafe/coverage.json b/contracts/drafts/bansafe/coverage.json new file mode 100644 index 0000000..c807812 --- /dev/null +++ b/contracts/drafts/bansafe/coverage.json @@ -0,0 +1,199 @@ +{ + "schemaVersion": 1, + "platformSha256": "9b37273ee85a1ce07d456060d46ce18a70832895f03e20ad83319d053232e0c5", + "scope": "OpenAPI operations tagged bansafe", + "covered": 25, + "excluded": 2, + "missing": 0, + "operations": [ + { + "operationId": "listBanSafeHealth", + "method": "GET", + "path": "/v1/bansafe/health", + "status": "covered", + "sdkPath": "PlatformClient.banSafe.listHealth" + }, + { + "operationId": "getBanSafeHealth", + "method": "GET", + "path": "/v1/bansafe/health/{session}", + "status": "covered", + "sdkPath": "PlatformClient.banSafe.getHealth" + }, + { + "operationId": "listBanSafeHealthHistory", + "method": "GET", + "path": "/v1/bansafe/health/{session}/history", + "status": "covered", + "sdkPath": "PlatformClient.banSafe.listHealthHistory" + }, + { + "operationId": "listBanSafeSignals", + "method": "GET", + "path": "/v1/bansafe/signals", + "status": "covered", + "sdkPath": "PlatformClient.banSafe.listSignals" + }, + { + "operationId": "getBanSafeTelemetry", + "method": "GET", + "path": "/v1/bansafe/telemetry/{session}", + "status": "covered", + "sdkPath": "PlatformClient.banSafe.getTelemetry" + }, + { + "operationId": "listBanSafeTelemetryHistory", + "method": "GET", + "path": "/v1/bansafe/telemetry/{session}/history", + "status": "covered", + "sdkPath": "PlatformClient.banSafe.listTelemetryHistory" + }, + { + "operationId": "listBanSafeCollection", + "method": "GET", + "path": "/v1/bansafe/collection", + "status": "covered", + "sdkPath": "PlatformClient.banSafe.listCollection" + }, + { + "operationId": "listBanSafeHealthActions", + "method": "GET", + "path": "/v1/bansafe/health-actions", + "status": "covered", + "sdkPath": "PlatformClient.banSafe.listHealthActions" + }, + { + "operationId": "listBanSafeFindings", + "method": "GET", + "path": "/v1/bansafe/findings", + "status": "covered", + "sdkPath": "PlatformClient.banSafe.listFindings" + }, + { + "operationId": "acknowledgeBanSafeFinding", + "method": "POST", + "path": "/v1/bansafe/findings/{findingId}/acknowledge", + "status": "excluded", + "reason": "Requires signed-in dashboard identity; server API keys and project tokens are refused." + }, + { + "operationId": "listBanSafeEnforcement", + "method": "GET", + "path": "/v1/bansafe/enforcement", + "status": "covered", + "sdkPath": "PlatformClient.banSafe.listEnforcement" + }, + { + "operationId": "appealBanSafeEnforcement", + "method": "POST", + "path": "/v1/bansafe/enforcement/{session}/appeal", + "status": "excluded", + "reason": "Requires signed-in dashboard identity; server API keys and project tokens are refused." + }, + { + "operationId": "listBanSafeIncidents", + "method": "GET", + "path": "/v1/bansafe/incidents", + "status": "covered", + "sdkPath": "PlatformClient.banSafe.listIncidents" + }, + { + "operationId": "createBanSafeIncident", + "method": "POST", + "path": "/v1/bansafe/incidents", + "status": "covered", + "sdkPath": "PlatformClient.banSafe.createIncident" + }, + { + "operationId": "retractBanSafeIncident", + "method": "POST", + "path": "/v1/bansafe/incidents/{incidentId}/retract", + "status": "covered", + "sdkPath": "PlatformClient.banSafe.retractIncident" + }, + { + "operationId": "listBanSafeClaims", + "method": "GET", + "path": "/v1/bansafe/claims", + "status": "covered", + "sdkPath": "PlatformClient.banSafe.listClaims" + }, + { + "operationId": "getBanSafeClaim", + "method": "GET", + "path": "/v1/bansafe/claims/{claimId}", + "status": "covered", + "sdkPath": "PlatformClient.banSafe.getClaim" + }, + { + "operationId": "getProjectSafeModeCeiling", + "method": "GET", + "path": "/v1/projects/{projectId}/safe-mode", + "status": "covered", + "sdkPath": "PlatformClient.projects.getSafeMode" + }, + { + "operationId": "updateProjectSafeModeCeiling", + "method": "PUT", + "path": "/v1/projects/{projectId}/safe-mode", + "status": "covered", + "sdkPath": "PlatformClient.projects.updateSafeMode" + }, + { + "operationId": "getNumberSafeMode", + "method": "GET", + "path": "/v1/sessions/{sessionId}/safe-mode", + "status": "covered", + "sdkPath": "PlatformClient.sessions.getSafeMode" + }, + { + "operationId": "updateNumberSafeMode", + "method": "PUT", + "path": "/v1/sessions/{sessionId}/safe-mode", + "status": "covered", + "sdkPath": "PlatformClient.sessions.updateSafeMode" + }, + { + "operationId": "getProjectWarmupPlanSettings", + "method": "GET", + "path": "/v1/projects/{projectId}/warmup-plan", + "status": "covered", + "sdkPath": "PlatformClient.projects.getWarmupPlan" + }, + { + "operationId": "updateProjectWarmupPlanSettings", + "method": "PUT", + "path": "/v1/projects/{projectId}/warmup-plan", + "status": "covered", + "sdkPath": "PlatformClient.projects.updateWarmupPlan" + }, + { + "operationId": "getProjectHealthPolicySettings", + "method": "GET", + "path": "/v1/projects/{projectId}/health-policy", + "status": "covered", + "sdkPath": "PlatformClient.projects.getHealthPolicy" + }, + { + "operationId": "updateProjectHealthPolicySettings", + "method": "PUT", + "path": "/v1/projects/{projectId}/health-policy", + "status": "covered", + "sdkPath": "PlatformClient.projects.updateHealthPolicy" + }, + { + "operationId": "getInsuranceEvidenceSettings", + "method": "GET", + "path": "/v1/projects/{projectId}/insurance-evidence", + "status": "covered", + "sdkPath": "PlatformClient.projects.getInsuranceEvidence" + }, + { + "operationId": "updateInsuranceEvidenceSettings", + "method": "PUT", + "path": "/v1/projects/{projectId}/insurance-evidence", + "status": "covered", + "sdkPath": "PlatformClient.projects.updateInsuranceEvidence" + } + ] +} diff --git a/contracts/drafts/bansafe/openapi.messaging.json b/contracts/drafts/bansafe/openapi.messaging.json new file mode 100644 index 0000000..4310d96 --- /dev/null +++ b/contracts/drafts/bansafe/openapi.messaging.json @@ -0,0 +1,31823 @@ +{ + "openapi": "3.0.3", + "info": { + "title": "Polymorfa WhatsApp API", + "version": "1.0.0", + "description": "Public Polymorfa REST API for sessions, messaging, media, webhooks, campaigns, templates, client tokens, widgets, and bridge routing.", + "contact": { + "name": "Polymorfa API", + "url": "https://docs.polymorfa.com" + } + }, + "servers": [ + { + "url": "https://api.polymorfa.com" + } + ], + "security": [ + { + "BearerAuth": [] + } + ], + "components": { + "schemas": { + "JIDRef": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "phoneNumber": { + "type": "string" + }, + "username": { + "type": "string" + }, + "lid": { + "type": "string", + "deprecated": true + }, + "mode": { + "type": "string", + "enum": [ + "pn", + "lid" + ], + "deprecated": true + } + }, + "required": [ + "id" + ] + }, + "PollOption": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "hash": { + "type": "string" + } + }, + "required": [ + "name", + "hash" + ] + }, + "MessagePayload": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "from": { + "$ref": "#/components/schemas/JIDRef" + }, + "sender": { + "$ref": "#/components/schemas/JIDRef" + }, + "fromMe": { + "type": "boolean" + }, + "timestamp": { + "type": "number" + }, + "pushName": { + "type": "string" + }, + "isGroup": { + "type": "boolean" + }, + "type": { + "type": "string", + "enum": [ + "text", + "image", + "video", + "audio", + "document", + "location", + "contact", + "phone_number_shared", + "poll", + "sticker", + "reaction", + "revoke", + "edited", + "unknown" + ] + }, + "text": { + "type": "string" + }, + "caption": { + "type": "string" + }, + "mimeType": { + "type": "string" + }, + "ptt": { + "type": "boolean" + }, + "filename": { + "type": "string" + }, + "latitude": { + "type": "number" + }, + "longitude": { + "type": "number" + }, + "displayName": { + "type": "string" + }, + "title": { + "type": "string" + }, + "reaction": { + "type": "string" + }, + "reactionTo": { + "type": "string" + }, + "revokedId": { + "type": "string" + }, + "nativeFlowResponse": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1, + "maxLength": 64 + }, + "paramsJson": { + "type": "string", + "minLength": 1, + "maxLength": 262144 + }, + "version": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "name", + "paramsJson" + ] + }, + "media": { + "type": "string" + }, + "mediaUrl": { + "type": "string" + }, + "edited": { + "type": "boolean" + }, + "pollOptions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PollOption" + } + }, + "unavailable": { + "type": "boolean" + }, + "unavailableReason": { + "type": "string" + } + }, + "required": [ + "id", + "from", + "sender", + "fromMe", + "timestamp", + "pushName", + "isGroup", + "type" + ] + }, + "CloudMessagePayload": { + "type": "object", + "properties": { + "messageId": { + "type": "string" + }, + "from": { + "type": "string", + "description": "Meta wa_id. This is not a LID-backed user ID." + }, + "timestamp": { + "type": "string" + }, + "type": { + "type": "string" + }, + "senderName": { + "type": "string" + }, + "nativeFlowResponse": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1, + "maxLength": 64 + }, + "paramsJson": { + "type": "string", + "minLength": 1, + "maxLength": 262144 + }, + "version": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "name", + "paramsJson" + ] + }, + "interactive": { + "type": "object", + "additionalProperties": { + "nullable": true + } + } + }, + "required": [ + "messageId", + "from", + "timestamp", + "type" + ] + }, + "MessageReceivedPayload": { + "oneOf": [ + { + "$ref": "#/components/schemas/MessagePayload" + }, + { + "$ref": "#/components/schemas/CloudMessagePayload" + } + ] + }, + "MessageReceivedEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/MessageReceivedPayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ] + }, + "MessageSentPayload": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "from": { + "$ref": "#/components/schemas/JIDRef" + }, + "type": { + "type": "string" + }, + "timestamp": { + "type": "number" + }, + "sender": { + "$ref": "#/components/schemas/JIDRef" + } + }, + "required": [ + "id", + "from", + "type", + "timestamp", + "sender" + ] + }, + "MessageSentEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/MessageSentPayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ] + }, + "MessageAckPayload": { + "type": "object", + "properties": { + "messageIds": { + "type": "array", + "items": { + "type": "string" + } + }, + "from": { + "$ref": "#/components/schemas/JIDRef" + }, + "sender": { + "$ref": "#/components/schemas/JIDRef" + }, + "type": { + "type": "string", + "description": "Ack type: error, delivered, read, played" + }, + "timestamp": { + "type": "number" + } + }, + "required": [ + "messageIds", + "from", + "sender", + "type", + "timestamp" + ] + }, + "MessageAckEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/MessageAckPayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ] + }, + "MessageRevokedEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/MessagePayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ] + }, + "MessageReactionEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/MessagePayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ] + }, + "MessageEditedEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/MessagePayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ] + }, + "MessageUpdateEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/MessagePayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ] + }, + "MessageDeletePayload": { + "type": "object", + "properties": { + "from": { + "$ref": "#/components/schemas/JIDRef" + }, + "sender": { + "$ref": "#/components/schemas/JIDRef" + }, + "messageId": { + "type": "string" + }, + "fromMe": { + "type": "boolean" + } + }, + "required": [ + "from", + "sender", + "messageId", + "fromMe" + ] + }, + "MessageDeleteEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/MessageDeletePayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ] + }, + "PollVotePayload": { + "type": "object", + "properties": { + "pollMessageId": { + "type": "string" + }, + "voter": { + "$ref": "#/components/schemas/JIDRef" + }, + "selectedHashes": { + "type": "array", + "items": { + "type": "string" + } + }, + "timestamp": { + "type": "number" + } + }, + "required": [ + "pollMessageId", + "voter", + "selectedHashes", + "timestamp" + ] + }, + "MessageVoteEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/PollVotePayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ] + }, + "SessionStatusPayload": { + "type": "object", + "properties": { + "status": { + "type": "string", + "description": "Session status: CONNECTING, CONNECTED, DISCONNECTED", + "example": "DISCONNECTED" + }, + "statusReason": { + "type": "string", + "description": "Reason for the status: SCAN_QR, AUTO_RECONNECT, FAILED, MANUAL_STOP, QR_TIMEOUT, LOGGED_OUT, TEMPORARY_BAN, STREAM_ERROR", + "example": "TEMPORARY_BAN" + }, + "banCode": { + "type": "integer", + "minimum": 0, + "description": "WhatsApp temporary-ban code (present only when statusReason is TEMPORARY_BAN).", + "example": 101 + }, + "banReason": { + "type": "string", + "description": "Human-readable label for the ban code (present only when statusReason is TEMPORARY_BAN).", + "example": "Suspected spam activity" + }, + "banExpiresAt": { + "type": "integer", + "description": "Unix timestamp in seconds when the temporary ban lifts, when WhatsApp provides a duration.", + "format": "int64", + "example": 1789000000 + }, + "detail": { + "type": "string", + "description": "Extra context for FAILED and STREAM_ERROR statuses (for example the connect-failure reason)." + } + }, + "required": [ + "status" + ] + }, + "SessionStatusEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/SessionStatusPayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ] + }, + "SessionQRPayload": { + "type": "object", + "properties": { + "code": { + "type": "string" + } + }, + "required": [ + "code" + ] + }, + "SessionQREvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/SessionQRPayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ] + }, + "SessionConnectedPayload": { + "type": "object", + "properties": { + "phoneNumber": { + "type": "string" + }, + "lid": { + "type": "string" + }, + "pushName": { + "type": "string" + }, + "platform": { + "type": "string" + }, + "businessName": { + "type": "string" + } + }, + "required": [ + "phoneNumber", + "pushName", + "platform" + ] + }, + "SessionConnectedEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/SessionConnectedPayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ] + }, + "SessionLoggedOutPayload": { + "type": "object", + "properties": { + "reason": { + "type": "string" + } + }, + "required": [ + "reason" + ] + }, + "SessionLoggedOutEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/SessionLoggedOutPayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ] + }, + "SessionPhoneOfflinePayload": { + "type": "object", + "properties": { + "daysSinceLastSeen": { + "type": "number", + "description": "Whole days since the phone was last seen online.", + "example": 11 + }, + "daysRemaining": { + "type": "number", + "description": "Days remaining before WhatsApp disconnects the session (clamped to 0). WhatsApp typically severs the companion link after ~14 days of phone inactivity.", + "example": 3 + }, + "lastSeen": { + "type": "string", + "description": "ISO 8601 timestamp of the last time the phone was seen online.", + "example": "2026-04-05T14:30:00Z" + }, + "action": { + "type": "string", + "description": "Human-readable action string to surface to the end user (e.g. ask them to open WhatsApp on their phone).", + "example": "Open WhatsApp on your phone to keep the session alive" + } + }, + "required": [ + "daysSinceLastSeen", + "daysRemaining", + "lastSeen", + "action" + ] + }, + "SessionPhoneOfflineEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/SessionPhoneOfflinePayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ] + }, + "GroupUpdatePayload": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "newSubject": { + "type": "string" + }, + "newDescription": { + "type": "string" + }, + "action": { + "type": "string" + } + }, + "required": [ + "id" + ] + }, + "GroupUpdateEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/GroupUpdatePayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ] + }, + "GroupParticipantPayload": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "joined": { + "type": "array", + "items": { + "$ref": "#/components/schemas/JIDRef" + } + }, + "left": { + "type": "array", + "items": { + "$ref": "#/components/schemas/JIDRef" + } + }, + "promoted": { + "type": "array", + "items": { + "$ref": "#/components/schemas/JIDRef" + } + }, + "demoted": { + "type": "array", + "items": { + "$ref": "#/components/schemas/JIDRef" + } + } + }, + "required": [ + "id" + ] + }, + "GroupParticipantEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/GroupParticipantPayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ] + }, + "PresenceUpdatePayload": { + "type": "object", + "properties": { + "observedAt": { + "type": "integer" + }, + "from": { + "$ref": "#/components/schemas/JIDRef" + }, + "sender": { + "$ref": "#/components/schemas/JIDRef" + }, + "state": { + "type": "string" + }, + "media": { + "type": "string" + }, + "unavailable": { + "type": "boolean" + }, + "lastSeen": { + "type": "number" + } + }, + "required": [ + "observedAt" + ] + }, + "PresenceUpdateEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/PresenceUpdatePayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ] + }, + "ContactUpdatePayload": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "lid": { + "type": "string", + "deprecated": true + }, + "phoneNumber": { + "type": "string" + }, + "username": { + "type": "string" + }, + "fullName": { + "type": "string" + }, + "firstName": { + "type": "string" + }, + "pushName": { + "type": "string" + }, + "oldPushName": { + "type": "string" + }, + "businessName": { + "type": "string" + }, + "oldBusinessName": { + "type": "string" + }, + "pictureId": { + "type": "string" + }, + "pictureRemoved": { + "type": "boolean" + } + }, + "required": [ + "id" + ] + }, + "ContactUpdateEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/ContactUpdatePayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ] + }, + "ChatArchivePayload": { + "type": "object", + "properties": { + "from": { + "$ref": "#/components/schemas/JIDRef" + }, + "archive": { + "type": "boolean" + }, + "pinned": { + "type": "boolean" + } + }, + "required": [ + "from" + ] + }, + "ChatArchiveEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/ChatArchivePayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ] + }, + "ChatMutePayload": { + "type": "object", + "properties": { + "from": { + "$ref": "#/components/schemas/JIDRef" + }, + "muted": { + "type": "boolean" + }, + "muteEndTimestamp": { + "type": "number" + } + }, + "required": [ + "from", + "muted" + ] + }, + "ChatMuteEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/ChatMutePayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ] + }, + "ChatReadPayload": { + "type": "object", + "properties": { + "from": { + "$ref": "#/components/schemas/JIDRef" + }, + "read": { + "type": "boolean" + } + }, + "required": [ + "from", + "read" + ] + }, + "ChatReadEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/ChatReadPayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ] + }, + "ChatClearPayload": { + "type": "object", + "properties": { + "from": { + "$ref": "#/components/schemas/JIDRef" + } + }, + "required": [ + "from" + ] + }, + "ChatClearEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/ChatClearPayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ] + }, + "ChatDeletePayload": { + "type": "object", + "properties": { + "from": { + "$ref": "#/components/schemas/JIDRef" + } + }, + "required": [ + "from" + ] + }, + "ChatDeleteEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/ChatDeletePayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ] + }, + "CallReceivedPayload": { + "type": "object", + "properties": { + "from": { + "$ref": "#/components/schemas/JIDRef" + }, + "callId": { + "type": "string" + } + }, + "required": [ + "from", + "callId" + ] + }, + "CallReceivedEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/CallReceivedPayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ] + }, + "CallMissedPayload": { + "type": "object", + "properties": { + "from": { + "$ref": "#/components/schemas/JIDRef" + }, + "callId": { + "type": "string" + }, + "reason": { + "type": "string" + } + }, + "required": [ + "from", + "callId", + "reason" + ] + }, + "CallMissedEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/CallMissedPayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ] + }, + "CallAcceptedPayload": { + "type": "object", + "properties": { + "from": { + "$ref": "#/components/schemas/JIDRef" + }, + "callId": { + "type": "string" + } + }, + "required": [ + "from", + "callId" + ] + }, + "CallAcceptedEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/CallAcceptedPayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ] + }, + "CallRejectedPayload": { + "type": "object", + "properties": { + "from": { + "$ref": "#/components/schemas/JIDRef" + }, + "callId": { + "type": "string" + } + }, + "required": [ + "from", + "callId" + ] + }, + "CallRejectedEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/CallRejectedPayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ] + }, + "NewsletterUpdatePayload": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "action": { + "type": "string" + }, + "muted": { + "type": "boolean" + } + }, + "required": [ + "id", + "action" + ] + }, + "NewsletterUpdateEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/NewsletterUpdatePayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ] + }, + "BlocklistChange": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "lid": { + "type": "string", + "deprecated": true + }, + "phoneNumber": { + "type": "string" + }, + "username": { + "type": "string" + }, + "action": { + "type": "string" + } + }, + "required": [ + "id", + "action" + ] + }, + "BlocklistUpdatePayload": { + "type": "object", + "properties": { + "action": { + "type": "string" + }, + "changes": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BlocklistChange" + } + } + }, + "required": [ + "action", + "changes" + ] + }, + "BlocklistUpdateEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/BlocklistUpdatePayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ] + }, + "LabelsUpdatePayload": { + "type": "object", + "properties": { + "action": { + "type": "string", + "description": "Action: label_edit, label_association_chat, star", + "example": "label_edit" + }, + "labelId": { + "type": "string", + "description": "Label ID affected by the action" + }, + "from": { + "allOf": [ + { + "$ref": "#/components/schemas/JIDRef" + }, + { + "description": "Chat the label action applies to" + } + ] + }, + "label": { + "type": "string", + "description": "Legacy field: the label's display name for label_edit, and the label ID for association actions. Prefer labelId and name." + }, + "name": { + "type": "string", + "description": "Label display name (present for label_edit)" + }, + "color": { + "type": "integer", + "description": "Label color index (present for label_edit)", + "format": "int32" + }, + "orderIndex": { + "type": "integer", + "description": "Label ordering index when supplied by app state", + "format": "int32" + }, + "deleted": { + "type": "boolean", + "description": "Whether the label definition was deleted" + }, + "labeled": { + "type": "boolean", + "description": "Whether the chat or message association is active" + }, + "observedAt": { + "type": "integer", + "description": "Unix timestamp in seconds when the app-state mutation was observed", + "format": "int64" + }, + "messageId": { + "type": "string", + "description": "Message ID (present for star actions)" + }, + "starred": { + "type": "boolean", + "description": "Whether the message is starred (present for star actions)" + } + }, + "required": [ + "action" + ] + }, + "LabelsUpdateEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/LabelsUpdatePayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ] + }, + "BusinessQuickReplyUpdatePayload": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "shortcut": { + "type": "string" + }, + "message": { + "type": "string" + }, + "keywords": { + "type": "array", + "items": { + "type": "string" + } + }, + "count": { + "type": "integer", + "minimum": 0 + }, + "deleted": { + "type": "boolean" + }, + "associatedLabelIds": { + "type": "array", + "items": { + "type": "string" + } + }, + "observedAt": { + "type": "integer" + }, + "fromFullSync": { + "type": "boolean" + } + }, + "required": [ + "id", + "shortcut", + "message", + "keywords", + "count", + "deleted", + "associatedLabelIds", + "observedAt", + "fromFullSync" + ] + }, + "BusinessQuickReplyUpdateEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/BusinessQuickReplyUpdatePayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ] + }, + "HistorySyncPayload": { + "type": "object", + "properties": { + "messageId": { + "type": "string" + }, + "originalMessageId": { + "type": "string" + }, + "mode": { + "type": "string", + "enum": [ + "deliver" + ] + }, + "syncType": { + "type": "string" + }, + "chunkOrder": { + "type": "integer", + "minimum": 0 + }, + "progress": { + "type": "integer", + "minimum": 0, + "maximum": 100 + }, + "fileLength": { + "type": "integer", + "minimum": 0 + }, + "conversationCount": { + "type": "integer", + "minimum": 0 + }, + "messageCount": { + "type": "integer", + "minimum": 0 + }, + "pushNameCount": { + "type": "integer", + "minimum": 0 + }, + "statusMessageCount": { + "type": "integer", + "minimum": 0 + }, + "data": { + "type": "string", + "description": "Base64-encoded gzip-compressed HistorySync protobuf" + } + }, + "required": [ + "messageId", + "mode", + "syncType", + "fileLength", + "conversationCount", + "messageCount", + "pushNameCount", + "statusMessageCount", + "data" + ] + }, + "HistorySyncEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/HistorySyncPayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ] + }, + "CommandResultPayload": { + "type": "object", + "properties": { + "requestId": { + "type": "string" + }, + "command": { + "type": "string" + }, + "success": { + "type": "boolean" + }, + "data": { + "type": "object", + "additionalProperties": { + "nullable": true + } + }, + "error": { + "type": "string" + } + }, + "required": [ + "requestId", + "command", + "success" + ] + }, + "CommandResultEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/CommandResultPayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ] + }, + "CustomerEnabledPayload": { + "type": "object", + "properties": { + "eventId": { + "type": "string", + "format": "uuid" + }, + "occurredAt": { + "type": "string", + "format": "date-time" + }, + "organizationId": { + "type": "string", + "format": "uuid" + }, + "projectId": { + "type": "string", + "format": "uuid" + }, + "customerId": { + "type": "string", + "format": "uuid" + }, + "actorKind": { + "type": "string", + "enum": [ + "better_auth", + "org_key", + "project_token", + "cli_grant", + "system" + ] + }, + "migratedNumberCount": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "eventId", + "occurredAt", + "organizationId", + "projectId", + "customerId", + "actorKind", + "migratedNumberCount" + ], + "additionalProperties": false + }, + "CustomerEnabledEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/CustomerEnabledPayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ], + "additionalProperties": false + }, + "CustomerCreatedPayload": { + "type": "object", + "properties": { + "eventId": { + "type": "string", + "format": "uuid" + }, + "occurredAt": { + "type": "string", + "format": "date-time" + }, + "organizationId": { + "type": "string", + "format": "uuid" + }, + "projectId": { + "type": "string", + "format": "uuid" + }, + "customerId": { + "type": "string", + "format": "uuid" + }, + "actorKind": { + "type": "string", + "enum": [ + "better_auth", + "org_key", + "project_token", + "cli_grant", + "system" + ] + } + }, + "required": [ + "eventId", + "occurredAt", + "organizationId", + "projectId", + "customerId", + "actorKind" + ], + "additionalProperties": false + }, + "CustomerCreatedEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/CustomerCreatedPayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ], + "additionalProperties": false + }, + "CustomerUpdatedPayload": { + "type": "object", + "properties": { + "eventId": { + "type": "string", + "format": "uuid" + }, + "occurredAt": { + "type": "string", + "format": "date-time" + }, + "organizationId": { + "type": "string", + "format": "uuid" + }, + "projectId": { + "type": "string", + "format": "uuid" + }, + "customerId": { + "type": "string", + "format": "uuid" + }, + "actorKind": { + "type": "string", + "enum": [ + "better_auth", + "org_key", + "project_token", + "cli_grant", + "system" + ] + }, + "fields": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "name", + "phone", + "externalCustomerId" + ] + }, + "minItems": 1, + "maxItems": 3 + } + }, + "required": [ + "eventId", + "occurredAt", + "organizationId", + "projectId", + "customerId", + "actorKind", + "fields" + ], + "additionalProperties": false + }, + "CustomerUpdatedEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/CustomerUpdatedPayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ], + "additionalProperties": false + }, + "CustomerArchivingPayload": { + "type": "object", + "properties": { + "eventId": { + "type": "string", + "format": "uuid" + }, + "occurredAt": { + "type": "string", + "format": "date-time" + }, + "organizationId": { + "type": "string", + "format": "uuid" + }, + "projectId": { + "type": "string", + "format": "uuid" + }, + "customerId": { + "type": "string", + "format": "uuid" + }, + "actorKind": { + "type": "string", + "enum": [ + "better_auth", + "org_key", + "project_token", + "cli_grant", + "system" + ] + }, + "blockingNumberCount": { + "type": "integer", + "minimum": 0 + }, + "revokedPairingLinkCount": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "eventId", + "occurredAt", + "organizationId", + "projectId", + "customerId", + "actorKind", + "blockingNumberCount", + "revokedPairingLinkCount" + ], + "additionalProperties": false + }, + "CustomerArchivingEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/CustomerArchivingPayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ], + "additionalProperties": false + }, + "CustomerArchivedPayload": { + "type": "object", + "properties": { + "eventId": { + "type": "string", + "format": "uuid" + }, + "occurredAt": { + "type": "string", + "format": "date-time" + }, + "organizationId": { + "type": "string", + "format": "uuid" + }, + "projectId": { + "type": "string", + "format": "uuid" + }, + "customerId": { + "type": "string", + "format": "uuid" + }, + "actorKind": { + "type": "string", + "enum": [ + "better_auth", + "org_key", + "project_token", + "cli_grant", + "system" + ] + } + }, + "required": [ + "eventId", + "occurredAt", + "organizationId", + "projectId", + "customerId", + "actorKind" + ], + "additionalProperties": false + }, + "CustomerArchivedEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/CustomerArchivedPayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ], + "additionalProperties": false + }, + "CustomerRestoredPayload": { + "type": "object", + "properties": { + "eventId": { + "type": "string", + "format": "uuid" + }, + "occurredAt": { + "type": "string", + "format": "date-time" + }, + "organizationId": { + "type": "string", + "format": "uuid" + }, + "projectId": { + "type": "string", + "format": "uuid" + }, + "customerId": { + "type": "string", + "format": "uuid" + }, + "actorKind": { + "type": "string", + "enum": [ + "better_auth", + "org_key", + "project_token", + "cli_grant", + "system" + ] + } + }, + "required": [ + "eventId", + "occurredAt", + "organizationId", + "projectId", + "customerId", + "actorKind" + ], + "additionalProperties": false + }, + "CustomerRestoredEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/CustomerRestoredPayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ], + "additionalProperties": false + }, + "CustomerPairingLinkCreatedPayload": { + "type": "object", + "properties": { + "eventId": { + "type": "string", + "format": "uuid" + }, + "occurredAt": { + "type": "string", + "format": "date-time" + }, + "organizationId": { + "type": "string", + "format": "uuid" + }, + "projectId": { + "type": "string", + "format": "uuid" + }, + "customerId": { + "type": "string", + "format": "uuid" + }, + "actorKind": { + "type": "string", + "enum": [ + "better_auth", + "org_key", + "project_token", + "cli_grant", + "system" + ] + }, + "pairingLinkId": { + "type": "string", + "format": "uuid" + } + }, + "required": [ + "eventId", + "occurredAt", + "organizationId", + "projectId", + "customerId", + "actorKind", + "pairingLinkId" + ], + "additionalProperties": false + }, + "CustomerPairingLinkCreatedEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/CustomerPairingLinkCreatedPayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ], + "additionalProperties": false + }, + "CustomerPairingLinkOpenedPayload": { + "type": "object", + "properties": { + "eventId": { + "type": "string", + "format": "uuid" + }, + "occurredAt": { + "type": "string", + "format": "date-time" + }, + "organizationId": { + "type": "string", + "format": "uuid" + }, + "projectId": { + "type": "string", + "format": "uuid" + }, + "customerId": { + "type": "string", + "format": "uuid" + }, + "actorKind": { + "type": "string", + "enum": [ + "better_auth", + "org_key", + "project_token", + "cli_grant", + "system" + ] + }, + "pairingLinkId": { + "type": "string", + "format": "uuid" + } + }, + "required": [ + "eventId", + "occurredAt", + "organizationId", + "projectId", + "customerId", + "actorKind", + "pairingLinkId" + ], + "additionalProperties": false + }, + "CustomerPairingLinkOpenedEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/CustomerPairingLinkOpenedPayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ], + "additionalProperties": false + }, + "CustomerPairingLinkConnectedPayload": { + "type": "object", + "properties": { + "eventId": { + "type": "string", + "format": "uuid" + }, + "occurredAt": { + "type": "string", + "format": "date-time" + }, + "organizationId": { + "type": "string", + "format": "uuid" + }, + "projectId": { + "type": "string", + "format": "uuid" + }, + "customerId": { + "type": "string", + "format": "uuid" + }, + "actorKind": { + "type": "string", + "enum": [ + "better_auth", + "org_key", + "project_token", + "cli_grant", + "system" + ] + }, + "pairingLinkId": { + "type": "string", + "format": "uuid" + }, + "sessionId": { + "type": "string", + "format": "uuid" + } + }, + "required": [ + "eventId", + "occurredAt", + "organizationId", + "projectId", + "customerId", + "actorKind", + "pairingLinkId", + "sessionId" + ], + "additionalProperties": false + }, + "CustomerPairingLinkConnectedEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/CustomerPairingLinkConnectedPayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ], + "additionalProperties": false + }, + "CustomerPairingLinkFailedPayload": { + "type": "object", + "properties": { + "eventId": { + "type": "string", + "format": "uuid" + }, + "occurredAt": { + "type": "string", + "format": "date-time" + }, + "organizationId": { + "type": "string", + "format": "uuid" + }, + "projectId": { + "type": "string", + "format": "uuid" + }, + "customerId": { + "type": "string", + "format": "uuid" + }, + "actorKind": { + "type": "string", + "enum": [ + "better_auth", + "org_key", + "project_token", + "cli_grant", + "system" + ] + }, + "pairingLinkId": { + "type": "string", + "format": "uuid" + }, + "errorCode": { + "type": "string", + "pattern": "^[a-z0-9_]{1,64}$" + } + }, + "required": [ + "eventId", + "occurredAt", + "organizationId", + "projectId", + "customerId", + "actorKind", + "pairingLinkId", + "errorCode" + ], + "additionalProperties": false + }, + "CustomerPairingLinkFailedEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/CustomerPairingLinkFailedPayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ], + "additionalProperties": false + }, + "CustomerPairingLinkExpiredPayload": { + "type": "object", + "properties": { + "eventId": { + "type": "string", + "format": "uuid" + }, + "occurredAt": { + "type": "string", + "format": "date-time" + }, + "organizationId": { + "type": "string", + "format": "uuid" + }, + "projectId": { + "type": "string", + "format": "uuid" + }, + "customerId": { + "type": "string", + "format": "uuid" + }, + "actorKind": { + "type": "string", + "enum": [ + "better_auth", + "org_key", + "project_token", + "cli_grant", + "system" + ] + }, + "pairingLinkId": { + "type": "string", + "format": "uuid" + } + }, + "required": [ + "eventId", + "occurredAt", + "organizationId", + "projectId", + "customerId", + "actorKind", + "pairingLinkId" + ], + "additionalProperties": false + }, + "CustomerPairingLinkExpiredEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/CustomerPairingLinkExpiredPayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ], + "additionalProperties": false + }, + "CustomerPairingLinkRevokedPayload": { + "type": "object", + "properties": { + "eventId": { + "type": "string", + "format": "uuid" + }, + "occurredAt": { + "type": "string", + "format": "date-time" + }, + "organizationId": { + "type": "string", + "format": "uuid" + }, + "projectId": { + "type": "string", + "format": "uuid" + }, + "customerId": { + "type": "string", + "format": "uuid" + }, + "actorKind": { + "type": "string", + "enum": [ + "better_auth", + "org_key", + "project_token", + "cli_grant", + "system" + ] + }, + "pairingLinkId": { + "type": "string", + "format": "uuid" + }, + "reason": { + "type": "string", + "enum": [ + "customer_archived", + "phone_mismatch_limit", + "exchange_failure_limit", + "terminal_failure" + ] + } + }, + "required": [ + "eventId", + "occurredAt", + "organizationId", + "projectId", + "customerId", + "actorKind", + "pairingLinkId" + ], + "additionalProperties": false + }, + "CustomerPairingLinkRevokedEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/CustomerPairingLinkRevokedPayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ], + "additionalProperties": false + }, + "CustomerNumberAttachedPayload": { + "type": "object", + "properties": { + "eventId": { + "type": "string", + "format": "uuid" + }, + "occurredAt": { + "type": "string", + "format": "date-time" + }, + "organizationId": { + "type": "string", + "format": "uuid" + }, + "projectId": { + "type": "string", + "format": "uuid" + }, + "customerId": { + "type": "string", + "format": "uuid" + }, + "actorKind": { + "type": "string", + "enum": [ + "better_auth", + "org_key", + "project_token", + "cli_grant", + "system" + ] + }, + "sessionId": { + "type": "string", + "format": "uuid" + }, + "pairingLinkId": { + "type": "string", + "format": "uuid" + } + }, + "required": [ + "eventId", + "occurredAt", + "organizationId", + "projectId", + "customerId", + "actorKind", + "sessionId" + ], + "additionalProperties": false + }, + "CustomerNumberAttachedEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/CustomerNumberAttachedPayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ], + "additionalProperties": false + }, + "CustomerNumberTransferredPayload": { + "type": "object", + "properties": { + "eventId": { + "type": "string", + "format": "uuid" + }, + "occurredAt": { + "type": "string", + "format": "date-time" + }, + "organizationId": { + "type": "string", + "format": "uuid" + }, + "projectId": { + "type": "string", + "format": "uuid" + }, + "customerId": { + "type": "string", + "format": "uuid" + }, + "actorKind": { + "type": "string", + "enum": [ + "better_auth", + "org_key", + "project_token", + "cli_grant", + "system" + ] + }, + "sessionId": { + "type": "string", + "format": "uuid" + }, + "sourceCustomerId": { + "type": "string", + "format": "uuid" + } + }, + "required": [ + "eventId", + "occurredAt", + "organizationId", + "projectId", + "customerId", + "actorKind", + "sessionId", + "sourceCustomerId" + ], + "additionalProperties": false + }, + "CustomerNumberTransferredEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/CustomerNumberTransferredPayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ], + "additionalProperties": false + }, + "CustomerNumberDisconnectedPayload": { + "type": "object", + "properties": { + "eventId": { + "type": "string", + "format": "uuid" + }, + "occurredAt": { + "type": "string", + "format": "date-time" + }, + "organizationId": { + "type": "string", + "format": "uuid" + }, + "projectId": { + "type": "string", + "format": "uuid" + }, + "customerId": { + "type": "string", + "format": "uuid" + }, + "actorKind": { + "type": "string", + "enum": [ + "better_auth", + "org_key", + "project_token", + "cli_grant", + "system" + ] + }, + "sessionId": { + "type": "string", + "format": "uuid" + }, + "reason": { + "type": "string", + "pattern": "^[a-z0-9_]{1,64}$" + } + }, + "required": [ + "eventId", + "occurredAt", + "organizationId", + "projectId", + "customerId", + "actorKind", + "sessionId", + "reason" + ], + "additionalProperties": false + }, + "CustomerNumberDisconnectedEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/CustomerNumberDisconnectedPayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ], + "additionalProperties": false + }, + "BanSafeEnforcementPayload": { + "type": "object", + "properties": { + "phoneNumber": { + "type": "string", + "pattern": "^\\+[1-9]\\d{1,14}$", + "description": "The customer's own number in E.164 format.", + "example": "+15551234567" + }, + "kind": { + "type": "string", + "enum": [ + "cap_warning", + "cap_reached", + "timelock", + "temporary_ban", + "permanent_ban", + "connect_blocked", + "customer_report" + ], + "description": "Enforcement outcome, or customer_report for a customer-reported ban." + }, + "source": { + "type": "string", + "enum": [ + "runtime", + "customer" + ], + "description": "Whether Polymorfa observed the enforcement or the customer reported it." + }, + "code": { + "type": "integer", + "minimum": 0, + "description": "WhatsApp status code (for example 402, 403, 406, 475) when observed.", + "example": 402 + }, + "subCode": { + "type": "integer", + "minimum": 0, + "description": "WhatsApp sub-code (101-106 for temporary bans) when provided.", + "example": 101 + }, + "reason": { + "type": "string", + "maxLength": 200, + "description": "Sanitised reason from the WhatsApp code table.", + "example": "Suspected spam activity" + }, + "enforcementType": { + "type": "string", + "maxLength": 64, + "description": "WhatsApp enforcement type (for example BIZ_QUALITY) when provided." + }, + "startedAt": { + "type": "string", + "format": "date-time", + "description": "ISO 8601 timestamp when the enforcement started.", + "example": "2026-09-06T14:03:12.000Z" + }, + "endsAt": { + "type": "string", + "format": "date-time", + "description": "ISO 8601 timestamp when the enforcement lifts, when WhatsApp provides a duration.", + "example": "2026-09-07T14:03:12.000Z" + } + }, + "required": [ + "phoneNumber", + "kind", + "source", + "startedAt" + ], + "additionalProperties": false + }, + "BanSafeEnforcementEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/BanSafeEnforcementPayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ], + "additionalProperties": false + }, + "BanSafeRequiredFinding": { + "type": "object", + "properties": { + "findingKey": { + "type": "string", + "pattern": "^[a-z0-9_]{1,64}$", + "description": "Stable finding identifier.", + "example": "typing_absent" + }, + "title": { + "type": "string", + "minLength": 1, + "maxLength": 160, + "description": "Customer-facing finding title.", + "example": "Messages sent without showing that you are typing" + }, + "severity": { + "type": "string", + "enum": [ + "info", + "warning", + "critical" + ] + } + }, + "required": [ + "findingKey", + "title", + "severity" + ], + "additionalProperties": false + }, + "BanSafeActionPayload": { + "type": "object", + "properties": { + "phoneNumber": { + "type": "string", + "pattern": "^\\+[1-9]\\d{1,14}$", + "description": "The customer's own number in E.164 format.", + "example": "+15551234567" + }, + "action": { + "type": "string", + "enum": [ + "applied", + "changed", + "lifted", + "daily_allowance_reached" + ], + "description": "Whether the restriction was newly applied, moved, or removed. `daily_allowance_reached` reports that the number spent its warm-up allowance for the day; nothing on the ladder moved and sending resumes at the next reset." + }, + "scope": { + "type": "string", + "enum": [ + "number", + "organization" + ], + "description": "Whether this covers one number or every number in the workspace." + }, + "rung": { + "type": "string", + "enum": [ + "none", + "notify", + "throttle", + "block_cold", + "suspend" + ], + "description": "Restriction now in force." + }, + "previousRung": { + "type": "string", + "nullable": true, + "enum": [ + "none", + "notify", + "throttle", + "block_cold", + "suspend" + ], + "description": "Restriction previously in force, or null when none was." + }, + "reason": { + "type": "string", + "enum": [ + "health", + "finding", + "org_pattern", + "repeat", + "restriction", + "operator", + "health_model_cutover", + "warmup" + ], + "description": "Why the restriction changed." + }, + "health": { + "type": "integer", + "nullable": true, + "minimum": 0, + "maximum": 100, + "description": "Measured health from 0 (worst) to 100 (best), or null when not measured.", + "example": 62 + }, + "healthBand": { + "type": "string", + "enum": [ + "good", + "fair", + "poor", + "failing", + "unknown" + ], + "description": "Health band matching health." + }, + "requires": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BanSafeRequiredFinding" + }, + "maxItems": 25, + "description": "Findings that must resolve before this restriction lifts." + }, + "throughputPerMinute": { + "type": "integer", + "nullable": true, + "minimum": 0, + "maximum": 10000, + "description": "Messages per minute allowed while paced, or null when not paced.", + "example": 6 + }, + "eligibleLiftAt": { + "type": "string", + "nullable": true, + "format": "date-time", + "description": "Earliest instant the restriction can step down, ISO 8601.", + "example": "2026-09-08T14:00:00.000Z" + }, + "liftRequires": { + "type": "string", + "minLength": 1, + "maxLength": 240, + "description": "One sentence describing what lifts the restriction.", + "example": "Resolve the two open checks and keep them clean for six evaluations." + }, + "appealUrl": { + "type": "string", + "maxLength": 500, + "format": "uri", + "description": "Where to appeal this action.", + "example": "https://app.polymorfa.com/safety/appeal" + }, + "startedAt": { + "type": "string", + "format": "date-time", + "description": "ISO 8601 timestamp when this restriction took effect.", + "example": "2026-09-06T14:00:00.000Z" + }, + "docs": { + "type": "string", + "maxLength": 500, + "format": "uri", + "description": "Documentation for this restriction.", + "example": "https://docs.polymorfa.com/safety/restrictions" + } + }, + "required": [ + "phoneNumber", + "action", + "scope", + "rung", + "previousRung", + "reason", + "health", + "healthBand", + "requires", + "throughputPerMinute", + "eligibleLiftAt", + "liftRequires", + "appealUrl", + "startedAt", + "docs" + ], + "additionalProperties": false + }, + "BanSafeActionEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/BanSafeActionPayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ], + "additionalProperties": false + }, + "BanSafeHealthThresholdPayload": { + "type": "object", + "properties": { + "sessionId": { + "type": "string", + "format": "uuid", + "description": "Session whose present Health crossed the project threshold." + }, + "projectId": { + "type": "string", + "format": "uuid", + "description": "Project whose Health rule produced this action." + }, + "health": { + "type": "number", + "minimum": 0, + "maximum": 100, + "description": "Present Health; higher is healthier." + }, + "threshold": { + "type": "integer", + "minimum": 0, + "maximum": 100, + "description": "Configured project threshold crossed by this evaluation." + }, + "healthSource": { + "type": "string", + "enum": [ + "rules_v1", + "ml_model" + ], + "description": "Estimator family used by the evaluation." + }, + "estimatorVersion": { + "type": "string", + "minLength": 1, + "maxLength": 128, + "description": "Estimator version used by the evaluation." + }, + "modelVersion": { + "type": "string", + "nullable": true, + "minLength": 1, + "maxLength": 128, + "description": "Learned-model version, or null for a rules-based estimate." + }, + "evaluatedAt": { + "type": "string", + "format": "date-time", + "description": "Evaluation time in ISO 8601 format." + }, + "policyVersion": { + "type": "integer", + "minimum": 1, + "maximum": 9007199254740991, + "description": "Project Health rule version evaluated." + }, + "episodeId": { + "type": "string", + "format": "uuid", + "description": "Stable below-threshold episode identifier." + }, + "actionId": { + "type": "string", + "format": "uuid", + "description": "Stable event identity used for retries." + } + }, + "required": [ + "sessionId", + "projectId", + "health", + "threshold", + "healthSource", + "estimatorVersion", + "modelVersion", + "evaluatedAt", + "policyVersion", + "episodeId", + "actionId" + ], + "additionalProperties": false + }, + "BanSafeHealthThresholdEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/BanSafeHealthThresholdPayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ], + "additionalProperties": false + }, + "BanSafeIncidentPayload": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Incident id. Stable, quotable, and the subject of a Ban Insurance claim.", + "example": "01936b2e-5f2a-7c1d-9a3e-8b4c2d1e0f11" + }, + "phoneNumber": { + "type": "string", + "pattern": "^\\+[1-9]\\d{1,14}$", + "description": "The customer's own number in E.164 format.", + "example": "+15551234567" + }, + "kind": { + "type": "string", + "enum": [ + "cap_warning", + "cap_reached", + "timelock", + "temporary_ban", + "permanent_ban", + "connect_blocked", + "customer_report" + ], + "description": "What WhatsApp did, or customer_report when you reported it." + }, + "source": { + "type": "string", + "enum": [ + "runtime", + "customer" + ], + "description": "Whether Polymorfa observed it or you reported it." + }, + "startedAt": { + "type": "string", + "format": "date-time", + "description": "ISO 8601 timestamp when the restriction started.", + "example": "2026-09-06T14:03:12.000Z" + }, + "endsAt": { + "type": "string", + "nullable": true, + "format": "date-time", + "description": "ISO 8601 timestamp when the restriction ends, or null when it has no end. A ban you report ends 24 hours after the time you give unless you report it again or Polymorfa observes the restriction itself.", + "example": "2026-09-07T14:03:12.000Z" + }, + "belief": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "How confident Polymorfa is that this restriction was real, from 0 to 1. A restriction WhatsApp announced is 1. A ban you report starts at 0.9 and moves once the number's own sending shows whether it was restricted.", + "example": 1 + }, + "resolution": { + "type": "string", + "enum": [ + "open", + "corroborated", + "contradicted", + "phone_switch", + "final" + ], + "description": "How the incident settled. open: still being decided. corroborated: a report and an observed restriction agree. contradicted: the number kept sending, so there was no restriction. phone_switch: the number moved to another phone. final: settled with the confidence shown." + }, + "claimId": { + "type": "string", + "nullable": true, + "description": "The Ban Insurance claim this incident belongs to, or null when there is none.", + "example": null + }, + "closedAt": { + "type": "string", + "nullable": true, + "format": "date-time", + "description": "ISO 8601 timestamp when you closed or retracted the report, or null.", + "example": null + } + }, + "required": [ + "id", + "phoneNumber", + "kind", + "source", + "startedAt", + "endsAt", + "belief", + "resolution", + "claimId", + "closedAt" + ], + "additionalProperties": false + }, + "BanSafeIncidentEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/BanSafeIncidentPayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ], + "additionalProperties": false + }, + "BanSafeClaimPayload": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Claim id. Stable and quotable.", + "example": "01936b2e-5f2a-7c1d-9a3e-8b4c2d1e0f22" + }, + "incidentId": { + "type": "string", + "description": "The incident this claim was filed against.", + "example": "01936b2e-5f2a-7c1d-9a3e-8b4c2d1e0f11" + }, + "phoneNumber": { + "type": "string", + "pattern": "^\\+[1-9]\\d{1,14}$", + "description": "The customer's own number in E.164 format.", + "example": "+15551234567" + }, + "status": { + "type": "string", + "enum": [ + "filed", + "under_review", + "approved", + "denied", + "paid", + "reversed" + ], + "description": "Where the claim sits. filed and under_review are open. approved means it was accepted, and with a zero amount that there was nothing to return. paid means the credits are on your balance. reversed means what Polymorfa knew about the ban changed afterwards and the credits were taken back." + }, + "verdict": { + "type": "string", + "enum": [ + "other_device", + "customer_conduct", + "shared_network", + "ours", + "inconclusive" + ], + "description": "What the ban was attributed to. other_device: another device on the account was sending. customer_conduct: Polymorfa was already restricting this number, or named the same serious problem for a week. shared_network: the number shared its connection with numbers that were being restricted. ours: nothing points at how the number was used. inconclusive: Polymorfa could not see enough of the window to say." + }, + "windowStart": { + "type": "string", + "format": "date-time", + "description": "ISO 8601 start of the 30 days the refund covers.", + "example": "2026-08-07T14:03:12.000Z" + }, + "windowEnd": { + "type": "string", + "format": "date-time", + "description": "ISO 8601 end of the window: the moment the ban started.", + "example": "2026-09-06T14:03:12.000Z" + }, + "measuredCents": { + "type": "integer", + "minimum": 0, + "description": "Credits this number consumed inside the window, in cents.", + "example": 1080 + }, + "capCents": { + "type": "integer", + "minimum": 0, + "description": "The most a claim on this number's plan can return, in cents.", + "example": 1080 + }, + "amountCents": { + "type": "integer", + "minimum": 0, + "description": "What this claim returns, in cents.", + "example": 1080 + }, + "summary": { + "type": "string", + "description": "One sentence describing the claim's state." + }, + "reason": { + "type": "string", + "description": "One sentence describing what the ban was attributed to." + }, + "decidedAt": { + "type": "string", + "nullable": true, + "format": "date-time", + "description": "ISO 8601 timestamp of the decision, or null while none was taken.", + "example": null + }, + "paidAt": { + "type": "string", + "nullable": true, + "format": "date-time", + "description": "ISO 8601 timestamp the credits landed, or null.", + "example": null + } + }, + "required": [ + "id", + "incidentId", + "phoneNumber", + "status", + "verdict", + "windowStart", + "windowEnd", + "measuredCents", + "capCents", + "amountCents", + "summary", + "reason", + "decidedAt", + "paidAt" + ], + "additionalProperties": false + }, + "BanSafeClaimEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/BanSafeClaimPayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ], + "additionalProperties": false + }, + "MessageFailedPayload": { + "type": "object", + "properties": { + "to": { + "allOf": [ + { + "$ref": "#/components/schemas/JIDRef" + }, + { + "description": "Recipient chat the send was attempted to" + } + ] + }, + "type": { + "type": "string", + "description": "Type of the attempted message (text, image, ...)", + "example": "text" + }, + "error": { + "type": "string", + "enum": [ + "invalid_recipient", + "session_not_connected", + "ack_timeout", + "send_failed", + "blocked_by_safety" + ], + "description": "Sanitized failure class", + "example": "send_failed" + }, + "code": { + "type": "string", + "description": "Stable machine-readable code from the API error envelope, present for classified safety refusals and an unknown send outcome", + "example": "bansafe_cold_blocked" + }, + "retryAfter": { + "type": "integer", + "minimum": 0, + "exclusiveMinimum": true, + "description": "Whole seconds to wait before retrying a paced send, exhausted allowance, or temporary allowance-accounting pause", + "example": 5 + }, + "timestamp": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp in seconds when the failure occurred", + "example": 1757161200 + } + }, + "required": [ + "to", + "type", + "error", + "timestamp" + ] + }, + "MessageFailedEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/MessageFailedPayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ] + }, + "TemplateStatusPayload": { + "type": "object", + "properties": { + "templateName": { + "type": "string", + "description": "Template name as registered with Meta", + "example": "order_update" + }, + "templateId": { + "type": "string", + "description": "Meta template id", + "example": "1234567890" + }, + "status": { + "type": "string", + "description": "New approval status: APPROVED, REJECTED, PAUSED, DISABLED, DELETED", + "example": "APPROVED" + }, + "category": { + "type": "string", + "description": "Template category (MARKETING, UTILITY, AUTHENTICATION)", + "example": "UTILITY" + }, + "reason": { + "type": "string", + "description": "Reason for the status change; empty unless REJECTED, PAUSED or DISABLED", + "example": "" + }, + "qualityRating": { + "type": "string", + "description": "Quality rating bucket reported by Meta (GREEN, YELLOW, RED)", + "example": "GREEN" + } + }, + "required": [ + "templateName", + "templateId", + "status", + "category", + "reason", + "qualityRating" + ] + }, + "TemplateStatusEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/TemplateStatusPayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ] + }, + "CampaignPausedPayload": { + "type": "object", + "properties": { + "campaignId": { + "type": "string", + "description": "Campaign id", + "example": "01936b2e-5f2a-7c1d-9a3e-8b4c2d1e0f11" + }, + "sentCount": { + "type": "integer", + "minimum": 0, + "description": "Recipients sent so far" + }, + "remainingCount": { + "type": "integer", + "minimum": 0, + "description": "Recipients still queued" + }, + "pausedAt": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp in seconds when the campaign paused", + "example": 1757161200 + } + }, + "required": [ + "campaignId", + "sentCount", + "remainingCount", + "pausedAt" + ] + }, + "CampaignPausedEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/CampaignPausedPayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ] + }, + "CampaignCompletedPayload": { + "type": "object", + "properties": { + "campaignId": { + "type": "string", + "description": "Campaign id", + "example": "01936b2e-5f2a-7c1d-9a3e-8b4c2d1e0f11" + }, + "sentCount": { + "type": "integer", + "minimum": 0 + }, + "deliveredCount": { + "type": "integer", + "minimum": 0 + }, + "readCount": { + "type": "integer", + "minimum": 0 + }, + "failedCount": { + "type": "integer", + "minimum": 0 + }, + "skippedCount": { + "type": "integer", + "minimum": 0 + }, + "responseCount": { + "type": "integer", + "minimum": 0 + }, + "completedAt": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp in seconds when the last recipient settled", + "example": 1757161200 + }, + "durationMs": { + "type": "integer", + "minimum": 0, + "description": "Wall-clock duration from launch to completion, in milliseconds" + } + }, + "required": [ + "campaignId", + "sentCount", + "deliveredCount", + "readCount", + "failedCount", + "skippedCount", + "responseCount", + "completedAt", + "durationMs" + ] + }, + "CampaignCompletedEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/CampaignCompletedPayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ] + }, + "CampaignFailedPayload": { + "type": "object", + "properties": { + "campaignId": { + "type": "string", + "description": "Campaign id", + "example": "01936b2e-5f2a-7c1d-9a3e-8b4c2d1e0f11" + }, + "reason": { + "type": "string", + "description": "Stable reason the campaign failed", + "example": "no_eligible_numbers" + }, + "failedAt": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp in seconds when the campaign failed", + "example": 1757161200 + } + }, + "required": [ + "campaignId", + "reason", + "failedAt" + ] + }, + "CampaignFailedEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/CampaignFailedPayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ] + }, + "CampaignRecipientSentPayload": { + "type": "object", + "properties": { + "campaignId": { + "type": "string", + "description": "Campaign id", + "example": "01936b2e-5f2a-7c1d-9a3e-8b4c2d1e0f11" + }, + "recipientId": { + "type": "string", + "description": "Campaign recipient id", + "example": "01936b2e-6a11-7d2e-8f4a-1c2b3d4e5f66" + }, + "phone": { + "type": "string", + "description": "Recipient phone number in E.164", + "example": "+14155550123" + }, + "sessionKey": { + "type": "string", + "description": "Sending number's session key", + "example": "sales-1" + }, + "externalMessageId": { + "type": "string", + "description": "WhatsApp message id of the delivered send", + "example": "3EB0A1B2C3D4E5F60718" + }, + "variantKey": { + "type": "string", + "description": "Content variant used for this recipient", + "example": "v1" + }, + "attempt": { + "type": "integer", + "minimum": 0, + "exclusiveMinimum": true, + "description": "Attempt number that succeeded", + "example": 1 + } + }, + "required": [ + "campaignId", + "recipientId", + "phone", + "sessionKey", + "externalMessageId", + "variantKey", + "attempt" + ] + }, + "CampaignRecipientSentEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/CampaignRecipientSentPayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ] + }, + "CampaignRecipientFailedPayload": { + "type": "object", + "properties": { + "campaignId": { + "type": "string", + "description": "Campaign id", + "example": "01936b2e-5f2a-7c1d-9a3e-8b4c2d1e0f11" + }, + "recipientId": { + "type": "string", + "description": "Campaign recipient id", + "example": "01936b2e-6a11-7d2e-8f4a-1c2b3d4e5f66" + }, + "phone": { + "type": "string", + "description": "Recipient phone number in E.164", + "example": "+14155550123" + }, + "attempts": { + "type": "integer", + "minimum": 0, + "description": "Attempts made before giving up" + }, + "error": { + "type": "string", + "description": "Sanitized failure class or stable code", + "example": "ack_timeout" + }, + "failedAt": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp in seconds when the recipient was marked failed", + "example": 1757161200 + } + }, + "required": [ + "campaignId", + "recipientId", + "phone", + "attempts", + "error", + "failedAt" + ] + }, + "CampaignRecipientFailedEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/CampaignRecipientFailedPayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ] + }, + "CampaignRecipientSkippedPayload": { + "type": "object", + "properties": { + "campaignId": { + "type": "string", + "description": "Campaign id", + "example": "01936b2e-5f2a-7c1d-9a3e-8b4c2d1e0f11" + }, + "recipientId": { + "type": "string", + "description": "Campaign recipient id", + "example": "01936b2e-6a11-7d2e-8f4a-1c2b3d4e5f66" + }, + "phone": { + "type": "string", + "description": "Recipient phone number in E.164", + "example": "+14155550123" + }, + "reason": { + "type": "string", + "description": "Stable skip reason (skipped-optout, skipped-error, skipped-cold)", + "example": "skipped-cold" + }, + "skippedAt": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp in seconds when the recipient was skipped", + "example": 1757161200 + } + }, + "required": [ + "campaignId", + "recipientId", + "phone", + "reason", + "skippedAt" + ] + }, + "CampaignRecipientSkippedEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/CampaignRecipientSkippedPayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ] + }, + "CampaignThrottledPayload": { + "type": "object", + "properties": { + "campaignId": { + "type": "string", + "description": "Campaign id", + "example": "01936b2e-5f2a-7c1d-9a3e-8b4c2d1e0f11" + }, + "sessionKey": { + "type": "string", + "description": "Sending number's session key", + "example": "sales-1" + }, + "reason": { + "type": "string", + "description": "Why sending was paced", + "example": "bansafe_throttled" + }, + "deferredCount": { + "type": "integer", + "minimum": 0, + "description": "Recipients deferred in this pass" + }, + "at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp in seconds of the pacing decision", + "example": 1757161200 + } + }, + "required": [ + "campaignId", + "sessionKey", + "reason", + "deferredCount", + "at" + ] + }, + "CampaignThrottledEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/CampaignThrottledPayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ] + }, + "CampaignCapReachedPayload": { + "type": "object", + "properties": { + "campaignId": { + "type": "string", + "description": "Campaign id", + "example": "01936b2e-5f2a-7c1d-9a3e-8b4c2d1e0f11" + }, + "sessionKey": { + "type": "string", + "description": "Sending number's session key", + "example": "sales-1" + }, + "phone": { + "type": "string", + "description": "Sending number in E.164", + "example": "+14155550100" + }, + "capType": { + "type": "string", + "description": "Which cap was reached: hourly or daily", + "example": "daily" + }, + "capLimit": { + "type": "integer", + "minimum": 0, + "description": "The cap that was reached" + }, + "windowResetsAt": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp in seconds when the cap window resets", + "example": 1757161200 + }, + "at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp in seconds of the decision", + "example": 1757161200 + } + }, + "required": [ + "campaignId", + "sessionKey", + "phone", + "capType", + "capLimit", + "windowResetsAt", + "at" + ] + }, + "CampaignCapReachedEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/CampaignCapReachedPayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ] + }, + "CampaignColdBlockedPayload": { + "type": "object", + "properties": { + "campaignId": { + "type": "string", + "description": "Campaign id", + "example": "01936b2e-5f2a-7c1d-9a3e-8b4c2d1e0f11" + }, + "recipientId": { + "type": "string", + "description": "Campaign recipient id", + "example": "01936b2e-6a11-7d2e-8f4a-1c2b3d4e5f66" + }, + "phone": { + "type": "string", + "description": "Recipient phone number in E.164", + "example": "+14155550123" + }, + "surface": { + "type": "string", + "description": "Campaign surface", + "example": "whatsapp" + }, + "reason": { + "type": "string", + "description": "Stable hold reason", + "example": "bansafe_cold_held" + }, + "at": { + "type": "integer", + "minimum": 0, + "description": "Unix timestamp in seconds when the recipient was held", + "example": 1757161200 + } + }, + "required": [ + "campaignId", + "recipientId", + "phone", + "surface", + "reason", + "at" + ] + }, + "CampaignColdBlockedEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/CampaignColdBlockedPayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ] + }, + "PingResponse": { + "type": "object", + "properties": { + "status": { + "type": "string", + "example": "ok" + } + }, + "required": [ + "status" + ] + }, + "HealthCheck": { + "type": "object", + "properties": { + "status": { + "type": "string", + "example": "healthy" + }, + "error": { + "type": "string" + } + }, + "required": [ + "status" + ] + }, + "HealthResponse": { + "type": "object", + "properties": { + "status": { + "type": "string", + "example": "healthy" + }, + "checks": { + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/HealthCheck" + } + } + }, + "required": [ + "status", + "checks" + ] + }, + "VersionResponse": { + "type": "object", + "properties": { + "version": { + "type": "string" + }, + "buildTime": { + "type": "string" + }, + "env": { + "type": "string" + }, + "apiVersion": { + "type": "string" + }, + "minSupportedVersion": { + "type": "string" + } + }, + "required": [ + "version", + "buildTime", + "env", + "apiVersion", + "minSupportedVersion" + ] + }, + "StatusResponse": { + "type": "object", + "properties": { + "status": { + "type": "string" + }, + "uptime": { + "type": "string" + }, + "version": { + "type": "string" + }, + "env": { + "type": "string" + } + }, + "required": [ + "status", + "uptime", + "version", + "env" + ] + }, + "ErrorResponse": { + "type": "object", + "properties": { + "error": { + "type": "string", + "description": "Human-readable error message" + }, + "code": { + "type": "string", + "description": "Stable machine-readable error code, present on safety and entitlement refusals" + }, + "retryAfter": { + "type": "integer", + "description": "Seconds until the request can be retried, present on paced refusals and retryable service pauses" + }, + "docs": { + "type": "string", + "description": "URL to the documentation for this error" + } + }, + "required": [ + "error" + ] + }, + "SuccessResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean" + }, + "message": { + "type": "string" + } + }, + "required": [ + "success" + ] + }, + "ClientToken": { + "type": "object", + "properties": { + "token": { + "type": "string", + "description": "Client token with pmfa_ct_ prefix" + }, + "expiresAt": { + "type": "string" + } + }, + "required": [ + "token", + "expiresAt" + ] + }, + "MintClientTokenResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/ClientToken" + } + }, + "required": [ + "success", + "data" + ] + }, + "MintClientTokenRequest": { + "type": "object", + "properties": { + "session": { + "type": "string", + "minLength": 1 + }, + "ephemeralId": { + "type": "string", + "minLength": 1 + }, + "ttlSeconds": { + "type": "integer" + } + }, + "required": [ + "session", + "ephemeralId" + ] + }, + "ClientRules": { + "type": "object", + "properties": { + "actions": { + "type": "array", + "items": { + "type": "string" + } + }, + "recipientMode": { + "type": "string" + }, + "verifiedJids": { + "type": "array", + "items": { + "type": "string" + } + }, + "rateLimits": { + "type": "object", + "properties": { + "perMinute": { + "type": "integer", + "minimum": 0 + }, + "perDay": { + "type": "integer", + "minimum": 0 + } + } + } + }, + "required": [ + "actions", + "recipientMode" + ] + }, + "GetClientRulesResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/ClientRules" + } + }, + "required": [ + "success", + "data" + ] + }, + "SetClientRulesRequest": { + "type": "object", + "properties": { + "recipientMode": { + "type": "string" + }, + "allowedActions": { + "type": "string", + "default": "" + }, + "rateLimit": { + "type": "integer", + "default": 0 + }, + "maxDaily": { + "type": "integer", + "default": 0 + }, + "allowedOrigins": { + "type": "string", + "default": "" + }, + "enabled": { + "type": "boolean" + } + }, + "required": [ + "recipientMode", + "enabled" + ] + }, + "Operation": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "kind": { + "type": "string" + }, + "resourceType": { + "type": "string" + }, + "resourceId": { + "type": "string" + }, + "projectId": { + "type": "string", + "nullable": true, + "format": "uuid" + }, + "status": { + "type": "string", + "enum": [ + "pending", + "running", + "action_required", + "cancelling", + "succeeded", + "failed", + "cancelled" + ] + }, + "progressCode": { + "type": "string", + "nullable": true + }, + "failureCode": { + "type": "string", + "nullable": true + }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "updatedAt": { + "type": "string", + "format": "date-time" + }, + "completedAt": { + "type": "string", + "nullable": true, + "format": "date-time" + } + }, + "required": [ + "id", + "kind", + "resourceType", + "resourceId", + "projectId", + "status", + "progressCode", + "failureCode", + "createdAt", + "updatedAt", + "completedAt" + ] + }, + "Session": { + "type": "object", + "properties": { + "sessionId": { + "type": "string", + "description": "Canonical per-org session identifier. Use this in /api/sessions/{session}/* paths." + }, + "name": { + "type": "string" + }, + "tenantId": { + "type": "string" + }, + "connection": { + "type": "string", + "enum": [ + "linked_device", + "cloud_api" + ], + "description": "How the session connects to WhatsApp. 'linked_device' pairs as a WhatsApp linked device; 'cloud_api' uses the Meta Cloud API. Immutable after create." + }, + "testMode": { + "type": "boolean", + "description": "Whether this session was created as a simulated testing number." + }, + "status": { + "type": "string", + "description": "Current status: CONNECTING, CONNECTED, or DISCONNECTED" + }, + "statusReason": { + "type": "string" + }, + "runnerId": { + "type": "string" + }, + "proxy": { + "type": "string" + }, + "config": { + "type": "object", + "additionalProperties": { + "nullable": true + } + }, + "createdAt": { + "type": "string" + }, + "updatedAt": { + "type": "string" + } + }, + "required": [ + "name", + "tenantId", + "connection", + "testMode", + "status", + "config", + "createdAt", + "updatedAt" + ] + }, + "ListSessionsResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Session" + } + } + }, + "required": [ + "success", + "data" + ] + }, + "SessionOperation": { + "allOf": [ + { + "$ref": "#/components/schemas/Session" + }, + { + "type": "object", + "properties": { + "operationId": { + "type": "string", + "format": "uuid" + } + } + } + ] + }, + "CreateSessionResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/SessionOperation" + } + }, + "required": [ + "success", + "data" + ] + }, + "CloudApiCredentials": { + "type": "object", + "properties": { + "phoneNumberId": { + "type": "string", + "minLength": 1 + }, + "wabaId": { + "type": "string", + "minLength": 1 + }, + "businessAccountId": { + "type": "string" + }, + "appId": { + "type": "string", + "minLength": 1 + }, + "appSecret": { + "type": "string", + "minLength": 1 + }, + "systemUserToken": { + "type": "string", + "minLength": 1 + }, + "webhookVerifyToken": { + "type": "string", + "minLength": 1 + } + }, + "required": [ + "phoneNumberId", + "wabaId", + "appId", + "appSecret", + "systemUserToken", + "webhookVerifyToken" + ], + "description": "Meta credentials. Required when connection='cloud_api'. Encrypted at rest before storage." + }, + "HistorySyncPolicy": { + "type": "object", + "properties": { + "mode": { + "type": "string", + "enum": [ + "metadata_only", + "deliver" + ], + "default": "metadata_only" + }, + "requestFull": { + "type": "boolean", + "default": false + } + }, + "additionalProperties": false + }, + "CreateSessionRequest": { + "type": "object", + "properties": { + "projectId": { + "type": "string", + "minLength": 1, + "description": "Project id the session belongs to. Required." + }, + "sessionId": { + "type": "string", + "minLength": 1, + "description": "Canonical per-org session identifier (1-64 alphanumeric chars, dots, hyphens, underscores). Caller-supplied or generated; returned in the response. This is the id used in all /api/sessions/{session}/* paths." + }, + "name": { + "type": "string", + "minLength": 1, + "description": "Optional human-friendly label for the session. Not an id." + }, + "start": { + "type": "boolean" + }, + "connection": { + "type": "string", + "enum": [ + "linked_device", + "cloud_api" + ], + "description": "How the session connects to WhatsApp. 'linked_device' (default) pairs as a WhatsApp linked device; 'cloud_api' uses the Meta Cloud API and requires the `cloudApi` creds block. Immutable after create." + }, + "testMode": { + "type": "boolean", + "description": "Create a simulated testing number (behaves like a real session via the simulated universe). Defaults to false." + }, + "bartenderMode": { + "type": "string", + "enum": [ + "magic", + "passthrough", + "passthrough_plus" + ], + "description": "Bartender privacy tier. Defaults to 'magic'. Mutable via the handoff ceremony at POST /api/sessions/{name}/handoff-keys + /handoff-import. 'magic' — Polymorfa holds the Signal session; full message visibility. 'passthrough' — Polymorfa holds noise creds only; neither messages nor app state are decryptable on Polymorfa's side. 'passthrough_plus' — Track P + customer has uploaded AppStateSyncKeys for selected collections (contacts, labels, mute/archive, blocklist), so Polymorfa sees metadata mutations but never message content." + }, + "cloudApi": { + "$ref": "#/components/schemas/CloudApiCredentials" + }, + "config": { + "type": "object", + "additionalProperties": true + }, + "historySync": { + "$ref": "#/components/schemas/HistorySyncPolicy" + } + }, + "required": [ + "projectId" + ] + }, + "GetSessionResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/Session" + } + }, + "required": [ + "success", + "data" + ] + }, + "UpdateSessionResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/Session" + } + }, + "required": [ + "success", + "data" + ] + }, + "UpdateSessionRequest": { + "type": "object", + "properties": { + "config": { + "type": "object", + "additionalProperties": true + }, + "historySync": { + "$ref": "#/components/schemas/HistorySyncPolicy" + } + } + }, + "OperationAccepted": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "message": { + "type": "string" + }, + "operationId": { + "type": "string", + "format": "uuid" + }, + "immediate": { + "type": "boolean" + } + }, + "required": [ + "success", + "message" + ] + }, + "WhatsAppAccount": { + "type": "object", + "properties": { + "lid": { + "type": "string" + }, + "phoneNumber": { + "type": "string" + }, + "pushName": { + "type": "string" + }, + "businessName": { + "type": "string" + }, + "platform": { + "type": "string" + }, + "profilePicUrl": { + "type": "string" + } + }, + "required": [ + "lid", + "pushName" + ] + }, + "GetSessionAccountResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/WhatsAppAccount" + } + }, + "required": [ + "success", + "data" + ] + }, + "HandoffKeysResponse": { + "type": "object", + "properties": { + "runnerPublicKeyB64": { + "type": "string", + "description": "Curve25519 public key the customer must seal their snapshot to. Base64 (URL-safe, no padding)." + }, + "handoffId": { + "type": "string" + } + }, + "required": [ + "runnerPublicKeyB64", + "handoffId" + ] + }, + "HandoffKeysSuccess": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/HandoffKeysResponse" + } + }, + "required": [ + "success", + "data" + ] + }, + "HandoffImportSuccess": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/SuccessResponse" + } + }, + "required": [ + "success", + "data" + ] + }, + "HandoffImportRequest": { + "type": "object", + "properties": { + "handoffId": { + "type": "string", + "description": "Round-trip id returned by POST /handoff-keys." + }, + "sealedEnvelopeB64": { + "type": "string", + "description": "Sealed-box envelope (ephemeral_pub(32) || ciphertext) wrapping the customer's SignalStoreSnapshot. Base64." + }, + "snapshotHashHex": { + "type": "string", + "description": "SHA-256 of the unsealed snapshot JSON, hex-encoded. The runner verifies after decrypt before flipping bartenderMode." + } + }, + "required": [ + "handoffId", + "sealedEnvelopeB64", + "snapshotHashHex" + ] + }, + "UploadAppStateKeysSuccess": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/SuccessResponse" + } + }, + "required": [ + "success", + "data" + ] + }, + "UploadAppStateKeysRequest": { + "type": "object", + "properties": { + "keys": { + "type": "array", + "items": { + "type": "object", + "properties": { + "keyId": { + "type": "string", + "description": "Base64-encoded AppStateSyncKey id (URL-safe-no-pad)." + }, + "keyB64": { + "type": "string", + "description": "Base64-encoded 32-byte symmetric key bytes." + }, + "fingerprintB64": { + "type": "string", + "description": "Base64-encoded WA fingerprint blob (optional)." + }, + "timestamp": { + "type": "number", + "description": "Unix-seconds timestamp WA stamped on the key." + } + }, + "required": [ + "keyId", + "keyB64", + "timestamp" + ] + } + }, + "upgradeTo": { + "type": "string", + "enum": [ + "passthrough_plus" + ], + "description": "When set, atomically flips sessions.config.bartenderMode → passthrough_plus after the keys persist. Eliminates the window where mode is set but no keys are staged." + } + }, + "required": [ + "keys" + ] + }, + "HandoffAckSuccess": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/SuccessResponse" + } + }, + "required": [ + "success", + "data" + ] + }, + "HandoffAckRequest": { + "type": "object", + "properties": { + "handoffId": { + "type": "string" + }, + "snapshotHashHex": { + "type": "string", + "description": "SHA-256 of the snapshot the customer received via mode.handoff_export. API verifies this matches what the runner exported before flipping bartenderMode." + } + }, + "required": [ + "handoffId", + "snapshotHashHex" + ] + }, + "QRResponse": { + "type": "object", + "properties": { + "qr": { + "type": "string", + "description": "QR code data to encode into a scannable image" + }, + "event": { + "type": "string", + "description": "QR channel event (e.g. success, timeout)" + } + } + }, + "GetQRCodeResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/QRResponse" + } + }, + "required": [ + "success", + "data" + ] + }, + "PairCodeResponse": { + "type": "object", + "properties": { + "code": { + "type": "string", + "description": "Numeric pairing code for device linking" + } + }, + "required": [ + "code" + ] + }, + "RequestPairCodeResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/PairCodeResponse" + } + }, + "required": [ + "success", + "data" + ] + }, + "PairCodeRequest": { + "type": "object", + "properties": { + "phone": { + "type": "string", + "minLength": 1 + } + }, + "required": [ + "phone" + ] + }, + "MessageResponse": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "WhatsApp message ID" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 send timestamp" + }, + "status": { + "type": "string", + "description": "Delivery status: pending, sent, delivered, read" + }, + "mediaId": { + "type": "string" + }, + "senderLid": { + "type": "string" + }, + "senderPhoneNumber": { + "type": "string" + }, + "fromLid": { + "type": "string" + }, + "fromPhoneNumber": { + "type": "string" + } + }, + "required": [ + "id", + "timestamp", + "status", + "senderLid", + "fromLid" + ] + }, + "SendMessageResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/MessageResponse" + } + }, + "required": [ + "success", + "data" + ] + }, + "QuotedMessage": { + "type": "object", + "properties": { + "messageId": { + "type": "string" + }, + "participant": { + "type": "string" + }, + "type": { + "type": "string" + }, + "text": { + "type": "string" + } + }, + "required": [ + "messageId", + "participant" + ] + }, + "SendMessageRequest": { + "type": "object", + "properties": { + "chatId": { + "type": "string", + "minLength": 1 + }, + "type": { + "type": "string", + "enum": [ + "text", + "image", + "file", + "voice", + "video", + "poll", + "location", + "contact", + "request_phone_number", + "product", + "product_list", + "order", + "list", + "buttons", + "address_message", + "flow" + ] + }, + "text": { + "type": "string" + }, + "url": { + "type": "string" + }, + "base64": { + "type": "string" + }, + "mimeType": { + "type": "string" + }, + "filename": { + "type": "string" + }, + "caption": { + "type": "string" + }, + "ptt": { + "type": "boolean" + }, + "pollTitle": { + "type": "string" + }, + "pollOptions": { + "type": "array", + "items": { + "type": "string" + } + }, + "pollMultiSelect": { + "type": "boolean" + }, + "latitude": { + "type": "number" + }, + "longitude": { + "type": "number" + }, + "address": { + "type": "string" + }, + "vcard": { + "type": "string" + }, + "product": { + "type": "object", + "properties": { + "businessOwnerJid": { + "type": "string", + "pattern": "^\\d+@s\\.whatsapp\\.net$" + }, + "id": { + "type": "string", + "minLength": 1 + }, + "title": { + "type": "string", + "minLength": 1 + }, + "description": { + "type": "string", + "minLength": 0 + }, + "currencyCode": { + "type": "string", + "pattern": "^[A-Z]{3}$" + }, + "priceAmount1000": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "salePriceAmount1000": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "retailerId": { + "type": "string", + "minLength": 0 + }, + "url": { + "type": "string", + "maxLength": 2048, + "format": "uri" + }, + "imageCount": { + "type": "integer", + "minimum": 0, + "maximum": 100 + }, + "image": { + "type": "object", + "properties": { + "url": { + "type": "string", + "maxLength": 4096, + "format": "uri" + }, + "base64": { + "type": "string", + "maxLength": 87384 + }, + "mimeType": { + "type": "string", + "minLength": 0 + } + } + }, + "body": { + "type": "string", + "minLength": 0 + }, + "footer": { + "type": "string", + "minLength": 0 + } + }, + "required": [ + "businessOwnerJid", + "id", + "title", + "currencyCode", + "priceAmount1000" + ] + }, + "productList": { + "type": "object", + "properties": { + "businessOwnerJid": { + "type": "string", + "pattern": "^\\d+@s\\.whatsapp\\.net$" + }, + "title": { + "type": "string", + "minLength": 1 + }, + "description": { + "type": "string", + "minLength": 0 + }, + "buttonText": { + "type": "string", + "minLength": 1 + }, + "footer": { + "type": "string", + "minLength": 0 + }, + "sections": { + "type": "array", + "items": { + "type": "object", + "properties": { + "title": { + "type": "string", + "minLength": 0 + }, + "productIds": { + "type": "array", + "items": { + "type": "string", + "minLength": 1 + }, + "minItems": 1, + "maxItems": 30 + } + }, + "required": [ + "productIds" + ] + }, + "minItems": 1, + "maxItems": 10 + } + }, + "required": [ + "businessOwnerJid", + "title", + "buttonText", + "sections" + ] + }, + "order": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1 + }, + "thumbnailBase64": { + "type": "string", + "maxLength": 87384 + }, + "itemCount": { + "type": "integer", + "minimum": 1, + "maximum": 100 + }, + "status": { + "type": "string", + "enum": [ + "inquiry", + "accepted", + "declined" + ] + }, + "message": { + "type": "string", + "minLength": 0 + }, + "title": { + "type": "string", + "minLength": 0 + }, + "sellerJid": { + "type": "string", + "pattern": "^\\d+@s\\.whatsapp\\.net$" + }, + "token": { + "type": "string", + "minLength": 0 + }, + "totalAmount1000": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "totalCurrencyCode": { + "type": "string", + "pattern": "^[A-Z]{3}$" + }, + "catalogType": { + "type": "string", + "minLength": 0 + } + }, + "required": [ + "id", + "itemCount", + "status", + "sellerJid", + "totalAmount1000", + "totalCurrencyCode" + ] + }, + "list": { + "type": "object", + "properties": { + "title": { + "type": "string", + "minLength": 1 + }, + "description": { + "type": "string", + "minLength": 0 + }, + "buttonText": { + "type": "string", + "minLength": 1 + }, + "footer": { + "type": "string", + "minLength": 0 + }, + "sections": { + "type": "array", + "items": { + "type": "object", + "properties": { + "title": { + "type": "string", + "minLength": 0 + }, + "rows": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1 + }, + "title": { + "type": "string", + "minLength": 1 + }, + "description": { + "type": "string", + "minLength": 0 + } + }, + "required": [ + "id", + "title" + ] + }, + "minItems": 1, + "maxItems": 30 + } + }, + "required": [ + "rows" + ] + }, + "minItems": 1, + "maxItems": 10 + } + }, + "required": [ + "title", + "buttonText", + "sections" + ] + }, + "buttons": { + "type": "object", + "properties": { + "title": { + "type": "string", + "minLength": 0 + }, + "body": { + "type": "string", + "minLength": 1 + }, + "footer": { + "type": "string", + "minLength": 0 + }, + "buttons": { + "type": "array", + "items": { + "oneOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "url" + ] + }, + "text": { + "type": "string", + "minLength": 1 + }, + "url": { + "type": "string", + "maxLength": 2048, + "format": "uri" + } + }, + "required": [ + "type", + "text", + "url" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "call" + ] + }, + "text": { + "type": "string", + "minLength": 1 + }, + "phoneNumber": { + "type": "string", + "pattern": "^\\+?\\d{6,20}$" + } + }, + "required": [ + "type", + "text", + "phoneNumber" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "reply" + ] + }, + "text": { + "type": "string", + "minLength": 1 + }, + "id": { + "type": "string", + "minLength": 1 + } + }, + "required": [ + "type", + "text", + "id" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "copy" + ] + }, + "text": { + "type": "string", + "minLength": 1 + }, + "copyCode": { + "type": "string", + "minLength": 1 + } + }, + "required": [ + "type", + "text", + "copyCode" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "catalog" + ] + }, + "text": { + "type": "string", + "minLength": 1 + }, + "businessPhoneNumber": { + "type": "string", + "pattern": "^\\+?\\d{6,20}$" + }, + "catalogProductId": { + "type": "string", + "minLength": 0 + } + }, + "required": [ + "type", + "text", + "businessPhoneNumber" + ] + } + ] + }, + "minItems": 1, + "maxItems": 3 + } + }, + "required": [ + "body", + "buttons" + ] + }, + "addressMessage": { + "type": "object", + "properties": { + "body": { + "type": "string", + "minLength": 1 + }, + "buttonText": { + "type": "string", + "minLength": 1 + }, + "footer": { + "type": "string", + "minLength": 0 + }, + "country": { + "type": "string", + "pattern": "^[A-Z]{2}$" + } + }, + "required": [ + "body" + ] + }, + "flow": { + "type": "object", + "properties": { + "body": { + "type": "string", + "minLength": 1 + }, + "buttonText": { + "type": "string", + "minLength": 1 + }, + "footer": { + "type": "string", + "minLength": 0 + }, + "id": { + "type": "string", + "minLength": 1 + }, + "token": { + "type": "string", + "minLength": 1 + }, + "action": { + "type": "string", + "enum": [ + "navigate", + "data_exchange" + ] + }, + "screen": { + "type": "string", + "minLength": 0 + }, + "dataJson": { + "type": "string", + "minLength": 0 + } + }, + "required": [ + "body", + "buttonText", + "id", + "token", + "action" + ], + "oneOf": [ + { + "properties": { + "action": { + "enum": [ + "navigate" + ] + } + }, + "required": [ + "screen" + ] + }, + { + "properties": { + "action": { + "enum": [ + "data_exchange" + ] + } + }, + "not": { + "anyOf": [ + { + "required": [ + "screen" + ] + }, + { + "required": [ + "dataJson" + ] + } + ] + } + } + ] + }, + "isForwarded": { + "type": "boolean" + }, + "mentions": { + "type": "array", + "items": { + "type": "string" + } + }, + "quotedMessage": { + "$ref": "#/components/schemas/QuotedMessage" + }, + "template": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1 + }, + "language": { + "type": "string", + "minLength": 2 + }, + "components": { + "type": "array", + "items": { + "nullable": true + } + } + }, + "required": [ + "name", + "language" + ], + "description": "Template send (cloud_api only). When set, type is ignored. Rejected on whatsmeow sessions." + } + }, + "required": [ + "chatId", + "type" + ] + }, + "SeenRequest": { + "type": "object", + "properties": { + "chatId": { + "type": "string", + "minLength": 1 + }, + "messageId": { + "type": "string", + "minLength": 1 + }, + "participant": { + "type": "string", + "minLength": 1, + "description": "Sender JID of the message being marked read. Required by WhatsApp for group chats; when omitted the sender is resolved from the message id." + } + }, + "required": [ + "chatId", + "messageId" + ] + }, + "TypingRequest": { + "type": "object", + "properties": { + "chatId": { + "type": "string", + "minLength": 1 + }, + "state": { + "type": "string", + "enum": [ + "typing", + "recording", + "paused" + ] + } + }, + "required": [ + "chatId", + "state" + ] + }, + "SendReactionResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/MessageResponse" + } + }, + "required": [ + "success", + "data" + ] + }, + "ReactRequest": { + "type": "object", + "properties": { + "chatId": { + "type": "string", + "minLength": 1 + }, + "messageId": { + "type": "string", + "minLength": 1 + }, + "reaction": { + "type": "string" + } + }, + "required": [ + "chatId", + "messageId", + "reaction" + ] + }, + "StarMessageResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/MessageResponse" + } + }, + "required": [ + "success", + "data" + ] + }, + "StarRequest": { + "type": "object", + "properties": { + "chatId": { + "type": "string", + "minLength": 1 + }, + "messageId": { + "type": "string", + "minLength": 1 + }, + "star": { + "type": "boolean" + }, + "fromMe": { + "type": "boolean" + }, + "sender": { + "type": "string" + } + }, + "required": [ + "chatId", + "messageId", + "star" + ] + }, + "EditMessageRequest": { + "type": "object", + "properties": { + "text": { + "type": "string", + "minLength": 1 + } + }, + "required": [ + "text" + ] + }, + "DisappearingTimerRequest": { + "type": "object", + "properties": { + "durationSeconds": { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 86400 + ] + }, + { + "type": "number", + "enum": [ + 604800 + ] + }, + { + "type": "number", + "enum": [ + 7776000 + ] + } + ] + } + }, + "required": [ + "durationSeconds" + ] + }, + "RejectCallRequest": { + "type": "object", + "properties": { + "from": { + "type": "string", + "minLength": 1, + "description": "JID of the incoming caller" + } + }, + "required": [ + "from" + ] + }, + "Participant": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "lid": { + "type": "string", + "deprecated": true + }, + "phoneNumber": { + "type": "string" + }, + "username": { + "type": "string" + }, + "isAdmin": { + "type": "boolean" + }, + "isSuperAdmin": { + "type": "boolean" + } + }, + "required": [ + "id", + "lid", + "isAdmin", + "isSuperAdmin" + ] + }, + "Group": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Group JID (e.g. 120363...@g.us)" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "ownerId": { + "type": "string" + }, + "ownerLid": { + "type": "string", + "deprecated": true + }, + "createdAt": { + "type": "number", + "description": "Unix timestamp in seconds" + }, + "participants": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Participant" + } + } + }, + "required": [ + "id", + "name", + "description", + "ownerId", + "ownerLid", + "createdAt", + "participants" + ] + }, + "ListGroupsResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Group" + } + } + }, + "required": [ + "success", + "data" + ] + }, + "CreateGroupResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/Group" + } + }, + "required": [ + "success", + "data" + ] + }, + "CreateGroupRequest": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1 + }, + "participants": { + "type": "array", + "items": { + "type": "string" + }, + "minItems": 1 + } + }, + "required": [ + "name", + "participants" + ] + }, + "GroupInviteInfo": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "subject": { + "type": "string" + }, + "creatorId": { + "type": "string" + }, + "creatorLid": { + "type": "string", + "deprecated": true + }, + "createdAt": { + "type": "number" + }, + "size": { + "type": "number" + }, + "participants": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Participant" + } + } + }, + "required": [ + "id", + "subject", + "creatorId", + "creatorLid", + "createdAt", + "size", + "participants" + ] + }, + "GetGroupJoinInfoResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/GroupInviteInfo" + } + }, + "required": [ + "success", + "data" + ] + }, + "JoinGroupRequest": { + "type": "object", + "properties": { + "code": { + "type": "string", + "minLength": 1 + } + }, + "required": [ + "code" + ] + }, + "GetGroupResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/Group" + } + }, + "required": [ + "success", + "data" + ] + }, + "SetGroupFieldRequest": { + "type": "object", + "properties": { + "value": { + "type": "string" + } + }, + "required": [ + "value" + ] + }, + "InviteCodeResponse": { + "type": "object", + "properties": { + "code": { + "type": "string", + "description": "Group invite code" + } + }, + "required": [ + "code" + ] + }, + "GetGroupInviteCodeResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/InviteCodeResponse" + } + }, + "required": [ + "success", + "data" + ] + }, + "RevokeGroupInviteCodeResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/InviteCodeResponse" + } + }, + "required": [ + "success", + "data" + ] + }, + "GetGroupParticipantsResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Participant" + } + } + }, + "required": [ + "success", + "data" + ] + }, + "GroupParticipantsRequest": { + "type": "object", + "properties": { + "participants": { + "type": "array", + "items": { + "type": "string" + }, + "minItems": 1 + } + }, + "required": [ + "participants" + ] + }, + "SetGroupPictureRequest": { + "type": "object", + "properties": { + "url": { + "type": "string" + }, + "base64": { + "type": "string" + } + } + }, + "GroupAdminOnlySettingRequest": { + "type": "object", + "properties": { + "adminsOnly": { + "type": "boolean" + } + }, + "required": [ + "adminsOnly" + ] + }, + "GroupMemberAddModeRequest": { + "type": "object", + "properties": { + "mode": { + "type": "string", + "enum": [ + "admin_add", + "all_member_add" + ] + } + }, + "required": [ + "mode" + ] + }, + "GroupJoinApprovalRequest": { + "type": "object", + "properties": { + "required": { + "type": "boolean" + } + }, + "required": [ + "required" + ] + }, + "Contact": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "lid": { + "type": "string", + "deprecated": true + }, + "phoneNumber": { + "type": "string" + }, + "username": { + "type": "string" + }, + "name": { + "type": "string" + }, + "pushName": { + "type": "string" + }, + "businessName": { + "type": "string" + }, + "profileUrl": { + "type": "string" + } + }, + "required": [ + "id", + "lid", + "name", + "pushName" + ] + }, + "ListContactsResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Contact" + } + } + }, + "required": [ + "success", + "data" + ] + }, + "CheckContactResult": { + "type": "object", + "properties": { + "exists": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "lid": { + "type": "string", + "deprecated": true + }, + "phoneNumber": { + "type": "string" + }, + "username": { + "type": "string" + } + }, + "required": [ + "exists" + ] + }, + "CheckContactsResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CheckContactResult" + } + } + }, + "required": [ + "success", + "data" + ] + }, + "Blocklist": { + "type": "object", + "properties": { + "hash": { + "type": "string" + }, + "jids": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "hash", + "jids" + ] + }, + "GetBlocklistResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/Blocklist" + } + }, + "required": [ + "success", + "data" + ] + }, + "GetContactResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/Contact" + } + }, + "required": [ + "success", + "data" + ] + }, + "ProfilePictureResponse": { + "type": "object", + "properties": { + "url": { + "type": "string", + "description": "HTTPS URL of the profile picture" + } + }, + "required": [ + "url" + ] + }, + "GetContactPictureResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/ProfilePictureResponse" + } + }, + "required": [ + "success", + "data" + ] + }, + "UserInfo": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "jid": { + "type": "string", + "deprecated": true + }, + "lid": { + "type": "string", + "deprecated": true + }, + "phoneNumber": { + "type": "string" + }, + "username": { + "type": "string" + }, + "status": { + "type": "string" + }, + "pictureId": { + "type": "string" + }, + "verifiedName": { + "type": "string" + }, + "devices": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "id", + "jid", + "lid", + "status", + "pictureId", + "verifiedName", + "devices" + ] + }, + "GetUserInfoResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/UserInfo" + } + }, + "required": [ + "success", + "data" + ] + }, + "GetUserDevicesResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "success", + "data" + ] + }, + "BusinessProfile": { + "type": "object", + "properties": { + "jid": { + "type": "string" + }, + "address": { + "type": "string" + }, + "email": { + "type": "string" + }, + "description": { + "type": "string" + }, + "websites": { + "type": "array", + "items": { + "type": "string", + "format": "uri" + } + }, + "coverPhotoId": { + "type": "string" + }, + "categories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": [ + "id", + "name" + ] + } + }, + "options": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "hoursTimeZone": { + "type": "string" + }, + "hours": { + "type": "array", + "items": { + "type": "object", + "properties": { + "dayOfWeek": { + "type": "string" + }, + "mode": { + "type": "string" + }, + "openTime": { + "type": "string" + }, + "closeTime": { + "type": "string" + } + }, + "required": [ + "dayOfWeek", + "mode", + "openTime", + "closeTime" + ] + } + } + }, + "required": [ + "jid", + "address", + "email", + "description", + "websites", + "coverPhotoId", + "categories", + "options", + "hoursTimeZone", + "hours" + ] + }, + "GetBusinessProfileResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/BusinessProfile" + } + }, + "required": [ + "success", + "data" + ] + }, + "BusinessLinkedAccounts": { + "type": "object", + "properties": { + "facebookPage": { + "type": "object", + "properties": { + "hasActiveCTWAAd": { + "type": "boolean" + }, + "hasCreatedAd": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "displayName": { + "type": "string" + }, + "profileSync": { + "type": "string", + "enum": [ + "disable", + "import" + ] + }, + "profilePictureUrl": { + "type": "string", + "format": "uri" + }, + "showOnProfile": { + "type": "boolean" + }, + "whatsAppAsPageButton": { + "type": "boolean" + } + }, + "required": [ + "hasActiveCTWAAd", + "hasCreatedAd", + "id", + "displayName", + "profilePictureUrl", + "showOnProfile", + "whatsAppAsPageButton" + ] + }, + "facebookBusiness": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "displayName": { + "type": "string" + }, + "catalogId": { + "type": "string" + }, + "catalogState": { + "type": "string", + "enum": [ + "disable", + "import" + ] + } + }, + "required": [ + "id", + "displayName" + ] + }, + "instagramProfessional": { + "type": "object", + "properties": { + "handle": { + "type": "string" + }, + "displayName": { + "type": "string" + }, + "profilePictureUrl": { + "type": "string", + "format": "uri" + }, + "showOnProfile": { + "type": "boolean" + } + }, + "required": [ + "handle", + "displayName", + "profilePictureUrl", + "showOnProfile" + ] + }, + "whatsAppAdIdentity": { + "type": "object", + "properties": { + "hasActiveCTWAAd": { + "type": "boolean" + }, + "hasCreatedAd": { + "type": "boolean" + }, + "id": { + "type": "string" + } + }, + "required": [ + "hasActiveCTWAAd", + "hasCreatedAd", + "id" + ] + } + } + }, + "GetBusinessLinkedAccountsResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/BusinessLinkedAccounts" + } + }, + "required": [ + "success", + "data" + ] + }, + "BusinessEligibility": { + "type": "object", + "properties": { + "features": { + "type": "array", + "items": { + "type": "object", + "properties": { + "feature": { + "type": "string", + "enum": [ + "meta_verified", + "marketing_messages", + "genai", + "genai_image", + "meta_one", + "bb_pro" + ] + }, + "status": { + "type": "string" + }, + "expiration": { + "type": "integer" + }, + "additionalParams": { + "type": "string" + }, + "showPrivacyInterstitialToNewUsers": { + "type": "boolean" + }, + "v1Enabled": { + "type": "boolean" + } + }, + "required": [ + "feature", + "status" + ] + }, + "maxItems": 6 + } + }, + "required": [ + "features" + ] + }, + "GetBusinessEligibilityResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/BusinessEligibility" + } + }, + "required": [ + "success", + "data" + ] + }, + "GetOwnBusinessProfileResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/BusinessProfile" + } + }, + "required": [ + "success", + "data" + ] + }, + "UpdateBusinessProfileResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "type": "object", + "properties": { + "status": { + "type": "string" + } + }, + "required": [ + "status" + ] + } + }, + "required": [ + "success", + "data" + ] + }, + "BusinessProfileUpdateRequest": { + "type": "object", + "properties": { + "address": { + "type": "string", + "maxLength": 512 + }, + "email": { + "anyOf": [ + { + "type": "string", + "enum": [ + "" + ] + }, + { + "type": "string", + "maxLength": 320, + "format": "email" + } + ] + }, + "description": { + "type": "string", + "maxLength": 1024 + }, + "websites": { + "type": "array", + "items": { + "type": "string", + "maxLength": 2048, + "format": "uri" + }, + "minItems": 1, + "maxItems": 2 + }, + "hours": { + "type": "object", + "properties": { + "timeZone": { + "type": "string", + "minLength": 1, + "maxLength": 128 + }, + "days": { + "type": "array", + "items": { + "type": "object", + "properties": { + "dayOfWeek": { + "type": "string", + "enum": [ + "sun", + "mon", + "tue", + "wed", + "thu", + "fri", + "sat" + ] + }, + "mode": { + "type": "string", + "enum": [ + "specific_hours", + "open_24h", + "appointment_only" + ] + }, + "openTime": { + "type": "integer", + "minimum": 0, + "maximum": 1439 + }, + "closeTime": { + "type": "integer", + "minimum": 0, + "maximum": 1439 + } + }, + "required": [ + "dayOfWeek", + "mode" + ] + }, + "minItems": 1, + "maxItems": 7 + } + }, + "required": [ + "timeZone", + "days" + ] + } + } + }, + "SetBusinessCoverPhotoResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "type": "object", + "properties": { + "coverPhotoId": { + "type": "string" + } + }, + "required": [ + "coverPhotoId" + ] + } + }, + "required": [ + "success", + "data" + ] + }, + "BusinessCoverPhotoRequest": { + "type": "object", + "properties": { + "url": { + "type": "string", + "maxLength": 2048, + "format": "uri" + }, + "base64": { + "type": "string", + "minLength": 1, + "maxLength": 6990508 + } + } + }, + "DeleteBusinessCoverPhotoResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "type": "object", + "properties": { + "status": { + "type": "string" + } + }, + "required": [ + "status" + ] + } + }, + "required": [ + "success", + "data" + ] + }, + "BusinessMerchantCompliance": { + "type": "object", + "properties": { + "entityName": { + "type": "string", + "maxLength": 256 + }, + "entityType": { + "type": "string", + "enum": [ + "SOLE_PROPRIETORSHIP", + "PARTNERSHIP", + "PRIVATE_COMPANY", + "PUBLIC_COMPANY", + "LIMITED_LIABILITY_PARTNERSHIP", + "OTHER" + ] + }, + "isRegistered": { + "type": "boolean" + }, + "entityTypeCustom": { + "type": "string", + "maxLength": 256 + }, + "customerCare": { + "type": "object", + "properties": { + "email": { + "type": "string", + "maxLength": 254 + }, + "landlineNumber": { + "type": "string", + "maxLength": 64 + }, + "mobileNumber": { + "type": "string", + "maxLength": 64 + } + }, + "required": [ + "email", + "landlineNumber", + "mobileNumber" + ], + "additionalProperties": false + }, + "grievanceOfficer": { + "type": "object", + "properties": { + "email": { + "type": "string", + "maxLength": 254 + }, + "landlineNumber": { + "type": "string", + "maxLength": 64 + }, + "mobileNumber": { + "type": "string", + "maxLength": 64 + }, + "name": { + "type": "string", + "maxLength": 256 + } + }, + "required": [ + "email", + "landlineNumber", + "mobileNumber", + "name" + ], + "additionalProperties": false + } + }, + "required": [ + "entityName", + "entityType", + "isRegistered", + "entityTypeCustom", + "customerCare", + "grievanceOfficer" + ], + "additionalProperties": false + }, + "GetBusinessMerchantComplianceResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/BusinessMerchantCompliance" + } + }, + "required": [ + "success", + "data" + ] + }, + "SetBusinessMerchantComplianceResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/BusinessMerchantCompliance" + } + }, + "required": [ + "success", + "data" + ] + }, + "BusinessQuickReplyMutation": { + "type": "object", + "properties": { + "shortcut": { + "type": "string", + "minLength": 1, + "maxLength": 25, + "pattern": "^[\\p{L}\\p{N}]+$" + }, + "message": { + "type": "string", + "minLength": 1, + "maxLength": 65536 + }, + "keywords": { + "type": "array", + "items": { + "type": "string", + "minLength": 1, + "maxLength": 256 + }, + "maxItems": 100, + "default": [] + }, + "count": { + "type": "integer", + "minimum": 0, + "maximum": 2147483647, + "default": 0 + } + }, + "required": [ + "shortcut", + "message" + ] + }, + "BusinessQuickReply": { + "allOf": [ + { + "$ref": "#/components/schemas/BusinessQuickReplyMutation" + }, + { + "type": "object", + "properties": { + "id": { + "type": "string" + } + }, + "required": [ + "id" + ] + } + ] + }, + "CreateBusinessQuickReplyResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/BusinessQuickReply" + } + }, + "required": [ + "success", + "data" + ] + }, + "BusinessQuickReplyObserved": { + "allOf": [ + { + "$ref": "#/components/schemas/BusinessQuickReply" + }, + { + "type": "object", + "properties": { + "associatedLabelIds": { + "type": "array", + "items": { + "type": "string" + } + }, + "observedAt": { + "type": "string", + "format": "date-time" + } + }, + "required": [ + "associatedLabelIds", + "observedAt" + ] + } + ] + }, + "BusinessQuickReplyCollection": { + "type": "object", + "properties": { + "policy": { + "type": "string", + "enum": [ + "off", + "events", + "cache" + ] + }, + "status": { + "type": "string", + "enum": [ + "disabled", + "unknown", + "partial", + "fresh" + ] + }, + "unknownReason": { + "type": "string", + "enum": [ + "observation_disabled", + "not_retained", + "not_observed" + ] + }, + "observedAt": { + "type": "string", + "format": "date-time" + }, + "quickReplies": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BusinessQuickReplyObserved" + } + } + }, + "required": [ + "policy", + "status", + "quickReplies" + ] + }, + "ListBusinessQuickRepliesResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/BusinessQuickReplyCollection" + } + }, + "required": [ + "success", + "data" + ] + }, + "SetBusinessQuickReplyResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/BusinessQuickReply" + } + }, + "required": [ + "success", + "data" + ] + }, + "DeleteBusinessQuickReplyResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "status": { + "type": "string", + "enum": [ + "DELETED" + ] + } + }, + "required": [ + "id", + "status" + ] + } + }, + "required": [ + "success", + "data" + ] + }, + "BusinessProduct": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "retailerId": { + "type": "string" + }, + "belongsTo": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "price": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "url": { + "type": "string", + "format": "uri" + }, + "shimmedUrl": { + "type": "string", + "format": "uri" + }, + "hidden": { + "type": "boolean" + }, + "sanctioned": { + "type": "boolean" + }, + "maxAvailable": { + "type": "integer", + "minimum": 0 + }, + "availability": { + "type": "string" + }, + "complianceCategory": { + "type": "string" + }, + "compliance": { + "type": "object", + "properties": { + "countryCodeOrigin": { + "type": "string" + }, + "importerName": { + "type": "string" + }, + "importerAddress": { + "type": "object", + "properties": { + "street1": { + "type": "string" + }, + "street2": { + "type": "string" + }, + "city": { + "type": "string" + }, + "region": { + "type": "string" + }, + "postalCode": { + "type": "string" + }, + "countryCode": { + "type": "string" + } + } + } + } + }, + "media": { + "type": "object", + "properties": { + "images": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "originalUrl": { + "type": "string", + "format": "uri" + }, + "requestUrl": { + "type": "string", + "format": "uri" + } + }, + "required": [ + "id" + ] + } + }, + "videos": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "originalUrl": { + "type": "string", + "format": "uri" + }, + "thumbnailUrl": { + "type": "string", + "format": "uri" + } + }, + "required": [ + "id" + ] + } + } + }, + "required": [ + "images", + "videos" + ] + }, + "salePrice": { + "type": "object", + "properties": { + "price": { + "type": "string" + }, + "startDate": { + "type": "string" + }, + "endDate": { + "type": "string" + } + }, + "required": [ + "price" + ] + }, + "status": { + "type": "object", + "properties": { + "status": { + "type": "string" + }, + "canAppeal": { + "type": "boolean" + } + }, + "required": [ + "canAppeal" + ] + }, + "variant": { + "type": "object", + "properties": { + "availability": { + "type": "object", + "properties": { + "listings": { + "type": "array", + "items": { + "type": "object", + "properties": { + "productId": { + "type": "string" + }, + "available": { + "type": "boolean" + }, + "options": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ] + } + } + }, + "required": [ + "available", + "options" + ] + } + } + }, + "required": [ + "listings" + ] + }, + "listingDetails": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "lowestPrice": { + "type": "string" + }, + "multiPrice": { + "type": "string" + } + } + }, + "types": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "options": { + "type": "array", + "items": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "thumbnail": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "originalUrl": { + "type": "string", + "format": "uri" + }, + "requestUrl": { + "type": "string", + "format": "uri" + }, + "originalDimensions": { + "type": "object", + "properties": { + "width": { + "type": "integer", + "minimum": 0 + }, + "height": { + "type": "integer", + "minimum": 0 + } + } + } + }, + "required": [ + "originalDimensions" + ] + } + }, + "required": [ + "value" + ] + } + } + }, + "required": [ + "name", + "options" + ] + } + }, + "properties": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ] + } + } + }, + "required": [ + "availability", + "listingDetails", + "types", + "properties" + ] + } + }, + "required": [ + "id", + "name", + "price", + "currency", + "hidden", + "sanctioned", + "media", + "status" + ] + }, + "BusinessCatalogPage": { + "type": "object", + "properties": { + "next": { + "type": "string" + }, + "previous": { + "type": "string" + }, + "products": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BusinessProduct" + } + } + }, + "required": [ + "products" + ] + }, + "GetBusinessCatalogResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/BusinessCatalogPage" + } + }, + "required": [ + "success", + "data" + ] + }, + "CreateBusinessCatalogResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + } + }, + "required": [ + "success" + ] + } + }, + "required": [ + "success", + "data" + ] + }, + "SetBusinessCartEnabledResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + } + }, + "required": [ + "success" + ] + } + }, + "required": [ + "success", + "data" + ] + }, + "BusinessCartSettingRequest": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + }, + "required": [ + "enabled" + ], + "additionalProperties": false + }, + "GetBusinessProductResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/BusinessProduct" + } + }, + "required": [ + "success", + "data" + ] + }, + "CreateBusinessProductResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/BusinessProduct" + } + }, + "required": [ + "success", + "data" + ] + }, + "BusinessProductMutationRequest": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1, + "maxLength": 256 + }, + "description": { + "type": "string", + "maxLength": 4096 + }, + "currency": { + "type": "string", + "pattern": "^[A-Z]{3}$" + }, + "price": { + "type": "string", + "pattern": "^\\d{1,18}$" + }, + "salePrice": { + "type": "string", + "pattern": "^\\d{1,18}$" + }, + "url": { + "type": "string", + "maxLength": 2048, + "format": "uri" + }, + "retailerId": { + "type": "string", + "maxLength": 256 + }, + "hidden": { + "type": "boolean" + }, + "images": { + "type": "array", + "items": { + "type": "object", + "properties": { + "url": { + "type": "string", + "maxLength": 4096, + "format": "uri", + "description": "HTTPS image source fetched through Polymorfa's SSRF-safe downloader" + }, + "base64": { + "type": "string", + "minLength": 1, + "maxLength": 22369624 + }, + "mediaUrl": { + "type": "string", + "maxLength": 4096, + "format": "uri", + "description": "Already-uploaded WhatsApp or Meta media URL reused without downloading" + } + }, + "additionalProperties": false + }, + "minItems": 1, + "maxItems": 10 + }, + "videoUrls": { + "type": "array", + "items": { + "type": "string", + "maxLength": 4096, + "format": "uri" + }, + "maxItems": 10 + }, + "complianceCategory": { + "type": "string", + "maxLength": 128 + }, + "compliance": { + "type": "object", + "properties": { + "countryCodeOrigin": { + "type": "string", + "maxLength": 3 + }, + "importerName": { + "type": "string", + "maxLength": 256 + }, + "importerAddress": { + "type": "object", + "properties": { + "street1": { + "type": "string", + "maxLength": 512 + }, + "street2": { + "type": "string", + "maxLength": 512 + }, + "city": { + "type": "string", + "maxLength": 256 + }, + "region": { + "type": "string", + "maxLength": 256 + }, + "postalCode": { + "type": "string", + "maxLength": 64 + }, + "countryCode": { + "type": "string", + "maxLength": 3 + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + "width": { + "type": "integer", + "minimum": 1, + "maximum": 1024 + }, + "height": { + "type": "integer", + "minimum": 1, + "maximum": 1024 + } + }, + "required": [ + "name", + "images" + ], + "additionalProperties": false + }, + "UpdateBusinessProductResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/BusinessProduct" + } + }, + "required": [ + "success", + "data" + ] + }, + "DeleteBusinessProductResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "type": "object", + "properties": { + "deletedCount": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "deletedCount" + ] + } + }, + "required": [ + "success", + "data" + ] + }, + "SetBusinessProductVisibilityResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + } + }, + "required": [ + "success" + ] + } + }, + "required": [ + "success", + "data" + ] + }, + "BusinessProductVisibilityRequest": { + "type": "object", + "properties": { + "hidden": { + "type": "boolean" + } + }, + "required": [ + "hidden" + ], + "additionalProperties": false + }, + "AppealBusinessProductResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + } + }, + "required": [ + "success" + ] + } + }, + "required": [ + "success", + "data" + ] + }, + "BusinessCatalogAppealRequest": { + "type": "object", + "properties": { + "reason": { + "type": "string", + "minLength": 1, + "maxLength": 4096 + } + }, + "required": [ + "reason" + ], + "additionalProperties": false + }, + "BusinessCollection": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "products": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BusinessProduct" + } + }, + "status": { + "type": "object", + "properties": { + "status": { + "type": "string" + }, + "canAppeal": { + "type": "boolean" + }, + "commerceUrl": { + "type": "string", + "format": "uri" + }, + "rejectReason": { + "type": "string" + } + }, + "required": [ + "canAppeal" + ] + } + }, + "required": [ + "id", + "name", + "products", + "status" + ] + }, + "BusinessCollectionPage": { + "type": "object", + "properties": { + "next": { + "type": "string" + }, + "collections": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BusinessCollection" + } + } + }, + "required": [ + "collections" + ] + }, + "GetBusinessCollectionsResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/BusinessCollectionPage" + } + }, + "required": [ + "success", + "data" + ] + }, + "CreateBusinessCollectionResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "reviewStatus": { + "type": "string" + } + }, + "required": [ + "id", + "reviewStatus" + ] + } + }, + "required": [ + "success", + "data" + ] + }, + "BusinessCollectionCreateRequest": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1, + "maxLength": 256 + }, + "productIds": { + "type": "array", + "items": { + "type": "string", + "minLength": 1, + "maxLength": 256 + }, + "minItems": 1, + "maxItems": 100 + } + }, + "required": [ + "name", + "productIds" + ], + "additionalProperties": false + }, + "GetBusinessCollectionResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/BusinessCollection" + } + }, + "required": [ + "success", + "data" + ] + }, + "ReorderBusinessCollectionsResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + } + }, + "required": [ + "success" + ] + } + }, + "required": [ + "success", + "data" + ] + }, + "BusinessCollectionReorderRequest": { + "type": "object", + "properties": { + "moves": { + "type": "array", + "items": { + "type": "object", + "properties": { + "collectionId": { + "type": "string", + "minLength": 1, + "maxLength": 256 + }, + "fromIndex": { + "type": "integer", + "minimum": 0, + "maximum": 99 + }, + "toIndex": { + "type": "integer", + "minimum": 0, + "maximum": 99 + } + }, + "required": [ + "collectionId", + "fromIndex", + "toIndex" + ], + "additionalProperties": false + }, + "minItems": 1, + "maxItems": 100 + } + }, + "required": [ + "moves" + ], + "additionalProperties": false + }, + "UpdateBusinessCollectionResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "reviewStatus": { + "type": "string" + } + }, + "required": [ + "id", + "reviewStatus" + ] + } + }, + "required": [ + "success", + "data" + ] + }, + "BusinessCollectionUpdateRequest": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1, + "maxLength": 256 + }, + "addProductIds": { + "type": "array", + "items": { + "type": "string", + "minLength": 1, + "maxLength": 256 + }, + "minItems": 0, + "maxItems": 100 + }, + "removeProductIds": { + "type": "array", + "items": { + "type": "string", + "minLength": 1, + "maxLength": 256 + }, + "minItems": 0, + "maxItems": 100 + } + }, + "additionalProperties": false + }, + "DeleteBusinessCollectionResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + } + }, + "required": [ + "success" + ] + } + }, + "required": [ + "success", + "data" + ] + }, + "AppealBusinessCollectionResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + } + }, + "required": [ + "success" + ] + } + }, + "required": [ + "success", + "data" + ] + }, + "BusinessOrder": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "createdAt": { + "type": "integer", + "minimum": 0 + }, + "catalogId": { + "type": "string" + }, + "price": { + "type": "object", + "properties": { + "subtotal": { + "type": "string" + }, + "total": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "priceStatus": { + "type": "string" + } + }, + "required": [ + "subtotal", + "total", + "currency" + ] + }, + "products": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "imageId": { + "type": "string" + }, + "imageUrl": { + "type": "string", + "format": "uri" + }, + "price": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "name": { + "type": "string" + }, + "quantity": { + "type": "integer", + "minimum": 0 + }, + "variantProperties": { + "type": "string" + } + }, + "required": [ + "id", + "price", + "currency", + "name", + "quantity" + ] + } + } + }, + "required": [ + "id", + "createdAt", + "price", + "products" + ] + }, + "GetBusinessOrderResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/BusinessOrder" + } + }, + "required": [ + "success", + "data" + ] + }, + "BusinessOrderLookupRequest": { + "type": "object", + "properties": { + "token": { + "type": "string", + "minLength": 1, + "maxLength": 8192 + } + }, + "required": [ + "token" + ] + }, + "ResolveLIDResult": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "lid": { + "type": "string", + "deprecated": true + }, + "phoneNumber": { + "type": "string" + }, + "username": { + "type": "string" + }, + "keyRequired": { + "type": "boolean" + } + } + }, + "ResolveLIDsResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/ResolveLIDResult" + } + }, + "required": [ + "success", + "data" + ] + }, + "UserSecurityCode": { + "type": "object", + "properties": { + "id": { + "type": "string", + "pattern": "^\\d+@lid$" + }, + "phoneNumber": { + "type": "string" + }, + "username": { + "type": "string" + }, + "numericCode": { + "type": "string", + "pattern": "^\\d{60}$" + }, + "qrCode": { + "type": "string" + } + }, + "required": [ + "id", + "numericCode", + "qrCode" + ] + }, + "UserSecurityCodeResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/UserSecurityCode" + } + }, + "required": [ + "success", + "data" + ] + }, + "Channel": { + "type": "object", + "properties": { + "lid": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "profileUrl": { + "type": "string" + }, + "followers": { + "type": "number" + }, + "muted": { + "type": "boolean" + }, + "preview": { + "type": "boolean" + } + } + }, + "ListChannelsResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Channel" + } + } + }, + "required": [ + "success", + "data" + ] + }, + "CreateChannelResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/Channel" + } + }, + "required": [ + "success", + "data" + ] + }, + "CreateChannelRequest": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1 + }, + "description": { + "type": "string" + }, + "picture": { + "type": "string" + } + }, + "required": [ + "name" + ] + }, + "GetChannelResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/Channel" + } + }, + "required": [ + "success", + "data" + ] + }, + "ChannelMessage": { + "type": "object", + "properties": { + "serverId": { + "type": "integer", + "minimum": 0, + "exclusiveMinimum": true + }, + "id": { + "type": "string" + }, + "type": { + "type": "string" + }, + "timestamp": { + "type": "string", + "format": "date-time" + }, + "views": { + "type": "integer", + "minimum": 0 + }, + "reactionCounts": { + "type": "object", + "additionalProperties": { + "type": "integer", + "minimum": 0 + } + }, + "text": { + "type": "string" + } + }, + "required": [ + "serverId", + "id", + "type", + "timestamp", + "views", + "reactionCounts" + ] + }, + "ListChannelMessagesResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ChannelMessage" + } + } + }, + "required": [ + "success", + "data" + ] + }, + "ListChannelMessageUpdatesResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ChannelMessage" + } + } + }, + "required": [ + "success", + "data" + ] + }, + "ChannelReactionRequest": { + "type": "object", + "properties": { + "reaction": { + "type": "string", + "maxLength": 32 + } + }, + "required": [ + "reaction" + ] + }, + "ChannelLiveUpdates": { + "type": "object", + "properties": { + "durationSeconds": { + "type": "integer", + "minimum": 0, + "exclusiveMinimum": true + } + }, + "required": [ + "durationSeconds" + ] + }, + "ChannelLiveUpdatesResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/ChannelLiveUpdates" + } + }, + "required": [ + "success", + "data" + ] + }, + "DeleteChannelResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "type": "object", + "properties": { + "status": { + "type": "string", + "enum": [ + "DELETED" + ] + } + }, + "required": [ + "status" + ] + } + }, + "required": [ + "success", + "data" + ] + }, + "AsyncAcceptedResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "type": "object", + "properties": { + "requestId": { + "type": "string", + "format": "uuid" + } + }, + "required": [ + "requestId" + ] + } + }, + "required": [ + "success", + "data" + ] + }, + "SetPresenceRequest": { + "type": "object", + "properties": { + "presence": { + "type": "string", + "enum": [ + "available", + "unavailable" + ] + } + }, + "required": [ + "presence" + ] + }, + "PresenceData": { + "type": "object", + "properties": { + "desired": { + "type": "string", + "enum": [ + "available", + "unavailable" + ] + }, + "desiredAt": { + "type": "string", + "format": "date-time" + }, + "lastSent": { + "type": "string", + "enum": [ + "available", + "unavailable" + ] + }, + "lastSentAt": { + "type": "string", + "format": "date-time" + }, + "authoritative": { + "type": "boolean", + "enum": [ + false + ] + } + }, + "required": [ + "authoritative" + ] + }, + "GetPresenceResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/PresenceData" + } + }, + "required": [ + "success", + "data" + ] + }, + "ChatPresenceData": { + "type": "object", + "properties": { + "policy": { + "type": "string", + "enum": [ + "off", + "events", + "cache" + ] + }, + "status": { + "type": "string", + "enum": [ + "unknown", + "fresh", + "stale" + ] + }, + "unknownReason": { + "type": "string", + "enum": [ + "disabled", + "not_observed", + "suspended" + ] + }, + "available": { + "type": "boolean" + }, + "lastSeen": { + "type": "string", + "format": "date-time" + }, + "observedAt": { + "type": "string", + "format": "date-time" + }, + "subscriptionExpiresAt": { + "type": "string", + "format": "date-time" + }, + "stale": { + "type": "boolean" + }, + "typingPolicy": { + "type": "string", + "enum": [ + "off", + "events", + "cache" + ] + }, + "typingStatus": { + "type": "string", + "enum": [ + "unknown", + "fresh", + "stale" + ] + }, + "typingUnknownReason": { + "type": "string", + "enum": [ + "disabled", + "not_observed", + "suspended" + ] + }, + "chatState": { + "type": "object", + "properties": { + "sender": { + "type": "string" + }, + "state": { + "type": "string", + "enum": [ + "composing", + "paused" + ] + }, + "media": { + "type": "string" + }, + "observedAt": { + "type": "string", + "format": "date-time" + }, + "stale": { + "type": "boolean" + } + }, + "required": [ + "sender", + "state", + "observedAt", + "stale" + ] + } + }, + "required": [ + "policy", + "status", + "stale", + "typingPolicy", + "typingStatus" + ] + }, + "GetChatPresenceResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/ChatPresenceData" + } + }, + "required": [ + "success", + "data" + ] + }, + "PresenceSubscriptionData": { + "type": "object", + "properties": { + "status": { + "type": "string", + "enum": [ + "SUBSCRIBED" + ] + }, + "expiresAt": { + "type": "string", + "format": "date-time" + } + }, + "required": [ + "status", + "expiresAt" + ] + }, + "SubscribePresenceResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/PresenceSubscriptionData" + } + }, + "required": [ + "success", + "data" + ] + }, + "ProjectSafeMode": { + "type": "object", + "properties": { + "projectId": { + "type": "string", + "format": "uuid" + }, + "ceiling": { + "type": "object", + "properties": { + "presence": { + "type": "string", + "enum": [ + "dark", + "online_while_sending", + "online_hours" + ] + }, + "typing": { + "type": "string", + "enum": [ + "off", + "before_text", + "before_all" + ] + }, + "reads": { + "type": "string", + "enum": [ + "off", + "replied_chats", + "all_inbound" + ] + }, + "pacing": { + "type": "string", + "enum": [ + "off", + "jittered", + "conversation" + ] + }, + "onlineStart": { + "type": "integer", + "minimum": 0, + "maximum": 23 + }, + "onlineEnd": { + "type": "integer", + "minimum": 0, + "maximum": 23 + } + }, + "required": [ + "presence", + "typing", + "reads", + "pacing", + "onlineStart", + "onlineEnd" + ] + }, + "entitled": { + "type": "boolean" + }, + "entitlementReason": { + "type": "string", + "nullable": true + } + }, + "required": [ + "projectId", + "ceiling", + "entitled", + "entitlementReason" + ] + }, + "GetProjectSafeModeResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/ProjectSafeMode" + } + }, + "required": [ + "success", + "data" + ] + }, + "UpdateProjectSafeModeResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/ProjectSafeMode" + } + }, + "required": [ + "success", + "data" + ] + }, + "SessionSafeMode": { + "type": "object", + "properties": { + "session": { + "type": "string" + }, + "projectId": { + "type": "string", + "format": "uuid" + }, + "project": { + "type": "object", + "properties": { + "presence": { + "type": "string", + "enum": [ + "dark", + "online_while_sending", + "online_hours" + ] + }, + "typing": { + "type": "string", + "enum": [ + "off", + "before_text", + "before_all" + ] + }, + "reads": { + "type": "string", + "enum": [ + "off", + "replied_chats", + "all_inbound" + ] + }, + "pacing": { + "type": "string", + "enum": [ + "off", + "jittered", + "conversation" + ] + }, + "onlineStart": { + "type": "integer", + "minimum": 0, + "maximum": 23 + }, + "onlineEnd": { + "type": "integer", + "minimum": 0, + "maximum": 23 + } + }, + "required": [ + "presence", + "typing", + "reads", + "pacing", + "onlineStart", + "onlineEnd" + ] + }, + "override": { + "type": "object", + "properties": { + "presence": { + "type": "string", + "enum": [ + "inherit", + "dark", + "online_while_sending", + "online_hours" + ] + }, + "typing": { + "type": "string", + "enum": [ + "inherit", + "off", + "before_text", + "before_all" + ] + }, + "reads": { + "type": "string", + "enum": [ + "inherit", + "off", + "replied_chats", + "all_inbound" + ] + }, + "pacing": { + "type": "string", + "enum": [ + "inherit", + "off", + "jittered", + "conversation" + ] + } + }, + "required": [ + "presence", + "typing", + "reads", + "pacing" + ] + }, + "effective": { + "type": "object", + "properties": { + "presence": { + "type": "string", + "enum": [ + "dark", + "online_while_sending", + "online_hours" + ] + }, + "typing": { + "type": "string", + "enum": [ + "off", + "before_text", + "before_all" + ] + }, + "reads": { + "type": "string", + "enum": [ + "off", + "replied_chats", + "all_inbound" + ] + }, + "pacing": { + "type": "string", + "enum": [ + "off", + "jittered", + "conversation" + ] + }, + "onlineStart": { + "type": "integer", + "minimum": 0, + "maximum": 23 + }, + "onlineEnd": { + "type": "integer", + "minimum": 0, + "maximum": 23 + } + }, + "required": [ + "presence", + "typing", + "reads", + "pacing", + "onlineStart", + "onlineEnd" + ] + }, + "applied": { + "type": "object", + "nullable": true, + "properties": { + "observedAt": { + "type": "string" + }, + "presence": { + "type": "string", + "nullable": true + }, + "typing": { + "type": "string", + "nullable": true + }, + "reads": { + "type": "string", + "nullable": true + }, + "pacing": { + "type": "string", + "nullable": true + } + }, + "required": [ + "observedAt", + "presence", + "typing", + "reads", + "pacing" + ] + }, + "mismatch": { + "type": "boolean" + }, + "entitled": { + "type": "boolean" + }, + "entitlementReason": { + "type": "string", + "nullable": true + } + }, + "required": [ + "session", + "projectId", + "project", + "override", + "effective", + "applied", + "mismatch", + "entitled", + "entitlementReason" + ] + }, + "GetSessionSafeModeResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/SessionSafeMode" + } + }, + "required": [ + "success", + "data" + ] + }, + "UpdateSessionSafeModeResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/SessionSafeMode" + } + }, + "required": [ + "success", + "data" + ] + }, + "ProjectWarmupPlan": { + "type": "object", + "properties": { + "projectId": { + "type": "string", + "format": "uuid" + }, + "plan": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "warmupDays": { + "type": "integer", + "minimum": 1, + "maximum": 90 + }, + "dailyStart": { + "type": "integer", + "minimum": 1, + "maximum": 2000 + } + }, + "required": [ + "enabled", + "warmupDays", + "dailyStart" + ] + }, + "ceiling": { + "type": "integer", + "minimum": 1 + }, + "curve": { + "type": "array", + "items": { + "type": "object", + "properties": { + "day": { + "type": "integer", + "minimum": 0 + }, + "allowance": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "day", + "allowance" + ] + }, + "maxItems": 91 + }, + "entitled": { + "type": "boolean" + }, + "entitlementReason": { + "type": "string", + "nullable": true + } + }, + "required": [ + "projectId", + "plan", + "ceiling", + "curve", + "entitled", + "entitlementReason" + ] + }, + "GetProjectWarmupPlanResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/ProjectWarmupPlan" + } + }, + "required": [ + "success", + "data" + ] + }, + "UpdateProjectWarmupPlanResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/ProjectWarmupPlan" + } + }, + "required": [ + "success", + "data" + ] + }, + "ProjectHealthPolicy": { + "type": "object", + "properties": { + "projectId": { + "type": "string", + "format": "uuid" + }, + "version": { + "type": "integer", + "minimum": 0 + }, + "enabled": { + "type": "boolean" + }, + "threshold": { + "type": "integer", + "minimum": 0, + "maximum": 100 + }, + "sessionAction": { + "type": "string", + "enum": [ + "none", + "stop", + "slow_down", + "log_out" + ] + }, + "slowDownMps": { + "type": "number", + "nullable": true, + "minimum": 0, + "exclusiveMinimum": true + }, + "emailNotification": { + "type": "boolean" + }, + "webhookNotification": { + "type": "boolean" + }, + "integrations": { + "type": "object", + "properties": { + "emailConfigured": { + "type": "boolean" + }, + "webhookConfigured": { + "type": "boolean" + } + }, + "required": [ + "emailConfigured", + "webhookConfigured" + ] + } + }, + "required": [ + "projectId", + "version", + "enabled", + "threshold", + "sessionAction", + "slowDownMps", + "emailNotification", + "webhookNotification", + "integrations" + ] + }, + "GetProjectHealthPolicyResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/ProjectHealthPolicy" + } + }, + "required": [ + "success", + "data" + ] + }, + "UpdateProjectHealthPolicyResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/ProjectHealthPolicy" + } + }, + "required": [ + "success", + "data" + ] + }, + "UpdateProjectHealthPolicyInput": { + "type": "object", + "properties": { + "version": { + "type": "integer", + "minimum": 0 + }, + "enabled": { + "type": "boolean" + }, + "threshold": { + "type": "integer", + "minimum": 0, + "maximum": 100 + }, + "sessionAction": { + "type": "string", + "enum": [ + "none", + "stop", + "slow_down", + "log_out" + ] + }, + "slowDownMps": { + "type": "number", + "nullable": true, + "minimum": 0, + "exclusiveMinimum": true + }, + "emailNotification": { + "type": "boolean" + }, + "webhookNotification": { + "type": "boolean" + } + }, + "required": [ + "version", + "enabled", + "threshold", + "sessionAction", + "slowDownMps", + "emailNotification", + "webhookNotification" + ], + "additionalProperties": false + }, + "ProjectInsuranceEvidence": { + "type": "object", + "properties": { + "projectId": { + "type": "string", + "format": "uuid" + }, + "enabled": { + "type": "boolean" + }, + "banInsuranceIncluded": { + "type": "boolean" + } + }, + "required": [ + "projectId", + "enabled", + "banInsuranceIncluded" + ] + }, + "GetProjectInsuranceEvidenceResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/ProjectInsuranceEvidence" + } + }, + "required": [ + "success", + "data" + ] + }, + "UpdateProjectInsuranceEvidenceResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/ProjectInsuranceEvidence" + } + }, + "required": [ + "success", + "data" + ] + }, + "ProjectObservationPolicy": { + "type": "object", + "properties": { + "projectId": { + "type": "string", + "format": "uuid" + }, + "presenceMode": { + "type": "string", + "enum": [ + "off", + "events", + "cache" + ] + }, + "typingMode": { + "type": "string", + "enum": [ + "off", + "events", + "cache" + ] + }, + "labelMode": { + "type": "string", + "enum": [ + "off", + "events", + "cache", + "project" + ] + }, + "quickReplyMode": { + "type": "string", + "enum": [ + "off", + "events", + "cache" + ] + } + }, + "required": [ + "projectId", + "presenceMode", + "typingMode", + "labelMode", + "quickReplyMode" + ] + }, + "GetProjectObservationPolicyResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/ProjectObservationPolicy" + } + }, + "required": [ + "success", + "data" + ] + }, + "UpdateProjectObservationPolicyResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/ProjectObservationPolicy" + } + }, + "required": [ + "success", + "data" + ] + }, + "SessionObservationPolicy": { + "type": "object", + "properties": { + "sessionName": { + "type": "string" + }, + "projectId": { + "type": "string", + "format": "uuid" + }, + "project": { + "type": "object", + "properties": { + "presenceMode": { + "type": "string", + "enum": [ + "off", + "events", + "cache" + ] + }, + "typingMode": { + "type": "string", + "enum": [ + "off", + "events", + "cache" + ] + }, + "labelMode": { + "type": "string", + "enum": [ + "off", + "events", + "cache", + "project" + ] + }, + "quickReplyMode": { + "type": "string", + "enum": [ + "off", + "events", + "cache" + ] + } + }, + "required": [ + "presenceMode", + "typingMode", + "labelMode", + "quickReplyMode" + ] + }, + "override": { + "type": "object", + "properties": { + "presenceMode": { + "type": "string", + "enum": [ + "inherit", + "off", + "events", + "cache" + ] + }, + "typingMode": { + "type": "string", + "enum": [ + "inherit", + "off", + "events", + "cache" + ] + }, + "labelMode": { + "type": "string", + "enum": [ + "inherit", + "off", + "events", + "cache", + "project" + ] + }, + "quickReplyMode": { + "type": "string", + "enum": [ + "inherit", + "off", + "events", + "cache" + ] + } + }, + "required": [ + "presenceMode", + "typingMode", + "labelMode", + "quickReplyMode" + ] + }, + "effective": { + "type": "object", + "properties": { + "presenceMode": { + "type": "string", + "enum": [ + "off", + "events", + "cache" + ] + }, + "typingMode": { + "type": "string", + "enum": [ + "off", + "events", + "cache" + ] + }, + "labelMode": { + "type": "string", + "enum": [ + "off", + "events", + "cache", + "project" + ] + }, + "quickReplyMode": { + "type": "string", + "enum": [ + "off", + "events", + "cache" + ] + } + }, + "required": [ + "presenceMode", + "typingMode", + "labelMode", + "quickReplyMode" + ] + } + }, + "required": [ + "sessionName", + "projectId", + "project", + "override", + "effective" + ] + }, + "GetSessionObservationPolicyResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/SessionObservationPolicy" + } + }, + "required": [ + "success", + "data" + ] + }, + "UpdateSessionObservationPolicyResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/SessionObservationPolicy" + } + }, + "required": [ + "success", + "data" + ] + }, + "ProfileData": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "status": { + "type": "string" + }, + "profilePicUrl": { + "type": "string" + } + }, + "required": [ + "name", + "status" + ] + }, + "GetProfileResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/ProfileData" + } + }, + "required": [ + "success", + "data" + ] + }, + "SetProfileNameRequest": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1 + } + }, + "required": [ + "name" + ] + }, + "SetProfileStatusRequest": { + "type": "object", + "properties": { + "status": { + "type": "string" + } + }, + "required": [ + "status" + ] + }, + "SetProfilePictureRequest": { + "type": "object", + "properties": { + "url": { + "type": "string" + }, + "base64": { + "type": "string" + } + } + }, + "PrivacySettings": { + "type": "object", + "properties": { + "groupAdd": { + "type": "string" + }, + "lastSeen": { + "type": "string" + }, + "status": { + "type": "string" + }, + "profile": { + "type": "string" + }, + "readReceipts": { + "type": "string" + }, + "online": { + "type": "string" + }, + "callAdd": { + "type": "string" + }, + "messages": { + "type": "string" + }, + "defense": { + "type": "string" + }, + "stickers": { + "type": "string" + } + }, + "required": [ + "groupAdd", + "lastSeen", + "status", + "profile", + "readReceipts", + "online", + "callAdd", + "messages", + "defense", + "stickers" + ] + }, + "PrivacySettingsResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/PrivacySettings" + } + }, + "required": [ + "success", + "data" + ] + }, + "DefaultDisappearingTimerRequest": { + "type": "object", + "properties": { + "durationSeconds": { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 86400 + ] + }, + { + "type": "number", + "enum": [ + 604800 + ] + }, + { + "type": "number", + "enum": [ + 7776000 + ] + } + ] + } + }, + "required": [ + "durationSeconds" + ] + }, + "UpdatedPrivacySettingsResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/PrivacySettings" + } + }, + "required": [ + "success", + "data" + ] + }, + "SetPrivacySettingRequest": { + "type": "object", + "properties": { + "value": { + "type": "string", + "enum": [ + "all", + "contacts", + "contact_allowlist", + "contact_blacklist", + "match_last_seen", + "known", + "none", + "on_standard", + "off" + ] + } + }, + "required": [ + "value" + ] + }, + "Label": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "color": { + "type": "integer" + }, + "orderIndex": { + "type": "integer" + }, + "chatCount": { + "type": "integer" + }, + "observedAt": { + "type": "string", + "format": "date-time" + } + }, + "required": [ + "id", + "name", + "color" + ] + }, + "LabelCollection": { + "type": "object", + "properties": { + "policy": { + "type": "string", + "enum": [ + "off", + "events", + "cache", + "project" + ] + }, + "status": { + "type": "string", + "enum": [ + "disabled", + "unknown", + "partial", + "fresh" + ] + }, + "unknownReason": { + "type": "string", + "enum": [ + "observation_disabled", + "not_retained", + "not_observed", + "expired" + ] + }, + "observedAt": { + "type": "string", + "format": "date-time" + }, + "expiresAt": { + "type": "string", + "format": "date-time" + }, + "labels": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Label" + } + } + }, + "required": [ + "policy", + "status", + "labels" + ] + }, + "LabelReadData": { + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/components/schemas/Label" + } + }, + { + "$ref": "#/components/schemas/LabelCollection" + } + ] + }, + "ListLabelsResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/LabelReadData" + } + }, + "required": [ + "success", + "data" + ] + }, + "CreateLabelResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/Label" + } + }, + "required": [ + "success", + "data" + ] + }, + "CreateLabelRequest": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1, + "maxLength": 100 + }, + "color": { + "type": "integer", + "minimum": 0, + "maximum": 19 + } + }, + "required": [ + "name" + ] + }, + "UpdateLabelRequest": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1, + "maxLength": 100 + }, + "color": { + "type": "integer", + "minimum": 0, + "maximum": 19 + } + } + }, + "GetChatLabelsResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/LabelReadData" + } + }, + "required": [ + "success", + "data" + ] + }, + "SetChatLabelsRequest": { + "type": "object", + "properties": { + "labels": { + "type": "array", + "items": { + "type": "string", + "minLength": 1, + "maxLength": 128 + }, + "maxItems": 20 + } + }, + "required": [ + "labels" + ] + }, + "RetryConfig": { + "type": "object", + "properties": { + "attempts": { + "type": "integer", + "minimum": 0 + }, + "delaySeconds": { + "type": "integer", + "minimum": 0 + }, + "policy": { + "type": "string", + "description": "linear, exponential, or constant" + } + }, + "required": [ + "attempts", + "delaySeconds", + "policy" + ] + }, + "WebhookHeader": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ] + }, + "Webhook": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "tenantId": { + "type": "string" + }, + "session": { + "type": "string" + }, + "url": { + "type": "string" + }, + "events": { + "type": "array", + "items": { + "type": "string" + } + }, + "retries": { + "$ref": "#/components/schemas/RetryConfig" + }, + "headers": { + "type": "array", + "items": { + "$ref": "#/components/schemas/WebhookHeader" + } + }, + "enabled": { + "type": "boolean" + }, + "format": { + "type": "string", + "enum": [ + "native", + "meta" + ] + }, + "createdAt": { + "type": "string" + } + }, + "required": [ + "id", + "tenantId", + "url", + "events", + "retries", + "headers", + "enabled", + "createdAt" + ] + }, + "ListWebhooksResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Webhook" + } + } + }, + "required": [ + "success", + "data" + ] + }, + "CreateWebhookResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/Webhook" + } + }, + "required": [ + "success", + "data" + ] + }, + "CreateWebhookRequest": { + "type": "object", + "properties": { + "session": { + "type": "string" + }, + "url": { + "type": "string", + "format": "uri" + }, + "events": { + "type": "array", + "items": { + "type": "string" + } + }, + "hmacKey": { + "type": "string" + }, + "retries": { + "$ref": "#/components/schemas/RetryConfig" + }, + "headers": { + "type": "array", + "items": { + "$ref": "#/components/schemas/WebhookHeader" + } + }, + "format": { + "type": "string", + "enum": [ + "native", + "meta" + ], + "description": "\"native\" (default) = Polymorfa event envelope. \"meta\" = Meta Cloud API webhook shape (object/entry/changes/value), signed with X-Hub-Signature-256." + } + }, + "required": [ + "url" + ] + }, + "GetWebhookResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/Webhook" + } + }, + "required": [ + "success", + "data" + ] + }, + "UpdateWebhookResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/Webhook" + } + }, + "required": [ + "success", + "data" + ] + }, + "UpdateWebhookRequest": { + "type": "object", + "properties": { + "url": { + "type": "string", + "format": "uri" + }, + "events": { + "type": "array", + "items": { + "type": "string" + } + }, + "hmacKey": { + "type": "string" + }, + "retries": { + "$ref": "#/components/schemas/RetryConfig" + }, + "headers": { + "type": "array", + "items": { + "$ref": "#/components/schemas/WebhookHeader" + } + }, + "enabled": { + "type": "boolean" + }, + "format": { + "type": "string", + "enum": [ + "native", + "meta" + ] + } + } + }, + "MediaInfo": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "session": { + "type": "string" + }, + "messageId": { + "type": "string" + }, + "mimeType": { + "type": "string" + }, + "fileLength": { + "type": "integer", + "minimum": 0 + }, + "persisted": { + "type": "boolean" + }, + "s3Url": { + "type": "string" + } + }, + "required": [ + "id", + "session", + "messageId", + "mimeType", + "fileLength", + "persisted" + ] + }, + "GetMediaInfoResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/MediaInfo" + } + }, + "required": [ + "success", + "data" + ] + }, + "MessageTemplate": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "category": { + "type": "string" + }, + "language": { + "type": "string" + }, + "status": { + "type": "string" + }, + "kind": { + "type": "string" + }, + "definition": { + "nullable": true + }, + "sampleValues": { + "nullable": true + }, + "cloudLinks": { + "type": "array", + "items": { + "nullable": true + } + }, + "createdAt": { + "type": "number" + }, + "updatedAt": { + "type": "number" + } + }, + "required": [ + "id", + "name", + "category", + "language", + "status", + "kind", + "cloudLinks", + "createdAt", + "updatedAt" + ] + }, + "ListProjectTemplatesResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MessageTemplate" + } + } + }, + "required": [ + "success", + "data" + ] + }, + "GetProjectTemplateResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/MessageTemplate" + } + }, + "required": [ + "success", + "data" + ] + }, + "CreateProjectTemplateResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/MessageTemplate" + } + }, + "required": [ + "success", + "data" + ] + }, + "CreateMessageTemplateRequest": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1, + "pattern": "^[a-z0-9_]+$" + }, + "definition": { + "type": "object", + "additionalProperties": { + "nullable": true + } + }, + "sampleValues": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + }, + "required": [ + "name", + "definition" + ] + }, + "UpdateProjectTemplateResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/MessageTemplate" + } + }, + "required": [ + "success", + "data" + ] + }, + "UpdateMessageTemplateRequest": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1 + }, + "status": { + "type": "string" + }, + "definition": { + "type": "object", + "additionalProperties": { + "nullable": true + } + }, + "sampleValues": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + }, + "PreviewProjectTemplateResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "type": "object", + "additionalProperties": { + "nullable": true + } + } + }, + "required": [ + "success", + "data" + ] + }, + "PreviewMessageTemplateRequest": { + "type": "object", + "properties": { + "values": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "surface": { + "type": "string", + "enum": [ + "cloud", + "whatsmeow", + "sandbox" + ] + } + } + }, + "SubmitProjectTemplateResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "type": "object", + "additionalProperties": { + "nullable": true + } + } + }, + "required": [ + "success", + "data" + ] + }, + "SubmitMessageTemplateRequest": { + "type": "object", + "properties": { + "session": { + "type": "string", + "minLength": 1 + } + }, + "required": [ + "session" + ] + }, + "Campaign": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "status": { + "type": "string" + }, + "templateId": { + "type": "string", + "nullable": true + }, + "recipientListId": { + "type": "string", + "nullable": true + }, + "recipientCount": { + "type": "number" + }, + "sentCount": { + "type": "number" + }, + "deliveredCount": { + "type": "number" + }, + "readCount": { + "type": "number" + }, + "failedCount": { + "type": "number" + }, + "skippedCount": { + "type": "number" + }, + "scheduledAt": { + "type": "number", + "nullable": true + }, + "launchedAt": { + "type": "number", + "nullable": true + }, + "completedAt": { + "type": "number", + "nullable": true + }, + "createdAt": { + "type": "number" + }, + "updatedAt": { + "type": "number" + } + }, + "required": [ + "id", + "name", + "status", + "templateId", + "recipientListId", + "recipientCount", + "sentCount", + "deliveredCount", + "readCount", + "failedCount", + "skippedCount", + "scheduledAt", + "launchedAt", + "completedAt", + "createdAt", + "updatedAt" + ] + }, + "ListCampaignsResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Campaign" + } + } + }, + "required": [ + "success", + "data" + ] + }, + "GetCampaignResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/Campaign" + } + }, + "required": [ + "success", + "data" + ] + }, + "CampaignAnalyticsResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "type": "object", + "additionalProperties": { + "nullable": true + } + } + }, + "required": [ + "success", + "data" + ] + }, + "CreateCampaignResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/Campaign" + } + }, + "required": [ + "success", + "data" + ] + }, + "CreateCampaignRequest": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1 + }, + "templateId": { + "type": "string" + }, + "recipientListId": { + "type": "string" + }, + "senderConfig": { + "type": "object", + "additionalProperties": { + "nullable": true + } + }, + "scheduledAt": { + "type": "number" + } + }, + "required": [ + "name" + ] + }, + "CampaignOperation": { + "allOf": [ + { + "$ref": "#/components/schemas/Campaign" + }, + { + "type": "object", + "properties": { + "operationId": { + "type": "string", + "format": "uuid" + } + }, + "required": [ + "operationId" + ] + } + ] + }, + "LaunchCampaignResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/CampaignOperation" + } + }, + "required": [ + "success", + "data" + ] + }, + "LaunchCampaignRequest": { + "type": "object", + "properties": { + "scheduledAt": { + "type": "number" + } + } + }, + "PauseCampaignResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/CampaignOperation" + } + }, + "required": [ + "success", + "data" + ] + }, + "ResumeCampaignResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/CampaignOperation" + } + }, + "required": [ + "success", + "data" + ] + }, + "StopCampaignResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/CampaignOperation" + } + }, + "required": [ + "success", + "data" + ] + }, + "RequeueCampaignResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "type": "object", + "additionalProperties": { + "nullable": true + } + } + }, + "required": [ + "success", + "data" + ] + }, + "RequeueCampaignRequest": { + "type": "object", + "properties": { + "includeSkippedError": { + "type": "boolean" + } + } + }, + "WidgetSessionResponse": { + "type": "object", + "properties": { + "widgetUrl": { + "type": "string" + }, + "redirectUrl": { + "type": "string" + }, + "clientToken": { + "type": "string" + }, + "session": { + "type": "string" + } + }, + "required": [ + "widgetUrl", + "redirectUrl", + "clientToken", + "session" + ] + }, + "WidgetSessionResponseWrapper": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/WidgetSessionResponse" + } + }, + "required": [ + "success", + "data" + ] + }, + "CreateWidgetSessionRequest": { + "type": "object", + "properties": { + "mode": { + "type": "string", + "enum": [ + "embedded", + "redirect" + ] + }, + "projectId": { + "type": "string", + "format": "uuid" + }, + "customerId": { + "type": "string", + "format": "uuid" + }, + "methods": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "qr", + "pairing", + "cloud-api" + ] + } + }, + "businessName": { + "type": "string", + "minLength": 1, + "maxLength": 120 + }, + "historySync": { + "type": "string", + "enum": [ + "force_on", + "force_off", + "ask" + ] + }, + "sessionName": { + "type": "string" + }, + "callbackUrl": { + "type": "string", + "maxLength": 2048, + "format": "uri", + "pattern": "^[Hh][Tt][Tt][Pp][Ss]://", + "description": "Exact HTTPS URL without credentials." + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string", + "maxLength": 2048, + "format": "uri", + "pattern": "^[Hh][Tt][Tt][Pp][Ss]://[^/?#@,]+/?$", + "description": "Exact HTTPS origin without credentials, path, query, fragment, or comma. A trailing root slash is removed." + }, + "maxItems": 50 + }, + "theme": { + "type": "string", + "enum": [ + "light", + "dark", + "system" + ] + }, + "accent": { + "type": "string", + "pattern": "^#[0-9a-fA-F]{6}$" + }, + "prefillPhone": { + "type": "string", + "pattern": "^\\+?\\d{6,15}$" + }, + "autoSubmitPhone": { + "type": "boolean" + }, + "analytics": { + "type": "object", + "properties": { + "posthogKey": { + "type": "string" + }, + "posthogHost": { + "type": "string" + } + }, + "required": [ + "posthogKey" + ] + }, + "metaApp": { + "type": "object", + "properties": { + "appId": { + "type": "string", + "minLength": 1 + }, + "appSecret": { + "type": "string", + "minLength": 1 + } + }, + "required": [ + "appId", + "appSecret" + ] + } + } + }, + "WidgetHandoffResponse": { + "type": "object", + "properties": { + "handoffUrl": { + "type": "string" + }, + "metaQrSvg": { + "type": "string" + }, + "expiresAt": { + "type": "string" + } + }, + "required": [ + "handoffUrl", + "metaQrSvg", + "expiresAt" + ] + }, + "WidgetHandoffState": { + "type": "object", + "properties": { + "qr": { + "type": "string", + "nullable": true + }, + "status": { + "type": "string" + }, + "sessionName": { + "type": "string" + }, + "businessName": { + "type": "string" + } + }, + "required": [ + "qr", + "status", + "sessionName" + ] + } + }, + "securitySchemes": { + "BearerAuth": { + "type": "http", + "scheme": "bearer", + "description": "Polymorfa API key (pmfa_ prefix) or client token (pmfa_ct_ prefix)." + } + } + }, + "paths": { + "/ping": { + "get": { + "operationId": "ping", + "tags": [ + "Health" + ], + "summary": "Liveness probe", + "security": [], + "responses": { + "200": { + "description": "Pong", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PingResponse" + } + } + } + } + } + } + }, + "/health": { + "get": { + "operationId": "getHealth", + "tags": [ + "Health" + ], + "summary": "Full service health check", + "security": [], + "responses": { + "200": { + "description": "All services healthy", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HealthResponse" + } + } + } + }, + "503": { + "description": "One or more services unhealthy or draining", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HealthResponse" + } + } + } + } + } + } + }, + "/api/info/version": { + "get": { + "operationId": "getVersion", + "tags": [ + "Info" + ], + "summary": "Get API version info", + "security": [], + "responses": { + "200": { + "description": "Version info", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VersionResponse" + } + } + } + } + } + } + }, + "/api/info/status": { + "get": { + "operationId": "getStatus", + "tags": [ + "Info" + ], + "summary": "Get API runtime status", + "security": [], + "responses": { + "200": { + "description": "Status info", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StatusResponse" + } + } + } + } + } + } + }, + "/v1/bridge/route": { + "get": { + "operationId": "getBridgeRoute", + "x-required-scope": "bridge:connect", + "tags": [ + "Bridge" + ], + "summary": "Verify a project token, resolve live project authority, and return the regional WSS endpoint.", + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "wsUrl": { + "type": "string", + "format": "uri" + }, + "region": { + "type": "string", + "enum": [ + "BR", + "US", + "IN", + "Auto" + ] + }, + "kind": { + "type": "string", + "enum": [ + "sandbox", + "production" + ] + }, + "signal": { + "type": "string", + "enum": [ + "customer", + "bartender" + ] + }, + "tokenKind": { + "type": "string", + "enum": [ + "project" + ] + }, + "expiresAt": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "wsUrl", + "region", + "kind", + "signal", + "tokenKind", + "expiresAt" + ] + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "error": { + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "error", + "message" + ] + } + } + } + }, + "503": { + "description": "Service unavailable", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "error": { + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "error", + "message" + ] + } + } + } + } + }, + "x-mint": { + "content": "bridge:connect" + }, + "description": "**Required scope:** `bridge:connect`" + } + }, + "/api/client-tokens": { + "post": { + "operationId": "mintClientToken", + "tags": [ + "Client Tokens" + ], + "summary": "Mint a short-lived browser-safe client token", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "sessions:manage", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MintClientTokenRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Token minted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MintClientTokenResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "sessions:manage" + }, + "description": "**Required scope:** `sessions:manage`" + } + }, + "/api/sessions/{session}/client-rules": { + "get": { + "operationId": "getClientRules", + "tags": [ + "Client Tokens" + ], + "summary": "Get client-token rules for a session", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "sessions:manage", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Client rules", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetClientRulesResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "sessions:manage" + }, + "description": "**Required scope:** `sessions:manage`" + }, + "put": { + "operationId": "setClientRules", + "tags": [ + "Client Tokens" + ], + "summary": "Set client-token rules for a session", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "sessions:manage", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SetClientRulesRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Rules saved", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "sessions:manage" + }, + "description": "**Required scope:** `sessions:manage`" + }, + "delete": { + "operationId": "deleteClientRules", + "tags": [ + "Client Tokens" + ], + "summary": "Delete client-token rules for a session", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "sessions:manage", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Rules deleted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "sessions:manage" + }, + "description": "**Required scope:** `sessions:manage`" + } + }, + "/api/operations/{operation}": { + "get": { + "operationId": "getOperation", + "tags": [ + "Operations" + ], + "summary": "Get a durable operation", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scopes": [ + "sessions:read", + "campaigns:read", + "webhooks:manage" + ], + "x-required-scope-mode": "any", + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid" + }, + "required": true, + "name": "operation", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Operation state", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/Operation" + } + }, + "required": [ + "success", + "data" + ] + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "sessions:read campaigns:read webhooks:manage" + }, + "description": "**Required scopes (any):** `sessions:read` · `campaigns:read` · `webhooks:manage`" + } + }, + "/api/sessions": { + "get": { + "operationId": "listSessions", + "tags": [ + "Sessions" + ], + "summary": "List all sessions for the tenant", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "sessions:read", + "responses": { + "200": { + "description": "Session list", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListSessionsResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "sessions:read" + }, + "description": "**Required scope:** `sessions:read`" + }, + "post": { + "operationId": "createSession", + "tags": [ + "Sessions" + ], + "summary": "Create a new session", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "sessions:manage", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateSessionRequest" + } + } + } + }, + "responses": { + "201": { + "description": "Session created; a testing session is connected and command-ready before this response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateSessionResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "409": { + "description": "Session with this name already exists", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "sessions:manage" + }, + "description": "**Required scope:** `sessions:manage`" + } + }, + "/api/sessions/{session}": { + "get": { + "operationId": "getSession", + "tags": [ + "Sessions" + ], + "summary": "Get session details", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "sessions:read", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Session details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetSessionResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "sessions:read" + }, + "description": "**Required scope:** `sessions:read`" + }, + "put": { + "operationId": "updateSession", + "tags": [ + "Sessions" + ], + "summary": "Update session configuration", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "sessions:manage", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateSessionRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Session updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateSessionResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "503": { + "description": "Session configuration was stored but the connected runner did not acknowledge it", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "sessions:manage" + }, + "description": "**Required scope:** `sessions:manage`" + }, + "delete": { + "operationId": "deleteSession", + "tags": [ + "Sessions" + ], + "summary": "Delete a session", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "sessions:manage", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Testing session deleted immediately after its simulated runtime closes", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OperationAccepted" + } + } + } + }, + "202": { + "description": "Session deletion scheduled", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OperationAccepted" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "sessions:manage" + }, + "description": "**Required scope:** `sessions:manage`" + } + }, + "/api/sessions/{session}/start": { + "post": { + "operationId": "startSession", + "tags": [ + "Sessions" + ], + "summary": "Start a session (connect to WhatsApp)", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "sessions:manage", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + } + ], + "responses": { + "202": { + "description": "Testing-session state changed immediately, or production-session start scheduled", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OperationAccepted" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "sessions:manage" + }, + "description": "**Required scope:** `sessions:manage`" + } + }, + "/api/sessions/{session}/stop": { + "post": { + "operationId": "stopSession", + "tags": [ + "Sessions" + ], + "summary": "Stop a session", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "sessions:manage", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + } + ], + "responses": { + "202": { + "description": "Testing session stopped after backend teardown, or production-session stop scheduled", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OperationAccepted" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "sessions:manage" + }, + "description": "**Required scope:** `sessions:manage`" + } + }, + "/api/sessions/{session}/restart": { + "post": { + "operationId": "restartSession", + "tags": [ + "Sessions" + ], + "summary": "Restart a session", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "sessions:manage", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + } + ], + "responses": { + "202": { + "description": "Testing session reconnected and ready, or production-session restart scheduled", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OperationAccepted" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "sessions:manage" + }, + "description": "**Required scope:** `sessions:manage`" + } + }, + "/api/sessions/{session}/logout": { + "post": { + "operationId": "logoutSession", + "tags": [ + "Sessions" + ], + "summary": "Log the session out of WhatsApp", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "sessions:manage", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + } + ], + "responses": { + "202": { + "description": "Session logout scheduled", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OperationAccepted" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "sessions:manage" + }, + "description": "**Required scope:** `sessions:manage`" + } + }, + "/api/sessions/{session}/me": { + "get": { + "operationId": "getSessionAccount", + "tags": [ + "Sessions" + ], + "summary": "Get the connected WhatsApp account info", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "sessions:read", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Account info", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetSessionAccountResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "sessions:read" + }, + "description": "**Required scope:** `sessions:read`" + } + }, + "/api/sessions/{session}/handoff-keys": { + "post": { + "operationId": "sessionHandoffKeys", + "tags": [ + "Sessions" + ], + "summary": "Initiate M↔P toggle: fetch the destination Curve25519 pubkey", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "sessions:manage", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Destination pubkey + correlation id for the handoff", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HandoffKeysSuccess" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "sessions:manage" + }, + "description": "**Required scope:** `sessions:manage`" + } + }, + "/api/sessions/{session}/handoff-import": { + "post": { + "operationId": "sessionHandoffImport", + "tags": [ + "Sessions" + ], + "summary": "Ship a sealed SignalStoreSnapshot from customer Baileys to the runner", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "sessions:manage", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HandoffImportRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Import accepted; bartenderMode will flip after the runner acks", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HandoffImportSuccess" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "sessions:manage" + }, + "description": "**Required scope:** `sessions:manage`" + } + }, + "/api/sessions/{session}/upload-appstate-keys": { + "post": { + "operationId": "sessionUploadAppStateKeys", + "tags": [ + "Sessions" + ], + "summary": "Upload selected AppStateSyncKeys (Track P+ tier)", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "sessions:manage", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UploadAppStateKeysRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Keys persisted; mode may have been flipped per upgradeTo", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UploadAppStateKeysSuccess" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "sessions:manage" + }, + "description": "**Required scope:** `sessions:manage`" + } + }, + "/api/sessions/{session}/handoff-ack": { + "post": { + "operationId": "sessionHandoffAck", + "tags": [ + "Sessions" + ], + "summary": "Acknowledge receipt of an M→P export; API flips bartenderMode after hash verify", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "sessions:manage", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HandoffAckRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Ack accepted; bartenderMode flipped from magic → passthrough", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HandoffAckSuccess" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "sessions:manage" + }, + "description": "**Required scope:** `sessions:manage`" + } + }, + "/api/{session}/pair/qr": { + "get": { + "operationId": "getQRCode", + "tags": [ + "Pairing" + ], + "summary": "Get QR code for device pairing", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "sessions:manage", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string", + "enum": [ + "json", + "image" + ], + "default": "json" + }, + "required": false, + "name": "format", + "in": "query" + } + ], + "responses": { + "200": { + "description": "QR code data", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetQRCodeResponse" + } + }, + "image/png": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API sessions:manage" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `sessions:manage`" + } + }, + "/api/{session}/pair/code": { + "post": { + "operationId": "requestPairCode", + "tags": [ + "Pairing" + ], + "summary": "Request a pairing code for a phone number", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "sessions:manage", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PairCodeRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Pairing code issued", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RequestPairCodeResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API sessions:manage" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `sessions:manage`" + } + }, + "/api/{session}/messages/send": { + "post": { + "operationId": "sendMessage", + "tags": [ + "Messages" + ], + "summary": "Send a message", + "description": "**Protocols:** Linked Device API · Meta Cloud API · Polymorfa Hybrid Link\n\n**Required scope:** `messages:write`\n\nTesting sessions accept a recipient testing number in E.164 format or as a phone-number JID, and can send only to active testing numbers in the same project. Malformed, unknown, stopped, deleted, and cross-project testing recipients all return 404 without creating recipient state.", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "messages:write", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SendMessageRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Message sent successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SendMessageResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API Meta Cloud API Polymorfa Hybrid Link messages:write" + }, + "x-protocols": [ + "Linked Device API", + "Meta Cloud API", + "Polymorfa Hybrid Link" + ] + } + }, + "/api/{session}/messages/seen": { + "post": { + "operationId": "sendSeen", + "tags": [ + "Messages" + ], + "summary": "Mark messages as seen", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "messages:write", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SeenRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Seen marker queued", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API Meta Cloud API Polymorfa Hybrid Link messages:write" + }, + "x-protocols": [ + "Linked Device API", + "Meta Cloud API", + "Polymorfa Hybrid Link" + ], + "description": "**Protocols:** Linked Device API · Meta Cloud API · Polymorfa Hybrid Link\n\n**Required scope:** `messages:write`" + } + }, + "/api/{session}/messages/typing": { + "post": { + "operationId": "setTyping", + "tags": [ + "Messages" + ], + "summary": "Set typing indicator for a chat", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "messages:write", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TypingRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Typing state queued", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API messages:write" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `messages:write`" + } + }, + "/api/{session}/messages/react": { + "post": { + "operationId": "sendReaction", + "tags": [ + "Messages" + ], + "summary": "React to a message", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "messages:write", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ReactRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Reaction sent", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SendReactionResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API Meta Cloud API Polymorfa Hybrid Link messages:write" + }, + "x-protocols": [ + "Linked Device API", + "Meta Cloud API", + "Polymorfa Hybrid Link" + ], + "description": "**Protocols:** Linked Device API · Meta Cloud API · Polymorfa Hybrid Link\n\n**Required scope:** `messages:write`" + } + }, + "/api/{session}/messages/star": { + "post": { + "operationId": "starMessage", + "tags": [ + "Messages" + ], + "summary": "Star or unstar a message", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "messages:write", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StarRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Star status updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StarMessageResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API messages:write" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `messages:write`" + } + }, + "/api/{session}/chats/{chatId}/messages/{messageId}": { + "put": { + "operationId": "editMessage", + "tags": [ + "Chats" + ], + "summary": "Edit a previously sent message", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "chats:manage", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "chatId", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "messageId", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EditMessageRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Message edited", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API chats:manage" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `chats:manage`" + }, + "delete": { + "operationId": "deleteMessage", + "tags": [ + "Chats" + ], + "summary": "Delete a previously sent message", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "chats:manage", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "chatId", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "messageId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Message deleted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API chats:manage" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `chats:manage`" + } + }, + "/api/{session}/chats/{chatId}/archive": { + "post": { + "operationId": "archiveChat", + "tags": [ + "Chats" + ], + "summary": "Archive a chat", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "chats:manage", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "chatId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Chat archived", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API chats:manage" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `chats:manage`" + } + }, + "/api/{session}/chats/{chatId}/unarchive": { + "post": { + "operationId": "unarchiveChat", + "tags": [ + "Chats" + ], + "summary": "Unarchive a chat", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "chats:manage", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "chatId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Chat unarchived", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API chats:manage" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `chats:manage`" + } + }, + "/api/{session}/chats/{chatId}/disappearing": { + "put": { + "operationId": "setChatDisappearingTimer", + "tags": [ + "Chats" + ], + "summary": "Set the disappearing-message timer for a chat", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "chats:manage", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "chatId", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DisappearingTimerRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Disappearing-message timer updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API chats:manage" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `chats:manage`" + } + }, + "/api/{session}/calls/{callId}/reject": { + "post": { + "operationId": "rejectCall", + "tags": [ + "Calls" + ], + "summary": "Reject an incoming WhatsApp call", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "chats:manage", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 128 + }, + "required": true, + "name": "callId", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RejectCallRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Call rejected", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API chats:manage" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `chats:manage`" + } + }, + "/api/{session}/groups": { + "get": { + "operationId": "listGroups", + "tags": [ + "Groups" + ], + "summary": "List groups the session is a member of", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "groups:read", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Group list", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListGroupsResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API groups:read" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `groups:read`" + }, + "post": { + "operationId": "createGroup", + "tags": [ + "Groups" + ], + "summary": "Create a new group", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "groups:manage", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateGroupRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Group created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateGroupResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API groups:manage" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `groups:manage`" + } + }, + "/api/{session}/groups/join-info": { + "get": { + "operationId": "getGroupJoinInfo", + "tags": [ + "Groups" + ], + "summary": "Look up group info for an invite code", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "groups:read", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1 + }, + "required": true, + "name": "code", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Join info", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetGroupJoinInfoResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API groups:read" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `groups:read`" + } + }, + "/api/{session}/groups/join": { + "post": { + "operationId": "joinGroup", + "tags": [ + "Groups" + ], + "summary": "Join a group by invite code", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "groups:manage", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/JoinGroupRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Joined group", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API groups:manage" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `groups:manage`" + } + }, + "/api/{session}/groups/{id}": { + "get": { + "operationId": "getGroup", + "tags": [ + "Groups" + ], + "summary": "Get group details", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "groups:read", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Group details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetGroupResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API groups:read" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `groups:read`" + }, + "delete": { + "operationId": "deleteGroup", + "tags": [ + "Groups" + ], + "summary": "Leave a group (DELETE alias)", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "groups:manage", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Left group", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API groups:manage" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `groups:manage`" + } + }, + "/api/{session}/groups/{id}/leave": { + "post": { + "operationId": "leaveGroup", + "tags": [ + "Groups" + ], + "summary": "Leave a group", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "groups:manage", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Left group", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API groups:manage" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `groups:manage`" + } + }, + "/api/{session}/groups/{id}/subject": { + "put": { + "operationId": "setGroupSubject", + "tags": [ + "Groups" + ], + "summary": "Set group subject (name)", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "groups:manage", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SetGroupFieldRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Subject updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API groups:manage" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `groups:manage`" + } + }, + "/api/{session}/groups/{id}/description": { + "put": { + "operationId": "setGroupDescription", + "tags": [ + "Groups" + ], + "summary": "Set group description", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "groups:manage", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SetGroupFieldRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Description updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API groups:manage" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `groups:manage`" + } + }, + "/api/{session}/groups/{id}/invite-code": { + "get": { + "operationId": "getGroupInviteCode", + "tags": [ + "Groups" + ], + "summary": "Get the current group invite code", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "groups:read", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Invite code", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetGroupInviteCodeResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API groups:read" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `groups:read`" + } + }, + "/api/{session}/groups/{id}/invite-code/revoke": { + "post": { + "operationId": "revokeGroupInviteCode", + "tags": [ + "Groups" + ], + "summary": "Revoke the current invite code and generate a new one", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "groups:manage", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "New invite code", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RevokeGroupInviteCodeResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API groups:manage" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `groups:manage`" + } + }, + "/api/{session}/groups/{id}/participants": { + "get": { + "operationId": "getGroupParticipants", + "tags": [ + "Groups" + ], + "summary": "List group participants", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "groups:read", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Participant list", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetGroupParticipantsResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API groups:read" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `groups:read`" + } + }, + "/api/{session}/groups/{id}/participants/add": { + "post": { + "operationId": "addGroupParticipants", + "tags": [ + "Groups" + ], + "summary": "Add participants to a group", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "groups:manage", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GroupParticipantsRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Participants added", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API groups:manage" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `groups:manage`" + } + }, + "/api/{session}/groups/{id}/participants/remove": { + "post": { + "operationId": "removeGroupParticipants", + "tags": [ + "Groups" + ], + "summary": "Remove participants from a group", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "groups:manage", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GroupParticipantsRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Participants removed", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API groups:manage" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `groups:manage`" + } + }, + "/api/{session}/groups/{id}/admin/promote": { + "post": { + "operationId": "promoteGroupAdmin", + "tags": [ + "Groups" + ], + "summary": "Promote participants to admin", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "groups:manage", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GroupParticipantsRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Participants promoted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API groups:manage" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `groups:manage`" + } + }, + "/api/{session}/groups/{id}/admin/demote": { + "post": { + "operationId": "demoteGroupAdmin", + "tags": [ + "Groups" + ], + "summary": "Demote admin participants", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "groups:manage", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GroupParticipantsRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Participants demoted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API groups:manage" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `groups:manage`" + } + }, + "/api/{session}/groups/{id}/picture": { + "put": { + "operationId": "setGroupPicture", + "tags": [ + "Groups" + ], + "summary": "Set the group profile picture", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "groups:manage", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SetGroupPictureRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Picture updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API groups:manage" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `groups:manage`" + } + }, + "/api/{session}/groups/{id}/settings/info-edit": { + "put": { + "operationId": "setGroupInfoEditing", + "tags": [ + "Groups" + ], + "summary": "Choose who can edit group information", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "groups:manage", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GroupAdminOnlySettingRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Group information permission updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API groups:manage" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `groups:manage`" + } + }, + "/api/{session}/groups/{id}/settings/messages": { + "put": { + "operationId": "setGroupMessaging", + "tags": [ + "Groups" + ], + "summary": "Choose who can send group messages", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "groups:manage", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GroupAdminOnlySettingRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Group messaging permission updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API groups:manage" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `groups:manage`" + } + }, + "/api/{session}/groups/{id}/settings/member-add": { + "put": { + "operationId": "setGroupMemberAddMode", + "tags": [ + "Groups" + ], + "summary": "Choose who can add group members", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "groups:manage", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GroupMemberAddModeRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Group member-add mode updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API groups:manage" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `groups:manage`" + } + }, + "/api/{session}/groups/{id}/settings/join-approval": { + "put": { + "operationId": "setGroupJoinApproval", + "tags": [ + "Groups" + ], + "summary": "Require admin approval for invite-link joins", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "groups:manage", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GroupJoinApprovalRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Group join approval updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API groups:manage" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `groups:manage`" + } + }, + "/api/{session}/contacts": { + "get": { + "operationId": "listContacts", + "tags": [ + "Contacts" + ], + "summary": "List all contacts known to the session", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "contacts:read", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Contact list", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListContactsResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API contacts:read" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `contacts:read`" + } + }, + "/api/{session}/contacts/check": { + "get": { + "operationId": "checkContacts", + "tags": [ + "Contacts" + ], + "summary": "Check if phone numbers are registered on WhatsApp", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "contacts:read", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + }, + "required": true, + "name": "phone", + "in": "query", + "style": "form", + "explode": false + } + ], + "responses": { + "200": { + "description": "Contact check results", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CheckContactsResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API contacts:read" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `contacts:read`" + } + }, + "/api/{session}/contacts/blocked": { + "get": { + "operationId": "getBlocklist", + "tags": [ + "Contacts" + ], + "summary": "Get blocked contacts", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "contacts:read", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Blocked contacts", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetBlocklistResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API contacts:read" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `contacts:read`" + } + }, + "/api/{session}/contacts/{contactId}": { + "get": { + "operationId": "getContact", + "tags": [ + "Contacts" + ], + "summary": "Get a contact by stable user ID", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "contacts:read", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "contactId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Contact details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetContactResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API contacts:read" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `contacts:read`" + } + }, + "/api/{session}/contacts/{contactId}/picture": { + "get": { + "operationId": "getContactPicture", + "tags": [ + "Contacts" + ], + "summary": "Get a contact's profile picture URL", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "contacts:read", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "contactId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Profile picture URL", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetContactPictureResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API contacts:read" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `contacts:read`" + } + }, + "/api/{session}/contacts/{contactId}/info": { + "get": { + "operationId": "getUserInfo", + "tags": [ + "Contacts" + ], + "summary": "Get live WhatsApp user metadata", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "contacts:read", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "contactId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "User metadata", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetUserInfoResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API contacts:read" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `contacts:read`" + } + }, + "/api/{session}/contacts/{contactId}/devices": { + "get": { + "operationId": "getUserDevices", + "tags": [ + "Contacts" + ], + "summary": "Get a contact's linked devices", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "contacts:read", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "contactId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Linked-device JIDs", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetUserDevicesResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API contacts:read" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `contacts:read`" + } + }, + "/api/{session}/contacts/{contactId}/business-profile": { + "get": { + "operationId": "getBusinessProfile", + "tags": [ + "Contacts" + ], + "summary": "Get a WhatsApp business profile", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "contacts:read", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "contactId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Business profile", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetBusinessProfileResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API contacts:read" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `contacts:read`" + } + }, + "/api/{session}/contacts/{contactId}/block": { + "post": { + "operationId": "blockContact", + "tags": [ + "Contacts" + ], + "summary": "Block a contact", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "contacts:manage", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "contactId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Contact blocked", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API contacts:manage" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `contacts:manage`" + } + }, + "/api/{session}/contacts/{contactId}/unblock": { + "post": { + "operationId": "unblockContact", + "tags": [ + "Contacts" + ], + "summary": "Unblock a contact", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "contacts:manage", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "contactId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Contact unblocked", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API contacts:manage" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `contacts:manage`" + } + }, + "/api/{session}/business/linked-accounts": { + "get": { + "operationId": "getBusinessLinkedAccounts", + "tags": [ + "Business App" + ], + "summary": "Read live accounts linked to the connected WhatsApp Business App", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "business:read", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Live linked-account state", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetBusinessLinkedAccountsResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API business:read" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `business:read`" + } + }, + "/api/{session}/business/eligibility": { + "get": { + "operationId": "getBusinessEligibility", + "tags": [ + "Business App" + ], + "summary": "Read live feature eligibility for the connected WhatsApp Business App", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "business:read", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Live business feature eligibility", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetBusinessEligibilityResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API business:read" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `business:read`" + } + }, + "/api/{session}/business/profile": { + "get": { + "operationId": "getOwnBusinessProfile", + "tags": [ + "Business App" + ], + "summary": "Read the connected WhatsApp Business App profile", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "profile:read", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Live business profile", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetOwnBusinessProfileResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API profile:read" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:read`" + }, + "patch": { + "operationId": "updateBusinessProfile", + "tags": [ + "Business App" + ], + "summary": "Update the connected WhatsApp Business App profile", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "profile:write", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BusinessProfileUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Profile updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateBusinessProfileResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API profile:write" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:write`" + } + }, + "/api/{session}/business/profile/cover-photo": { + "put": { + "operationId": "setBusinessCoverPhoto", + "tags": [ + "Business App" + ], + "summary": "Set the connected WhatsApp Business App cover photo", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "profile:write", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BusinessCoverPhotoRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Cover photo set", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SetBusinessCoverPhotoResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API profile:write" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:write`" + } + }, + "/api/{session}/business/profile/cover-photo/{coverPhotoId}": { + "delete": { + "operationId": "deleteBusinessCoverPhoto", + "tags": [ + "Business App" + ], + "summary": "Delete the connected WhatsApp Business App cover photo", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "profile:write", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256 + }, + "required": true, + "name": "coverPhotoId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Cover photo removed", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeleteBusinessCoverPhotoResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API profile:write" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:write`" + } + }, + "/api/{session}/business/compliance": { + "get": { + "operationId": "getBusinessMerchantCompliance", + "tags": [ + "Business App" + ], + "summary": "Read merchant compliance details for the connected WhatsApp Business App account", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "profile:read", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Live merchant compliance details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetBusinessMerchantComplianceResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API profile:read" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:read`" + }, + "put": { + "operationId": "setBusinessMerchantCompliance", + "tags": [ + "Business App" + ], + "summary": "Replace merchant compliance details for the connected WhatsApp Business App account", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "profile:write", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BusinessMerchantCompliance" + } + } + } + }, + "responses": { + "200": { + "description": "Merchant compliance details updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SetBusinessMerchantComplianceResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API profile:write" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:write`" + } + }, + "/api/{session}/business/quick-replies": { + "post": { + "operationId": "createBusinessQuickReply", + "tags": [ + "Business App" + ], + "summary": "Create a WhatsApp Business App quick reply", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "profile:write", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BusinessQuickReplyMutation" + } + } + } + }, + "responses": { + "200": { + "description": "Quick reply created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateBusinessQuickReplyResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API profile:write" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:write`" + }, + "get": { + "operationId": "listBusinessQuickReplies", + "tags": [ + "Business App" + ], + "summary": "List remembered WhatsApp Business App quick replies", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "profile:read", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Best-effort quick reply list", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListBusinessQuickRepliesResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API profile:read" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:read`" + } + }, + "/api/{session}/business/quick-replies/{quickReplyId}": { + "put": { + "operationId": "setBusinessQuickReply", + "tags": [ + "Business App" + ], + "summary": "Replace a WhatsApp Business App quick reply", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "profile:write", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 20, + "pattern": "^[0-9]+$" + }, + "required": true, + "name": "quickReplyId", + "in": "path" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BusinessQuickReplyMutation" + } + } + } + }, + "responses": { + "200": { + "description": "Quick reply replaced", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SetBusinessQuickReplyResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API profile:write" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:write`" + }, + "delete": { + "operationId": "deleteBusinessQuickReply", + "tags": [ + "Business App" + ], + "summary": "Delete a WhatsApp Business App quick reply", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "profile:write", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 20, + "pattern": "^[0-9]+$" + }, + "required": true, + "name": "quickReplyId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Quick reply deleted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeleteBusinessQuickReplyResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API profile:write" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:write`" + } + }, + "/api/{session}/business/catalog": { + "get": { + "operationId": "getBusinessCatalog", + "tags": [ + "Business App" + ], + "summary": "Read a WhatsApp Business App catalog", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "business:read", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string", + "maxLength": 256, + "pattern": "^\\d{1,32}@(s\\.whatsapp\\.net|lid)$" + }, + "required": true, + "name": "jid", + "in": "query" + }, + { + "schema": { + "type": "string", + "maxLength": 2048 + }, + "required": false, + "name": "after", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100 + }, + "required": false, + "name": "limit", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 1024 + }, + "required": false, + "name": "width", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 1024 + }, + "required": false, + "name": "height", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Live catalog page", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetBusinessCatalogResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "502": { + "description": "Upstream WhatsApp request failed or its response could not be mapped", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API business:read" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `business:read`" + }, + "post": { + "operationId": "createBusinessCatalog", + "tags": [ + "Business App" + ], + "summary": "Create a catalog for the connected WhatsApp Business App account", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "profile:write", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Catalog created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateBusinessCatalogResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API profile:write" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:write`" + } + }, + "/api/{session}/business/catalog/cart": { + "patch": { + "operationId": "setBusinessCartEnabled", + "tags": [ + "Business App" + ], + "summary": "Enable or disable the connected WhatsApp Business App catalog cart", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "profile:write", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BusinessCartSettingRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Cart setting updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SetBusinessCartEnabledResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API profile:write" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:write`" + } + }, + "/api/{session}/business/products/{productId}": { + "get": { + "operationId": "getBusinessProduct", + "tags": [ + "Business App" + ], + "summary": "Read a WhatsApp Business App product", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "business:read", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string", + "maxLength": 256 + }, + "required": true, + "name": "productId", + "in": "path" + }, + { + "schema": { + "type": "string", + "maxLength": 256, + "pattern": "^\\d{1,32}@(s\\.whatsapp\\.net|lid)$" + }, + "required": true, + "name": "jid", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Live product", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetBusinessProductResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "502": { + "description": "Upstream WhatsApp request failed or its response could not be mapped", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API business:read" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `business:read`" + }, + "put": { + "operationId": "updateBusinessProduct", + "tags": [ + "Business App" + ], + "summary": "Replace a product in the connected WhatsApp Business App catalog", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "profile:write", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string", + "maxLength": 256 + }, + "required": true, + "name": "productId", + "in": "path" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BusinessProductMutationRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Product updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateBusinessProductResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API profile:write" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:write`" + }, + "delete": { + "operationId": "deleteBusinessProduct", + "tags": [ + "Business App" + ], + "summary": "Delete a product from the connected WhatsApp Business App catalog", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "profile:write", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string", + "maxLength": 256 + }, + "required": true, + "name": "productId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Product deleted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeleteBusinessProductResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API profile:write" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:write`" + } + }, + "/api/{session}/business/products": { + "post": { + "operationId": "createBusinessProduct", + "tags": [ + "Business App" + ], + "summary": "Create a product in the connected WhatsApp Business App catalog", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "profile:write", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BusinessProductMutationRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Product created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateBusinessProductResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API profile:write" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:write`" + } + }, + "/api/{session}/business/products/{productId}/visibility": { + "patch": { + "operationId": "setBusinessProductVisibility", + "tags": [ + "Business App" + ], + "summary": "Hide or show a product in the connected WhatsApp Business App catalog", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "profile:write", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string", + "maxLength": 256 + }, + "required": true, + "name": "productId", + "in": "path" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BusinessProductVisibilityRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Product visibility updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SetBusinessProductVisibilityResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API profile:write" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:write`" + } + }, + "/api/{session}/business/products/{productId}/appeal": { + "post": { + "operationId": "appealBusinessProduct", + "tags": [ + "Business App" + ], + "summary": "Request a review of a rejected WhatsApp Business App catalog product", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "profile:write", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string", + "maxLength": 256 + }, + "required": true, + "name": "productId", + "in": "path" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BusinessCatalogAppealRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Product appeal submitted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AppealBusinessProductResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API profile:write" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:write`" + } + }, + "/api/{session}/business/collections": { + "get": { + "operationId": "getBusinessCollections", + "tags": [ + "Business App" + ], + "summary": "Read WhatsApp Business App collections", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "business:read", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string", + "maxLength": 256, + "pattern": "^\\d{1,32}@(s\\.whatsapp\\.net|lid)$" + }, + "required": true, + "name": "jid", + "in": "query" + }, + { + "schema": { + "type": "string", + "maxLength": 2048 + }, + "required": false, + "name": "after", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 20 + }, + "required": false, + "name": "collectionLimit", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100 + }, + "required": false, + "name": "itemLimit", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 1024 + }, + "required": false, + "name": "width", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 1024 + }, + "required": false, + "name": "height", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Live collection page", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetBusinessCollectionsResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "502": { + "description": "Upstream WhatsApp request failed or its response could not be mapped", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API business:read" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `business:read`" + }, + "post": { + "operationId": "createBusinessCollection", + "tags": [ + "Business App" + ], + "summary": "Create a collection in the connected WhatsApp Business App catalog", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "profile:write", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BusinessCollectionCreateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Collection created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateBusinessCollectionResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API profile:write" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:write`" + } + }, + "/api/{session}/business/collections/{collectionId}": { + "get": { + "operationId": "getBusinessCollection", + "tags": [ + "Business App" + ], + "summary": "Read a WhatsApp Business App collection", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "business:read", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string", + "maxLength": 256 + }, + "required": true, + "name": "collectionId", + "in": "path" + }, + { + "schema": { + "type": "string", + "maxLength": 256, + "pattern": "^\\d{1,32}@(s\\.whatsapp\\.net|lid)$" + }, + "required": true, + "name": "jid", + "in": "query" + }, + { + "schema": { + "type": "string", + "maxLength": 2048 + }, + "required": false, + "name": "after", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100 + }, + "required": false, + "name": "limit", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 1024 + }, + "required": false, + "name": "width", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 1024 + }, + "required": false, + "name": "height", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Live collection", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetBusinessCollectionResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "502": { + "description": "Upstream WhatsApp request failed or its response could not be mapped", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API business:read" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `business:read`" + }, + "patch": { + "operationId": "updateBusinessCollection", + "tags": [ + "Business App" + ], + "summary": "Update a collection and its product membership", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "profile:write", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string", + "maxLength": 256 + }, + "required": true, + "name": "collectionId", + "in": "path" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BusinessCollectionUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Collection updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateBusinessCollectionResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API profile:write" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:write`" + }, + "delete": { + "operationId": "deleteBusinessCollection", + "tags": [ + "Business App" + ], + "summary": "Delete a collection from the connected WhatsApp Business App catalog", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "profile:write", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string", + "maxLength": 256 + }, + "required": true, + "name": "collectionId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Collection deleted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeleteBusinessCollectionResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API profile:write" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:write`" + } + }, + "/api/{session}/business/collections/reorder": { + "post": { + "operationId": "reorderBusinessCollections", + "tags": [ + "Business App" + ], + "summary": "Reorder connected WhatsApp Business App catalog collections", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "profile:write", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BusinessCollectionReorderRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Collections reordered", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ReorderBusinessCollectionsResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API profile:write" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:write`" + } + }, + "/api/{session}/business/collections/{collectionId}/appeal": { + "post": { + "operationId": "appealBusinessCollection", + "tags": [ + "Business App" + ], + "summary": "Request a review of a rejected WhatsApp Business App catalog collection", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "profile:write", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string", + "maxLength": 256 + }, + "required": true, + "name": "collectionId", + "in": "path" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BusinessCatalogAppealRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Collection appeal submitted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AppealBusinessCollectionResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API profile:write" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:write`" + } + }, + "/api/{session}/business/orders/{orderId}/lookup": { + "post": { + "operationId": "getBusinessOrder", + "tags": [ + "Business App" + ], + "summary": "Read WhatsApp Business App order details", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "business:read", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string", + "maxLength": 256 + }, + "required": true, + "name": "orderId", + "in": "path" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BusinessOrderLookupRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Order details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetBusinessOrderResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "502": { + "description": "Upstream WhatsApp request failed or its response could not be mapped", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API business:read" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `business:read`" + } + }, + "/api/{session}/lids/resolve": { + "get": { + "operationId": "resolveLIDs", + "tags": [ + "LIDs" + ], + "summary": "Resolve a user alias to a stable user ID", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "contacts:read", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": false, + "name": "phoneNumber", + "in": "query" + }, + { + "schema": { + "type": "string" + }, + "required": false, + "name": "id", + "in": "query" + }, + { + "schema": { + "type": "string" + }, + "required": false, + "name": "lid", + "in": "query", + "deprecated": true + }, + { + "schema": { + "type": "string", + "minLength": 3, + "maxLength": 35 + }, + "required": false, + "name": "username", + "in": "query" + }, + { + "schema": { + "type": "string", + "pattern": "^\\d{4}$" + }, + "required": false, + "name": "usernameKey", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Stable user ID and known aliases", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResolveLIDsResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API contacts:read" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `contacts:read`" + } + }, + "/api/{session}/users/{id}/security-code": { + "get": { + "operationId": "getUserSecurityCode", + "tags": [ + "Users" + ], + "summary": "Get an identity verification code for a user", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "contacts:read", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string", + "pattern": "^\\d+@lid$" + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Identity verification code and display QR", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserSecurityCodeResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API contacts:read" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `contacts:read`" + } + }, + "/api/{session}/channels": { + "get": { + "operationId": "listChannels", + "tags": [ + "Channels" + ], + "summary": "List channels the session follows", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "channels:read", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Channel list", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListChannelsResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API channels:read" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `channels:read`" + }, + "post": { + "operationId": "createChannel", + "tags": [ + "Channels" + ], + "summary": "Create a new channel", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "channels:manage", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateChannelRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Channel created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateChannelResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API channels:manage" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `channels:manage`" + } + }, + "/api/{session}/channels/{id}": { + "get": { + "operationId": "getChannel", + "tags": [ + "Channels" + ], + "summary": "Get channel details", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "channels:read", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Channel details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetChannelResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API channels:read" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `channels:read`" + }, + "delete": { + "operationId": "deleteChannel", + "tags": [ + "Channels" + ], + "summary": "Delete a channel", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "channels:manage", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Channel deleted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeleteChannelResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "502": { + "description": "Upstream WhatsApp request failed or its response could not be mapped", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API channels:manage" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `channels:manage`" + } + }, + "/api/{session}/channels/{id}/messages": { + "get": { + "operationId": "listChannelMessages", + "tags": [ + "Channels" + ], + "summary": "List channel messages", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "channels:read", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 50 + }, + "required": false, + "name": "count", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 0, + "exclusiveMinimum": true + }, + "required": false, + "name": "before", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Channel messages", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListChannelMessagesResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API channels:read" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `channels:read`" + } + }, + "/api/{session}/channels/{id}/message-updates": { + "get": { + "operationId": "listChannelMessageUpdates", + "tags": [ + "Channels" + ], + "summary": "List channel view and reaction updates", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "channels:read", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 50 + }, + "required": false, + "name": "count", + "in": "query" + }, + { + "schema": { + "type": "integer", + "nullable": true, + "minimum": 0 + }, + "required": false, + "name": "since", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 0, + "exclusiveMinimum": true + }, + "required": false, + "name": "after", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Channel message updates", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListChannelMessageUpdatesResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API channels:read" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `channels:read`" + } + }, + "/api/{session}/channels/{id}/messages/{serverId}/viewed": { + "post": { + "operationId": "markChannelMessageViewed", + "tags": [ + "Channels" + ], + "summary": "Mark a channel message as viewed", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "channels:manage", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "integer", + "minimum": 0, + "exclusiveMinimum": true + }, + "required": true, + "name": "serverId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Message marked viewed", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API channels:manage" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `channels:manage`" + } + }, + "/api/{session}/channels/{id}/messages/{serverId}/reaction": { + "post": { + "operationId": "reactToChannelMessage", + "tags": [ + "Channels" + ], + "summary": "React to a channel message", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "channels:manage", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "integer", + "minimum": 0, + "exclusiveMinimum": true + }, + "required": true, + "name": "serverId", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ChannelReactionRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Reaction updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API channels:manage" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `channels:manage`" + } + }, + "/api/{session}/channels/{id}/live-updates": { + "post": { + "operationId": "subscribeChannelLiveUpdates", + "tags": [ + "Channels" + ], + "summary": "Subscribe temporarily to channel live updates", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "channels:read", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Live-update subscription duration", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ChannelLiveUpdatesResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API channels:read" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `channels:read`" + } + }, + "/api/{session}/channels/{id}/follow": { + "post": { + "operationId": "followChannel", + "tags": [ + "Channels" + ], + "summary": "Follow a channel", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "channels:manage", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Channel followed", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API channels:manage" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `channels:manage`" + } + }, + "/api/{session}/channels/{id}/unfollow": { + "post": { + "operationId": "unfollowChannel", + "tags": [ + "Channels" + ], + "summary": "Unfollow a channel", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "channels:manage", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Channel unfollowed", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API channels:manage" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `channels:manage`" + } + }, + "/api/{session}/channels/{id}/mute": { + "post": { + "operationId": "muteChannel", + "tags": [ + "Channels" + ], + "summary": "Mute a channel", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "channels:manage", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Channel muted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API channels:manage" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `channels:manage`" + } + }, + "/api/{session}/channels/{id}/unmute": { + "post": { + "operationId": "unmuteChannel", + "tags": [ + "Channels" + ], + "summary": "Unmute a channel", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "channels:manage", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Channel unmuted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API channels:manage" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `channels:manage`" + } + }, + "/api/{session}/presence": { + "post": { + "operationId": "setPresence", + "tags": [ + "Presence" + ], + "summary": "Set the session's own presence (available / unavailable)", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "presence:write", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SetPresenceRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Presence updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "202": { + "description": "Accepted for asynchronous processing in response to `Prefer: respond-async`; the result is not included", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AsyncAcceptedResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API presence:write" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `presence:write`" + }, + "get": { + "operationId": "getPresence", + "tags": [ + "Presence" + ], + "summary": "Get the session's own presence", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "presence:read", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Presence info", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetPresenceResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API presence:read" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `presence:read`" + } + }, + "/api/{session}/presence/{chatId}": { + "get": { + "operationId": "getChatPresence", + "tags": [ + "Presence" + ], + "summary": "Get presence for a specific chat", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "presence:read", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "chatId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Chat presence", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetChatPresenceResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API presence:read" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `presence:read`" + } + }, + "/api/{session}/presence/{chatId}/subscribe": { + "post": { + "operationId": "subscribePresence", + "tags": [ + "Presence" + ], + "summary": "Subscribe to presence updates for a chat", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "presence:observe", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "chatId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Subscribed", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscribePresenceResponse" + } + } + } + }, + "202": { + "description": "Accepted for asynchronous processing in response to `Prefer: respond-async`; the result is not included", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AsyncAcceptedResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "429": { + "description": "Observation limit exceeded, or the session is inside the suspension window that follows", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API presence:observe" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `presence:observe`" + } + }, + "/api/projects/{projectId}/safe-mode": { + "get": { + "operationId": "getProjectSafeMode", + "tags": [ + "Safe Mode" + ], + "summary": "Get a project's Safe Mode ceiling", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "sessions:read", + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid" + }, + "required": true, + "name": "projectId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Project Safe Mode ceiling, and whether the plan includes BanSafe Lite", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetProjectSafeModeResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "sessions:read" + }, + "description": "**Required scope:** `sessions:read`" + }, + "put": { + "operationId": "updateProjectSafeMode", + "tags": [ + "Safe Mode" + ], + "summary": "Set a project's Safe Mode ceiling", + "description": "**Required scope:** `sessions:manage`\n\nSets the most visible behaviour any number in this project may use. Presence and read receipts are visible to the people this number messages: turning them on makes the number appear online, exposes last-seen subject to the account's privacy settings, and puts blue ticks on incoming messages. Every axis is off by default and only this request changes it.", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "sessions:manage", + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid" + }, + "required": true, + "name": "projectId", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "presence": { + "type": "string", + "enum": [ + "dark", + "online_while_sending", + "online_hours" + ] + }, + "typing": { + "type": "string", + "enum": [ + "off", + "before_text", + "before_all" + ] + }, + "reads": { + "type": "string", + "enum": [ + "off", + "replied_chats", + "all_inbound" + ] + }, + "pacing": { + "type": "string", + "enum": [ + "off", + "jittered", + "conversation" + ] + }, + "onlineStart": { + "type": "integer", + "minimum": 0, + "maximum": 23 + }, + "onlineEnd": { + "type": "integer", + "minimum": 0, + "maximum": 23 + } + }, + "additionalProperties": false + } + } + } + }, + "responses": { + "200": { + "description": "Project Safe Mode ceiling updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateProjectSafeModeResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "402": { + "description": "Safe Mode is part of BanSafe Lite, which is not included on this number's plan", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "503": { + "description": "Stored, but a connected number did not confirm the policy; retry the request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "sessions:manage" + } + } + }, + "/api/{session}/safe-mode": { + "get": { + "operationId": "getSessionSafeMode", + "tags": [ + "Safe Mode" + ], + "summary": "Get a number's effective Safe Mode", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "sessions:read", + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1 + }, + "required": true, + "name": "session", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Project ceiling, number override, the effective policy, and whether the plan includes BanSafe Lite", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetSessionSafeModeResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API sessions:read" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `sessions:read`" + }, + "put": { + "operationId": "updateSessionSafeMode", + "tags": [ + "Safe Mode" + ], + "summary": "Set a number's Safe Mode override", + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `sessions:manage`\n\nSets one number's Safe Mode. Each axis accepts `inherit` to follow the project ceiling. An override may only be equally or more conservative than the ceiling; a more visible value is refused with `safe_mode_exceeds_project_ceiling`.", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "sessions:manage", + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1 + }, + "required": true, + "name": "session", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "presence": { + "type": "string", + "enum": [ + "inherit", + "dark", + "online_while_sending", + "online_hours" + ] + }, + "typing": { + "type": "string", + "enum": [ + "inherit", + "off", + "before_text", + "before_all" + ] + }, + "reads": { + "type": "string", + "enum": [ + "inherit", + "off", + "replied_chats", + "all_inbound" + ] + }, + "pacing": { + "type": "string", + "enum": [ + "inherit", + "off", + "jittered", + "conversation" + ] + } + }, + "additionalProperties": false + } + } + } + }, + "responses": { + "200": { + "description": "Number Safe Mode override updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateSessionSafeModeResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "402": { + "description": "Safe Mode is part of BanSafe Lite, which is not included on this number's plan", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "503": { + "description": "Stored, but a connected number did not confirm the policy; retry the request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API sessions:manage" + }, + "x-protocols": [ + "Linked Device API" + ] + } + }, + "/api/projects/{projectId}/warmup-plan": { + "get": { + "operationId": "getProjectWarmupPlan", + "tags": [ + "Warm-up plan" + ], + "summary": "Get a project's warm-up plan", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "sessions:read", + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid" + }, + "required": true, + "name": "projectId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Project warm-up plan, its projected curve, and whether the plan includes BanSafe Lite", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetProjectWarmupPlanResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "sessions:read" + }, + "description": "**Required scope:** `sessions:read`" + }, + "put": { + "operationId": "updateProjectWarmupPlan", + "tags": [ + "Warm-up plan" + ], + "summary": "Set a project's warm-up plan", + "description": "**Required scope:** `sessions:manage`\n\nTurns the warm-up plan on or off for a project and sets how long the ramp takes and how many messages a number may send on its first day. While the plan is on, a send past a number's allowance is refused with `bansafe_daily_allowance_reached` and campaign recipients are deferred to the next reset.", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "sessions:manage", + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid" + }, + "required": true, + "name": "projectId", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "warmupDays": { + "type": "integer", + "minimum": 1, + "maximum": 90 + }, + "dailyStart": { + "type": "integer", + "minimum": 1, + "maximum": 2000 + } + }, + "additionalProperties": false + } + } + } + }, + "responses": { + "200": { + "description": "Project warm-up plan updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateProjectWarmupPlanResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "402": { + "description": "The warm-up plan is part of BanSafe Lite, which is not included on this project's plan", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "503": { + "description": "Stored, but a connected number did not confirm the plan; retry the request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "sessions:manage" + } + } + }, + "/api/projects/{projectId}/health-policy": { + "get": { + "operationId": "getProjectHealthPolicy", + "tags": [ + "BanSafe" + ], + "summary": "Get a project's health policy", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "sessions:read", + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid" + }, + "required": true, + "name": "projectId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Project health threshold and configured actions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetProjectHealthPolicyResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "sessions:read" + }, + "description": "**Required scope:** `sessions:read`" + }, + "put": { + "operationId": "updateProjectHealthPolicy", + "tags": [ + "BanSafe" + ], + "summary": "Set a project's health policy", + "description": "**Required scope:** `sessions:manage`\n\nReplaces the project policy when version matches the stored version. The rule triggers only when an available health estimate is below threshold. Stopping disconnects a session while retaining its linked credentials; logging out requires relinking.", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "sessions:manage", + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid" + }, + "required": true, + "name": "projectId", + "in": "path" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateProjectHealthPolicyInput" + } + } + } + }, + "responses": { + "200": { + "description": "Project health policy updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateProjectHealthPolicyResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "409": { + "description": "Version conflict or selected notification integration unavailable", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "error": { + "type": "string" + }, + "code": { + "type": "string" + } + }, + "required": [ + "error", + "code" + ] + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "sessions:manage" + } + } + }, + "/api/projects/{projectId}/insurance-evidence": { + "get": { + "operationId": "getProjectInsuranceEvidence", + "tags": [ + "Ban insurance" + ], + "summary": "Get ban insurance evidence setting", + "description": "**Required scope:** `sessions:read`\n\nBan insurance evidence lets Polymorfa measure what the other devices linked to a number do with it: how many messages they send, to how many people, how fast, and in which hours. Only counts are kept, never messages, contacts, or device names. With it off, a claim can still be filed, but Polymorfa cannot say whether another device caused the ban and a person decides the claim.", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "sessions:read", + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid" + }, + "required": true, + "name": "projectId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "The project's ban insurance evidence setting", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetProjectInsuranceEvidenceResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "sessions:read" + } + }, + "put": { + "operationId": "updateProjectInsuranceEvidence", + "tags": [ + "Ban insurance" + ], + "summary": "Set ban insurance evidence setting", + "description": "**Required scope:** `sessions:manage`\n\nBan insurance evidence lets Polymorfa measure what the other devices linked to a number do with it: how many messages they send, to how many people, how fast, and in which hours. Only counts are kept, never messages, contacts, or device names. With it off, a claim can still be filed, but Polymorfa cannot say whether another device caused the ban and a person decides the claim.", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "sessions:manage", + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid" + }, + "required": true, + "name": "projectId", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + }, + "required": [ + "enabled" + ], + "additionalProperties": false + } + } + } + }, + "responses": { + "200": { + "description": "The project's ban insurance evidence setting was updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateProjectInsuranceEvidenceResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "503": { + "description": "Stored, but a connected number did not confirm the change; retry the request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "sessions:manage" + } + } + }, + "/api/projects/{projectId}/observation-policy": { + "get": { + "operationId": "getProjectObservationPolicy", + "tags": [ + "Presence", + "Labels", + "Business App" + ], + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "presence:read", + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid" + }, + "required": true, + "name": "projectId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Project observation ceiling", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetProjectObservationPolicyResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "presence:read" + }, + "description": "**Required scope:** `presence:read`" + }, + "put": { + "operationId": "updateProjectObservationPolicy", + "tags": [ + "Presence", + "Labels", + "Business App" + ], + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "presence:observe", + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid" + }, + "required": true, + "name": "projectId", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "presenceMode": { + "type": "string", + "enum": [ + "off", + "events", + "cache" + ] + }, + "typingMode": { + "type": "string", + "enum": [ + "off", + "events", + "cache" + ] + }, + "labelMode": { + "type": "string", + "enum": [ + "off", + "events", + "cache", + "project" + ] + }, + "quickReplyMode": { + "type": "string", + "enum": [ + "off", + "events", + "cache" + ] + } + }, + "required": [ + "presenceMode", + "typingMode" + ], + "additionalProperties": false + } + } + } + }, + "responses": { + "200": { + "description": "Project observation ceiling updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateProjectObservationPolicyResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "409": { + "description": "Label projection cleanup is active or failed; resolve failed cleanup before re-enabling project retention", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "503": { + "description": "Policy was stored but a connected runner did not acknowledge it; retry the request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "presence:observe" + }, + "description": "**Required scope:** `presence:observe`" + } + }, + "/api/{session}/observation-policy": { + "get": { + "operationId": "getSessionObservationPolicy", + "tags": [ + "Presence", + "Labels", + "Business App" + ], + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "presence:read", + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1 + }, + "required": true, + "name": "session", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Effective session observation policy", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetSessionObservationPolicyResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API presence:read" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `presence:read`" + }, + "put": { + "operationId": "updateSessionObservationPolicy", + "tags": [ + "Presence", + "Labels", + "Business App" + ], + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "presence:observe", + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1 + }, + "required": true, + "name": "session", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "presenceMode": { + "type": "string", + "enum": [ + "inherit", + "off", + "events", + "cache" + ] + }, + "typingMode": { + "type": "string", + "enum": [ + "inherit", + "off", + "events", + "cache" + ] + }, + "labelMode": { + "type": "string", + "enum": [ + "inherit", + "off", + "events", + "cache", + "project" + ] + }, + "quickReplyMode": { + "type": "string", + "enum": [ + "inherit", + "off", + "events", + "cache" + ] + } + }, + "required": [ + "presenceMode", + "typingMode" + ], + "additionalProperties": false + } + } + } + }, + "responses": { + "200": { + "description": "Session observation override updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateSessionObservationPolicyResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "409": { + "description": "Label projection cleanup is active or failed; resolve failed cleanup before re-enabling project retention", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "503": { + "description": "Policy was stored but a connected runner did not acknowledge it; retry the request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API presence:observe" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `presence:observe`" + } + }, + "/api/{session}/profile": { + "get": { + "operationId": "getProfile", + "tags": [ + "Profile" + ], + "summary": "Get the session's own profile", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "profile:read", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Profile info", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetProfileResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API profile:read" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:read`" + } + }, + "/api/{session}/profile/name": { + "put": { + "operationId": "setProfileName", + "tags": [ + "Profile" + ], + "summary": "Set profile display name (push name)", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "profile:write", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SetProfileNameRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Name updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API profile:write" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:write`" + } + }, + "/api/{session}/profile/status": { + "put": { + "operationId": "setProfileStatus", + "tags": [ + "Profile" + ], + "summary": "Set profile status (about) text", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "profile:write", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SetProfileStatusRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Status updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API profile:write" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:write`" + } + }, + "/api/{session}/profile/picture": { + "put": { + "operationId": "setProfilePicture", + "tags": [ + "Profile" + ], + "summary": "Set profile picture", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "profile:write", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SetProfilePictureRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Picture updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API profile:write" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:write`" + }, + "delete": { + "operationId": "deleteProfilePicture", + "tags": [ + "Profile" + ], + "summary": "Remove the profile picture", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "profile:write", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Picture deleted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API profile:write" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:write`" + } + }, + "/api/{session}/privacy": { + "get": { + "operationId": "getPrivacySettings", + "tags": [ + "Privacy" + ], + "summary": "Get privacy settings", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "profile:read", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Privacy settings", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PrivacySettingsResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API profile:read" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:read`" + } + }, + "/api/{session}/privacy/disappearing/default": { + "put": { + "operationId": "setDefaultDisappearingTimer", + "tags": [ + "Privacy" + ], + "summary": "Set the default disappearing-message timer", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "profile:write", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DefaultDisappearingTimerRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Default disappearing-message timer updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API profile:write" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:write`" + } + }, + "/api/{session}/privacy/{setting}": { + "put": { + "operationId": "setPrivacySetting", + "tags": [ + "Privacy" + ], + "summary": "Update a privacy setting", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "profile:write", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string", + "enum": [ + "groupadd", + "last", + "status", + "profile", + "readreceipts", + "online", + "calladd", + "messages", + "defense", + "stickers" + ] + }, + "required": true, + "name": "setting", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SetPrivacySettingRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Updated privacy settings", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdatedPrivacySettingsResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API profile:write" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:write`" + } + }, + "/api/{session}/labels": { + "get": { + "operationId": "listLabels", + "tags": [ + "Labels" + ], + "summary": "List labels defined for the session", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "labels:read", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string", + "enum": [ + "true", + "false" + ] + }, + "required": false, + "name": "includeObservation", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Label list", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListLabelsResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API labels:read" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `labels:read`" + }, + "post": { + "operationId": "createLabel", + "tags": [ + "Labels" + ], + "summary": "Create a label", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "labels:manage", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateLabelRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Label created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateLabelResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API labels:manage" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `labels:manage`" + } + }, + "/api/{session}/labels/{labelId}": { + "put": { + "operationId": "updateLabel", + "tags": [ + "Labels" + ], + "summary": "Update a label", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "labels:manage", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "labelId", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateLabelRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Label updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "409": { + "description": "The session has no authoritative view of its labels yet. Retry once a cached or project-retained snapshot is complete.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API labels:manage" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `labels:manage`" + }, + "delete": { + "operationId": "deleteLabel", + "tags": [ + "Labels" + ], + "summary": "Delete a label", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "labels:manage", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "labelId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Label deleted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API labels:manage" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `labels:manage`" + } + }, + "/api/{session}/labels/chats/{chatId}": { + "get": { + "operationId": "getChatLabels", + "tags": [ + "Labels" + ], + "summary": "Get labels attached to a chat", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "labels:read", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "chatId", + "in": "path" + }, + { + "schema": { + "type": "string", + "enum": [ + "true", + "false" + ] + }, + "required": false, + "name": "includeObservation", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Chat labels", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetChatLabelsResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API labels:read" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `labels:read`" + }, + "put": { + "operationId": "setChatLabels", + "tags": [ + "Labels" + ], + "summary": "Replace the set of labels attached to a chat", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "labels:manage", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "chatId", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SetChatLabelsRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Chat labels updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "409": { + "description": "The session has no authoritative view of its labels yet. Retry once a cached or project-retained snapshot is complete.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API labels:manage" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `labels:manage`" + } + }, + "/api/webhooks": { + "get": { + "operationId": "listWebhooks", + "tags": [ + "Webhooks" + ], + "summary": "List webhooks for the tenant", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "webhooks:manage", + "responses": { + "200": { + "description": "Webhook list", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListWebhooksResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "webhooks:manage" + }, + "description": "**Required scope:** `webhooks:manage`" + }, + "post": { + "operationId": "createWebhook", + "tags": [ + "Webhooks" + ], + "summary": "Register a new webhook", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "webhooks:manage", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateWebhookRequest" + } + } + } + }, + "responses": { + "201": { + "description": "Webhook created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateWebhookResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "webhooks:manage" + }, + "description": "**Required scope:** `webhooks:manage`" + } + }, + "/api/webhooks/{id}": { + "get": { + "operationId": "getWebhook", + "tags": [ + "Webhooks" + ], + "summary": "Get a webhook by id", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "webhooks:manage", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Webhook details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetWebhookResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "webhooks:manage" + }, + "description": "**Required scope:** `webhooks:manage`" + }, + "put": { + "operationId": "updateWebhook", + "tags": [ + "Webhooks" + ], + "summary": "Update a webhook", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "webhooks:manage", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateWebhookRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Webhook updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateWebhookResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "webhooks:manage" + }, + "description": "**Required scope:** `webhooks:manage`" + }, + "delete": { + "operationId": "deleteWebhook", + "tags": [ + "Webhooks" + ], + "summary": "Delete a webhook", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "webhooks:manage", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Webhook deleted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "webhooks:manage" + }, + "description": "**Required scope:** `webhooks:manage`" + } + }, + "/api/media/{id}": { + "get": { + "operationId": "downloadMedia", + "tags": [ + "Media" + ], + "summary": "Download media (binary stream or redirect to S3)", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "media:read", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Media binary stream" + }, + "302": { + "description": "Redirect to S3" + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API media:read" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `media:read`" + } + }, + "/api/media/{id}/info": { + "get": { + "operationId": "getMediaInfo", + "tags": [ + "Media" + ], + "summary": "Get media metadata", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "media:read", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Media info", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetMediaInfoResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API media:read" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `media:read`" + } + }, + "/api/media/{id}/download-and-save": { + "post": { + "operationId": "downloadAndSaveMedia", + "tags": [ + "Media" + ], + "summary": "Download media and persist it to the tenant's S3 bucket", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "media:manage", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Persistence queued or already persisted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API media:manage" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `media:manage`" + } + }, + "/api/projects/{projectSlug}/templates": { + "get": { + "operationId": "listProjectTemplates", + "tags": [ + "Templates" + ], + "summary": "List project message templates", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "templates:read", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "projectSlug", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Templates", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListProjectTemplatesResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "templates:read" + }, + "description": "**Required scope:** `templates:read`" + }, + "post": { + "operationId": "createProjectTemplate", + "tags": [ + "Templates" + ], + "summary": "Create a project message template", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "templates:manage", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "projectSlug", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateMessageTemplateRequest" + } + } + } + }, + "responses": { + "201": { + "description": "Created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateProjectTemplateResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "templates:manage" + }, + "description": "**Required scope:** `templates:manage`" + } + }, + "/api/projects/{projectSlug}/templates/{id}": { + "get": { + "operationId": "getProjectTemplate", + "tags": [ + "Templates" + ], + "summary": "Get a project message template", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "templates:read", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "projectSlug", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Template", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetProjectTemplateResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "templates:read" + }, + "description": "**Required scope:** `templates:read`" + }, + "patch": { + "operationId": "updateProjectTemplate", + "tags": [ + "Templates" + ], + "summary": "Update a project message template", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "templates:manage", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "projectSlug", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateMessageTemplateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateProjectTemplateResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "templates:manage" + }, + "description": "**Required scope:** `templates:manage`" + }, + "delete": { + "operationId": "deleteProjectTemplate", + "tags": [ + "Templates" + ], + "summary": "Delete a project message template", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "templates:manage", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "projectSlug", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Deleted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "templates:manage" + }, + "description": "**Required scope:** `templates:manage`" + } + }, + "/api/projects/{projectSlug}/templates/{id}/preview": { + "post": { + "operationId": "previewProjectTemplate", + "tags": [ + "Templates" + ], + "summary": "Render a template preview (idealized) or surface-specific output", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "templates:read", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "projectSlug", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PreviewMessageTemplateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Rendered", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PreviewProjectTemplateResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "templates:read" + }, + "description": "**Required scope:** `templates:read`" + } + }, + "/api/projects/{projectSlug}/templates/{id}/submit": { + "post": { + "operationId": "submitProjectTemplateToMeta", + "tags": [ + "Templates" + ], + "summary": "Submit a project template to Meta for approval on a Cloud-API session", + "description": "**Required scope:** `templates:manage`\n\nRenders the canonical template into a Meta create-template payload and submits it through the given cloud_api session. Records a per-session approval pointer (cloudLinks) and returns the updated template. The Meta review verdict arrives later via webhook.", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "templates:manage", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "projectSlug", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubmitMessageTemplateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Submitted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubmitProjectTemplateResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "templates:manage" + } + } + }, + "/api/projects/{projectSlug}/campaigns": { + "get": { + "operationId": "listCampaigns", + "tags": [ + "Campaigns" + ], + "summary": "List campaigns", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "campaigns:read", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "projectSlug", + "in": "path" + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListCampaignsResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "campaigns:read" + }, + "description": "**Required scope:** `campaigns:read`" + }, + "post": { + "operationId": "createCampaign", + "tags": [ + "Campaigns" + ], + "summary": "Create a campaign", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "campaigns:manage", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "projectSlug", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateCampaignRequest" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateCampaignResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "402": { + "description": "This project has no number on a plan that includes Campaigns (`campaigns_not_entitled`)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "campaigns:manage" + }, + "description": "**Required scope:** `campaigns:manage`" + } + }, + "/api/projects/{projectSlug}/campaigns/{id}": { + "get": { + "operationId": "getCampaign", + "tags": [ + "Campaigns" + ], + "summary": "Get a campaign", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "campaigns:read", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "projectSlug", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetCampaignResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "402": { + "description": "This project has no number on a plan that includes Campaigns (`campaigns_not_entitled`)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "campaigns:read" + }, + "description": "**Required scope:** `campaigns:read`" + } + }, + "/api/projects/{projectSlug}/campaigns/{id}/analytics": { + "get": { + "operationId": "getCampaignAnalytics", + "tags": [ + "Campaigns" + ], + "summary": "Campaign analytics (funnel, response timing, retries)", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "campaigns:read", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "projectSlug", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CampaignAnalyticsResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "402": { + "description": "This project has no number on a plan that includes Campaigns (`campaigns_not_entitled`)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "campaigns:read" + }, + "description": "**Required scope:** `campaigns:read`" + } + }, + "/api/projects/{projectSlug}/campaigns/{id}/launch": { + "post": { + "operationId": "launchCampaign", + "tags": [ + "Campaigns" + ], + "summary": "Launch a campaign", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "campaigns:manage", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "projectSlug", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LaunchCampaignRequest" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LaunchCampaignResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "402": { + "description": "This project has no number on a plan that includes Campaigns (`campaigns_not_entitled`)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "campaigns:manage" + }, + "description": "**Required scope:** `campaigns:manage`" + } + }, + "/api/projects/{projectSlug}/campaigns/{id}/pause": { + "post": { + "operationId": "pauseCampaign", + "tags": [ + "Campaigns" + ], + "summary": "Pause a campaign", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "campaigns:manage", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "projectSlug", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PauseCampaignResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "402": { + "description": "This project has no number on a plan that includes Campaigns (`campaigns_not_entitled`)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "campaigns:manage" + }, + "description": "**Required scope:** `campaigns:manage`" + } + }, + "/api/projects/{projectSlug}/campaigns/{id}/resume": { + "post": { + "operationId": "resumeCampaign", + "tags": [ + "Campaigns" + ], + "summary": "Resume a campaign", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "campaigns:manage", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "projectSlug", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResumeCampaignResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "402": { + "description": "This project has no number on a plan that includes Campaigns (`campaigns_not_entitled`)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "campaigns:manage" + }, + "description": "**Required scope:** `campaigns:manage`" + } + }, + "/api/projects/{projectSlug}/campaigns/{id}/stop": { + "post": { + "operationId": "stopCampaign", + "tags": [ + "Campaigns" + ], + "summary": "Stop a campaign", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "campaigns:manage", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "projectSlug", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StopCampaignResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "402": { + "description": "This project has no number on a plan that includes Campaigns (`campaigns_not_entitled`)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "campaigns:manage" + }, + "description": "**Required scope:** `campaigns:manage`" + } + }, + "/api/projects/{projectSlug}/campaigns/{id}/requeue": { + "post": { + "operationId": "requeueCampaign", + "tags": [ + "Campaigns" + ], + "summary": "Re-queue failed recipients", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "campaigns:manage", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "projectSlug", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RequeueCampaignRequest" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RequeueCampaignResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "402": { + "description": "This project has no number on a plan that includes Campaigns (`campaigns_not_entitled`)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "campaigns:manage" + }, + "description": "**Required scope:** `campaigns:manage`" + } + }, + "/api/widget/sessions": { + "post": { + "operationId": "createWidgetSession", + "tags": [ + "Widget" + ], + "summary": "Create a widget session for embedding the connect flow", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "widget:create", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateWidgetSessionRequest" + } + } + } + }, + "responses": { + "201": { + "description": "Widget session created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WidgetSessionResponseWrapper" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "widget:create" + }, + "description": "**Required scope:** `widget:create`" + } + }, + "/api/widget/sessions/{id}": { + "delete": { + "operationId": "cancelWidgetSession", + "tags": [ + "Widget" + ], + "summary": "Cancel a pending widget session and revoke its CST", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "widget:create", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Cancelled", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "message": { + "type": "string" + } + }, + "required": [ + "success", + "message" + ] + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "widget:create" + }, + "description": "**Required scope:** `widget:create`" + } + }, + "/api/widget/sessions/{id}/handoff": { + "post": { + "operationId": "createWidgetHandoff", + "tags": [ + "Widget" + ], + "summary": "Mint a TV-style handoff token + meta-QR so the user can finish the connect flow on another device.", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "widget:create", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "responses": { + "201": { + "description": "Handoff minted", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/WidgetHandoffResponse" + } + }, + "required": [ + "success", + "data" + ] + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "widget:create" + }, + "description": "**Required scope:** `widget:create`" + } + }, + "/widget/handoff/{token}/state": { + "get": { + "operationId": "getWidgetHandoffState", + "tags": [ + "Widget" + ], + "security": [], + "summary": "Resolve a handoff token to the current QR + session status. Public — the token in the URL is the bearer.", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "token", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Current QR + status", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/WidgetHandoffState" + } + }, + "required": [ + "success", + "data" + ] + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + } + }, + "x-webhooks": { + "message.received": { + "post": { + "operationId": "onMessageReceived", + "summary": "Incoming message", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MessageReceivedEvent" + } + } + } + }, + "responses": { + "200": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "message.sent": { + "post": { + "operationId": "onMessageSent", + "summary": "Outgoing message successfully sent", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MessageSentEvent" + } + } + } + }, + "responses": { + "200": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "message.ack": { + "post": { + "operationId": "onMessageAck", + "summary": "Delivery acknowledgement", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MessageAckEvent" + } + } + } + }, + "responses": { + "200": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "message.revoked": { + "post": { + "operationId": "onMessageRevoked", + "summary": "Message revoked", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MessageRevokedEvent" + } + } + } + }, + "responses": { + "200": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "message.reaction": { + "post": { + "operationId": "onMessageReaction", + "summary": "Reaction added or removed", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MessageReactionEvent" + } + } + } + }, + "responses": { + "200": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "message.edited": { + "post": { + "operationId": "onMessageEdited", + "summary": "Message edited", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MessageEditedEvent" + } + } + } + }, + "responses": { + "200": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "message.update": { + "post": { + "operationId": "onMessageUpdate", + "summary": "Generic message update", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MessageUpdateEvent" + } + } + } + }, + "responses": { + "200": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "message.delete": { + "post": { + "operationId": "onMessageDelete", + "summary": "Message deleted from another device", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MessageDeleteEvent" + } + } + } + }, + "responses": { + "200": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "message.vote": { + "post": { + "operationId": "onMessageVote", + "summary": "Poll vote cast", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MessageVoteEvent" + } + } + } + }, + "responses": { + "200": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "session.status": { + "post": { + "operationId": "onSessionStatus", + "summary": "Session status change", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SessionStatusEvent" + } + } + } + }, + "responses": { + "200": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "session.qr": { + "post": { + "operationId": "onSessionQr", + "summary": "QR code issued for device linking", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SessionQREvent" + } + } + } + }, + "responses": { + "200": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "session.connected": { + "post": { + "operationId": "onSessionConnected", + "summary": "Session connected to WhatsApp", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SessionConnectedEvent" + } + } + } + }, + "responses": { + "200": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "session.logged_out": { + "post": { + "operationId": "onSessionLoggedOut", + "summary": "Session logged out", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SessionLoggedOutEvent" + } + } + } + }, + "responses": { + "200": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "session.phone_offline": { + "post": { + "operationId": "onSessionPhoneOffline", + "summary": "Primary phone has been offline for an extended period", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SessionPhoneOfflineEvent" + } + } + } + }, + "responses": { + "200": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "group.update": { + "post": { + "operationId": "onGroupUpdate", + "summary": "Group metadata changed", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GroupUpdateEvent" + } + } + } + }, + "responses": { + "200": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "group.participant": { + "post": { + "operationId": "onGroupParticipant", + "summary": "Group participants added/removed/promoted/demoted", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GroupParticipantEvent" + } + } + } + }, + "responses": { + "200": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "presence.update": { + "post": { + "operationId": "onPresenceUpdate", + "summary": "User or chat presence change", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PresenceUpdateEvent" + } + } + } + }, + "responses": { + "200": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "contact.update": { + "post": { + "operationId": "onContactUpdate", + "summary": "Contact info changed", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContactUpdateEvent" + } + } + } + }, + "responses": { + "200": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "chat.archive": { + "post": { + "operationId": "onChatArchive", + "summary": "Chat archived or pinned", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ChatArchiveEvent" + } + } + } + }, + "responses": { + "200": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "chat.mute": { + "post": { + "operationId": "onChatMute", + "summary": "Chat muted or unmuted", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ChatMuteEvent" + } + } + } + }, + "responses": { + "200": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "chat.read": { + "post": { + "operationId": "onChatRead", + "summary": "Chat marked read or unread", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ChatReadEvent" + } + } + } + }, + "responses": { + "200": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "chat.clear": { + "post": { + "operationId": "onChatClear", + "summary": "Chat cleared", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ChatClearEvent" + } + } + } + }, + "responses": { + "200": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "chat.delete": { + "post": { + "operationId": "onChatDelete", + "summary": "Chat deleted", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ChatDeleteEvent" + } + } + } + }, + "responses": { + "200": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "call.received": { + "post": { + "operationId": "onCallReceived", + "summary": "Incoming call", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CallReceivedEvent" + } + } + } + }, + "responses": { + "200": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "call.missed": { + "post": { + "operationId": "onCallMissed", + "summary": "Call missed", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CallMissedEvent" + } + } + } + }, + "responses": { + "200": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "call.accepted": { + "post": { + "operationId": "onCallAccepted", + "summary": "Call accepted", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CallAcceptedEvent" + } + } + } + }, + "responses": { + "200": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "call.rejected": { + "post": { + "operationId": "onCallRejected", + "summary": "Call rejected", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CallRejectedEvent" + } + } + } + }, + "responses": { + "200": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "newsletter.update": { + "post": { + "operationId": "onNewsletterUpdate", + "summary": "Newsletter subscription change", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NewsletterUpdateEvent" + } + } + } + }, + "responses": { + "200": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "blocklist.update": { + "post": { + "operationId": "onBlocklistUpdate", + "summary": "Blocklist changed", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BlocklistUpdateEvent" + } + } + } + }, + "responses": { + "200": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "labels.update": { + "post": { + "operationId": "onLabelsUpdate", + "summary": "Label edited / associated / star toggled", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LabelsUpdateEvent" + } + } + } + }, + "responses": { + "200": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "business.quick_reply.update": { + "post": { + "operationId": "onBusinessQuickReplyUpdate", + "summary": "WhatsApp Business App quick reply changed", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BusinessQuickReplyUpdateEvent" + } + } + } + }, + "responses": { + "200": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "history.sync": { + "post": { + "operationId": "onHistorySync", + "summary": "History sync chunk", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HistorySyncEvent" + } + } + } + }, + "responses": { + "200": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "command.result": { + "post": { + "operationId": "onCommandResult", + "summary": "Async command completed", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CommandResultEvent" + } + } + } + }, + "responses": { + "200": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "customer.enabled": { + "post": { + "operationId": "onCustomerEnabled", + "summary": "Customers enabled for a project", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomerEnabledEvent" + } + } + } + }, + "responses": { + "200": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "customer.created": { + "post": { + "operationId": "onCustomerCreated", + "summary": "Customer created", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomerCreatedEvent" + } + } + } + }, + "responses": { + "200": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "customer.updated": { + "post": { + "operationId": "onCustomerUpdated", + "summary": "Customer updated", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomerUpdatedEvent" + } + } + } + }, + "responses": { + "200": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "customer.archiving": { + "post": { + "operationId": "onCustomerArchiving", + "summary": "Customer archival started", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomerArchivingEvent" + } + } + } + }, + "responses": { + "200": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "customer.archived": { + "post": { + "operationId": "onCustomerArchived", + "summary": "Customer archived", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomerArchivedEvent" + } + } + } + }, + "responses": { + "200": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "customer.restored": { + "post": { + "operationId": "onCustomerRestored", + "summary": "Customer restored", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomerRestoredEvent" + } + } + } + }, + "responses": { + "200": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "customer.pairing_link.created": { + "post": { + "operationId": "onCustomerPairingLinkCreated", + "summary": "Customer pairing link created", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomerPairingLinkCreatedEvent" + } + } + } + }, + "responses": { + "200": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "customer.pairing_link.opened": { + "post": { + "operationId": "onCustomerPairingLinkOpened", + "summary": "Customer pairing link opened", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomerPairingLinkOpenedEvent" + } + } + } + }, + "responses": { + "200": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "customer.pairing_link.connected": { + "post": { + "operationId": "onCustomerPairingLinkConnected", + "summary": "Customer pairing link connected", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomerPairingLinkConnectedEvent" + } + } + } + }, + "responses": { + "200": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "customer.pairing_link.failed": { + "post": { + "operationId": "onCustomerPairingLinkFailed", + "summary": "Customer pairing attempt failed", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomerPairingLinkFailedEvent" + } + } + } + }, + "responses": { + "200": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "customer.pairing_link.expired": { + "post": { + "operationId": "onCustomerPairingLinkExpired", + "summary": "Customer pairing link expired", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomerPairingLinkExpiredEvent" + } + } + } + }, + "responses": { + "200": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "customer.pairing_link.revoked": { + "post": { + "operationId": "onCustomerPairingLinkRevoked", + "summary": "Customer pairing link revoked", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomerPairingLinkRevokedEvent" + } + } + } + }, + "responses": { + "200": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "customer.number.attached": { + "post": { + "operationId": "onCustomerNumberAttached", + "summary": "Number attached to a Customer", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomerNumberAttachedEvent" + } + } + } + }, + "responses": { + "200": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "customer.number.transferred": { + "post": { + "operationId": "onCustomerNumberTransferred", + "summary": "Number transferred to a Customer", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomerNumberTransferredEvent" + } + } + } + }, + "responses": { + "200": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "customer.number.disconnected": { + "post": { + "operationId": "onCustomerNumberDisconnected", + "summary": "Customer Number disconnected", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomerNumberDisconnectedEvent" + } + } + } + }, + "responses": { + "200": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "bansafe.enforcement": { + "post": { + "operationId": "onBansafeEnforcement", + "summary": "WhatsApp applied an enforcement to a number, or a ban was reported", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BanSafeEnforcementEvent" + } + } + } + }, + "responses": { + "200": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "bansafe.action": { + "post": { + "operationId": "onBansafeAction", + "summary": "Polymorfa applied, changed, or lifted a safety restriction on a number", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BanSafeActionEvent" + } + } + } + }, + "responses": { + "200": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "bansafe.health_threshold": { + "post": { + "operationId": "onBansafeHealthThreshold", + "summary": "A project's present Health rule crossed below its threshold", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BanSafeHealthThresholdEvent" + } + } + } + }, + "responses": { + "200": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "bansafe.incident": { + "post": { + "operationId": "onBansafeIncident", + "summary": "A restriction was recorded on a number, or the record of one settled", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BanSafeIncidentEvent" + } + } + } + }, + "responses": { + "200": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "bansafe.claim": { + "post": { + "operationId": "onBansafeClaim", + "summary": "A Ban Insurance claim was filed on a ban, decided, paid, or reversed", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BanSafeClaimEvent" + } + } + } + }, + "responses": { + "200": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "message.failed": { + "post": { + "operationId": "onMessageFailed", + "summary": "Outbound send failed, including a send refused by safety", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MessageFailedEvent" + } + } + } + }, + "responses": { + "200": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "template.status": { + "post": { + "operationId": "onTemplateStatus", + "summary": "Message template approval status changed", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TemplateStatusEvent" + } + } + } + }, + "responses": { + "200": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "campaign.paused": { + "post": { + "operationId": "onCampaignPaused", + "summary": "Campaign paused", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CampaignPausedEvent" + } + } + } + }, + "responses": { + "200": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "campaign.completed": { + "post": { + "operationId": "onCampaignCompleted", + "summary": "Campaign finished sending", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CampaignCompletedEvent" + } + } + } + }, + "responses": { + "200": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "campaign.failed": { + "post": { + "operationId": "onCampaignFailed", + "summary": "Campaign failed", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CampaignFailedEvent" + } + } + } + }, + "responses": { + "200": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "campaign.recipient_sent": { + "post": { + "operationId": "onCampaignRecipientSent", + "summary": "A campaign recipient was sent", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CampaignRecipientSentEvent" + } + } + } + }, + "responses": { + "200": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "campaign.recipient_failed": { + "post": { + "operationId": "onCampaignRecipientFailed", + "summary": "A campaign recipient failed after its last attempt", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CampaignRecipientFailedEvent" + } + } + } + }, + "responses": { + "200": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "campaign.recipient_skipped": { + "post": { + "operationId": "onCampaignRecipientSkipped", + "summary": "A campaign recipient was skipped", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CampaignRecipientSkippedEvent" + } + } + } + }, + "responses": { + "200": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "campaign.throttled": { + "post": { + "operationId": "onCampaignThrottled", + "summary": "Campaign sending was paced", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CampaignThrottledEvent" + } + } + } + }, + "responses": { + "200": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "campaign.cap_reached": { + "post": { + "operationId": "onCampaignCapReached", + "summary": "A sending number reached its hourly or daily cap", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CampaignCapReachedEvent" + } + } + } + }, + "responses": { + "200": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "campaign.cold_blocked": { + "post": { + "operationId": "onCampaignColdBlocked", + "summary": "A campaign recipient was held because they never wrote first", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CampaignColdBlockedEvent" + } + } + } + }, + "responses": { + "200": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + } + } +} diff --git a/contracts/drafts/bansafe/openapi.platform.json b/contracts/drafts/bansafe/openapi.platform.json new file mode 100644 index 0000000..79272f6 --- /dev/null +++ b/contracts/drafts/bansafe/openapi.platform.json @@ -0,0 +1,27456 @@ +{ + "openapi": "3.0.3", + "info": { + "title": "Polymorfa Console & Management API", + "version": "1.0.0", + "description": "Complete console/management surface. Resource-oriented REST: `{param}` path variables, single-word action sub-resources.\n\nNamespaces decide inclusion:\n- `/v1/…` — **public registry** (150 endpoints): each endpoint declares either a scoped `pmfa_` organization key or a verified live dashboard JWT, or dashboard-only authorization when a specific user's authority is required. Only implemented handlers are published to customers and SDKs.\n- `/console/…` — **console-only** (50 endpoints): verified dashboard identity. EXCLUDED from the published spec; reason per endpoint.\n- `/admin/…` — **staff-only** (53 endpoints): Polymorfa internal staff. EXCLUDED.\n\nThe published customer spec = this document filtered to `x-audience: public` endpoints with an implemented runtime handler.\nMost transitional body/response schemas remain loose (`additionalProperties: true`); session-control operations use explicit strict schemas." + }, + "servers": [ + { + "url": "https://api.polymorfa.com" + }, + { + "url": "http://localhost:8080", + "description": "local dev" + } + ], + "paths": { + "/v1/sessions": { + "get": { + "operationId": "listPlatformSessions", + "tags": [ + "sessions" + ], + "summary": "List sessions", + "description": "Lists every session in the authenticated organization or selected project, including disconnected sessions and their latest status reason.\n\nOrganization API-key callers require `sessions:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "sessions:read", + "x-merged-endpoints": [ + "listSessionsByOrganization" + ], + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "projectId", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PlatformSession" + } + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + } + } + } + }, + "/v1/sessions/{sessionId}/start": { + "post": { + "operationId": "startPlatformSession", + "tags": [ + "sessions" + ], + "summary": "Start a session", + "description": "Starts a stopped session or retries a session whose runtime failed. The identifier may be the session UUID or stable session slug.\n\nOrganization API-key callers require `sessions:manage`; project-token callers require the same action scope and are accepted only for `session` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "session", + "x-excluded-from-public": false, + "x-required-scope": "sessions:manage", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "sessionId", + "in": "path", + "required": true, + "description": "Database session UUID or stable session slug.", + "schema": { + "$ref": "#/components/schemas/SessionIdentifier" + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SessionProjectContext" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/SessionStartResult" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + }, + "409": { + "$ref": "#/components/responses/Conflict" + }, + "500": { + "$ref": "#/components/responses/InternalError" + } + } + } + }, + "/v1/sessions/{sessionId}/stop": { + "post": { + "operationId": "stopPlatformSession", + "tags": [ + "sessions" + ], + "summary": "Stop a session", + "description": "Requests an asynchronous stop for one session. The identifier may be the session UUID or stable session slug.\n\nOrganization API-key callers require `sessions:manage`; project-token callers require the same action scope and are accepted only for `session` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "session", + "x-excluded-from-public": false, + "x-required-scope": "sessions:manage", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "sessionId", + "in": "path", + "required": true, + "description": "Database session UUID or stable session slug.", + "schema": { + "$ref": "#/components/schemas/SessionIdentifier" + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SessionProjectContext" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/SessionStopResult" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + }, + "500": { + "$ref": "#/components/responses/InternalError" + } + } + } + }, + "/v1/sessions/{sessionId}": { + "delete": { + "operationId": "deletePlatformSession", + "tags": [ + "sessions" + ], + "summary": "Remove a session", + "description": "Permanently removes one session and terminates its active connection when needed.\n\nOrganization API-key callers require `sessions:manage`; project-token callers require the same action scope and are accepted only for `session` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "session", + "x-excluded-from-public": false, + "x-required-scope": "sessions:manage", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "sessionId", + "in": "path", + "required": true, + "description": "Database session UUID or stable session slug.", + "schema": { + "$ref": "#/components/schemas/SessionIdentifier" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/SessionRemoveResult" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + }, + "patch": { + "operationId": "setSessionTierOverride", + "tags": [ + "sessions" + ], + "summary": "Set a session tier override", + "description": "Sets an explicit session tier or clears the override with null.\n\nOrganization API-key callers require `sessions:manage`; project-token callers require the same action scope and are accepted only for `session` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "session", + "x-excluded-from-public": false, + "x-required-scope": "sessions:manage", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "sessionId", + "in": "path", + "required": true, + "description": "Database session UUID or stable session slug.", + "schema": { + "$ref": "#/components/schemas/SessionIdentifier" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SessionTierOverrideRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/ManagedSession" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/v1/sessions/stop": { + "post": { + "operationId": "stopSessions", + "tags": [ + "sessions" + ], + "summary": "Stop multiple sessions", + "description": "Requests asynchronous stops for up to 100 session UUIDs or slugs in the authenticated project scope.\n\nOrganization API-key callers require `sessions:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "sessions:manage", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SessionBatchRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/SessionBatchStopResult" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "500": { + "$ref": "#/components/responses/InternalError" + } + } + } + }, + "/v1/sessions/delete": { + "post": { + "operationId": "deleteSessions", + "tags": [ + "sessions" + ], + "summary": "Remove multiple sessions", + "description": "Permanently removes up to 100 session UUIDs or slugs and terminates any rows that were still active.\n\nOrganization API-key callers require `sessions:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "sessions:manage", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SessionBatchRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/SessionBatchRemoveResult" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + } + } + } + }, + "/v1/sessions/testing": { + "post": { + "operationId": "createTestingSession", + "tags": [ + "sessions" + ], + "summary": "Create a testing number", + "description": "Creates a disconnected simulated session with testMode enabled. Organization keys and dashboard bearers must provide a projectId in the body.\n\nOrganization API-key callers require `sessions:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "sessions:manage", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateTestingNumberRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/TestingSessionId" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + }, + "500": { + "$ref": "#/components/responses/InternalError" + } + } + } + }, + "/v1/bans": { + "get": { + "operationId": "listSessionBans", + "tags": [ + "bans" + ], + "summary": "List session bans", + "description": "Public Management API. Organization API-key callers require `sessions:read`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "organization", + "x-excluded-from-public": false, + "x-required-scope": "sessions:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/v1/bans/active": { + "get": { + "operationId": "listActiveSessionBans", + "tags": [ + "bans" + ], + "summary": "List active session bans", + "description": "Public Management API. Organization API-key callers require `sessions:read`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "organization", + "x-excluded-from-public": false, + "x-required-scope": "sessions:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/v1/bansafe/health": { + "get": { + "operationId": "listBanSafeHealth", + "tags": [ + "bansafe" + ], + "summary": "List number safety", + "description": "Lists present Health, findings counts, and the active Polymorfa restriction for every number in one project. Health is a 0 to 100 estimate from rules v1 or a validated learned model. It remains null until enough fresh evidence is available.\n\nOrganization API-key callers require `sessions:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "sessions:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "projectId", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "cursor", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "limit", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 25 + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BanSafeNumber" + } + }, + "page": { + "$ref": "#/components/schemas/CursorPageMetadata" + } + }, + "required": [ + "data", + "page" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/v1/bansafe/health/{session}": { + "get": { + "operationId": "getBanSafeHealth", + "tags": [ + "bansafe" + ], + "summary": "Get number safety", + "description": "Returns one number's present Health estimate and model metadata, retained open and acknowledged findings with their observation times, directly observed account state, the active Polymorfa restriction, and how that restriction lifts. Recorded findings and observed state remain separate from the estimate.\n\nOrganization API-key callers require `sessions:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "sessions:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "session", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/BanSafeNumberDetail" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/v1/bansafe/health/{session}/history": { + "get": { + "operationId": "listBanSafeHealthHistory", + "tags": [ + "bansafe" + ], + "summary": "List number health history", + "description": "Returns the newest Health evaluations since the requested date, up to the limit, ordered oldest to newest. Each point carries its estimator source and version, evidence coverage, reliability, and availability reason.\n\nOrganization API-key callers require `sessions:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "sessions:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "session", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "since", + "in": "query", + "required": false, + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "limit", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 720, + "default": 720 + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/BanSafeHealthHistory" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/v1/bansafe/signals": { + "get": { + "operationId": "listBanSafeSignals", + "tags": [ + "bansafe" + ], + "summary": "List BanSafe telemetry signals", + "description": "Lists the bounded numeric, boolean, enum, histogram, and error-code aggregate signals that BanSafe can return. The catalogue contains no message content, recipient identifiers, or raw telemetry records.\n\nOrganization API-key callers require `sessions:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "sessions:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BanSafeSignalDefinition" + } + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/v1/bansafe/telemetry/{session}": { + "get": { + "operationId": "getBanSafeTelemetry", + "tags": [ + "bansafe" + ], + "summary": "Get latest BanSafe telemetry", + "description": "Returns collection availability and the latest supported telemetry snapshot for one number. Empty collection is reported as not collected, not as a disabled collector.\n\nOrganization API-key callers require `sessions:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "sessions:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "session", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/BanSafeTelemetryDetail" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/v1/bansafe/telemetry/{session}/history": { + "get": { + "operationId": "listBanSafeTelemetryHistory", + "tags": [ + "bansafe" + ], + "summary": "List BanSafe telemetry history", + "description": "Returns the newest supported telemetry snapshots for one number. Signals are fixed-schema safe aggregates with explicit measured state; raw records and identifiers inside them are not returned.\n\nOrganization API-key callers require `sessions:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "sessions:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "session", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "since", + "in": "query", + "required": false, + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "until", + "in": "query", + "required": false, + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "cursor", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "limit", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 50, + "default": 10 + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BanSafeTelemetrySnapshot" + } + }, + "page": { + "$ref": "#/components/schemas/CursorPageMetadata" + } + }, + "required": [ + "data", + "page" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/v1/bansafe/collection": { + "get": { + "operationId": "listBanSafeCollection", + "tags": [ + "bansafe" + ], + "summary": "List BanSafe collection status", + "description": "Lists telemetry collection freshness for the numbers in one project. Status is derived from ingested records and does not guess whether a collector flag is configured.\n\nOrganization API-key callers require `sessions:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "sessions:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "projectId", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "cursor", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "limit", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 25 + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BanSafeCollectionSession" + } + }, + "page": { + "$ref": "#/components/schemas/CursorPageMetadata" + } + }, + "required": [ + "data", + "page" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/v1/bansafe/health-actions": { + "get": { + "operationId": "listBanSafeHealthActions", + "tags": [ + "bansafe" + ], + "summary": "List Health rule actions", + "description": "Lists the durable customer-visible outcomes of project Health rule actions, newest first. Internal leases, retry bookkeeping, runtime identifiers, and free-form outcomes are omitted.\n\nOrganization API-key callers require `sessions:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "sessions:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "projectId", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "session", + "in": "query", + "required": false, + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256 + } + }, + { + "name": "status", + "in": "query", + "required": false, + "schema": { + "type": "string", + "enum": [ + "pending", + "running", + "succeeded", + "failed", + "cancelled" + ] + } + }, + { + "name": "cursor", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "limit", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 25 + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BanSafeHealthAction" + } + }, + "page": { + "$ref": "#/components/schemas/CursorPageMetadata" + } + }, + "required": [ + "data", + "page" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/v1/bansafe/findings": { + "get": { + "operationId": "listBanSafeFindings", + "tags": [ + "bansafe" + ], + "summary": "List safety findings", + "description": "Lists safety findings across the organization, filterable by project, number, status, and severity. Evidence is numbers only and never contains message content or a recipient identifier.\n\nOrganization API-key callers require `sessions:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "sessions:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "projectId", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "session", + "in": "query", + "required": false, + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256 + } + }, + { + "name": "status", + "in": "query", + "required": false, + "schema": { + "type": "string", + "enum": [ + "open", + "acknowledged", + "resolved" + ] + } + }, + { + "name": "severity", + "in": "query", + "required": false, + "schema": { + "type": "string", + "enum": [ + "info", + "warning", + "critical" + ] + } + }, + { + "name": "cursor", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "limit", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 25 + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BanSafeFinding" + } + }, + "page": { + "$ref": "#/components/schemas/CursorPageMetadata" + } + }, + "required": [ + "data", + "page" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/v1/bansafe/findings/{findingId}/acknowledge": { + "post": { + "operationId": "acknowledgeBanSafeFinding", + "tags": [ + "bansafe" + ], + "summary": "Acknowledge a safety finding", + "description": "Records that a named person on the team has seen this finding, optionally silences its notifications for up to 30 days, and unlocks the appeal form. It does not change the Health estimate, the restriction, or any campaign limit. Requires a signed-in organization owner, admin, or developer; an API key or token is refused with `bansafe_ack_requires_dashboard_identity`.\n\nRequires a verified dashboard bearer and current organization authorization. Organization keys and project tokens are not accepted.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "organization", + "x-excluded-from-public": false, + "x-dashboard-only": true, + "security": [ + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "findingId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AcknowledgeBanSafeFindingInput" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/BanSafeFindingAcknowledgement" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/v1/bansafe/enforcement": { + "get": { + "operationId": "listBanSafeEnforcement", + "tags": [ + "bansafe" + ], + "summary": "List number restrictions", + "description": "Lists every number Polymorfa is currently restricting, what the restriction blocks, and the exact condition that lifts it.\n\nOrganization API-key callers require `sessions:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "sessions:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "projectId", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "rung", + "in": "query", + "required": false, + "schema": { + "type": "string", + "enum": [ + "none", + "notify", + "throttle", + "block_cold", + "suspend" + ] + } + }, + { + "name": "cursor", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "limit", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 25 + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BanSafeEnforcementSummary" + } + }, + "page": { + "$ref": "#/components/schemas/CursorPageMetadata" + } + }, + "required": [ + "data", + "page" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/v1/bansafe/enforcement/{session}/appeal": { + "post": { + "operationId": "appealBanSafeEnforcement", + "tags": [ + "bansafe" + ], + "summary": "Appeal a number restriction", + "description": "Files one appeal against a number's restriction. Every open finding on the number must be acknowledged first, otherwise the request is refused with `findings_unacknowledged`. Filing an appeal does not change the restriction. Requires a signed-in organization owner, admin, or developer.\n\nRequires a verified dashboard bearer and current organization authorization. Organization keys and project tokens are not accepted.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "organization", + "x-excluded-from-public": false, + "x-dashboard-only": true, + "security": [ + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "session", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AppealBanSafeEnforcementInput" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/BanSafeAppealReceipt" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + }, + "409": { + "$ref": "#/components/responses/Conflict" + } + } + } + }, + "/v1/bansafe/incidents": { + "get": { + "operationId": "listBanSafeIncidents", + "tags": [ + "bansafe" + ], + "summary": "List safety incidents", + "description": "Lists the WhatsApp restrictions and customer reports recorded for the organization's numbers.\n\nOrganization API-key callers require `sessions:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "sessions:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "projectId", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "session", + "in": "query", + "required": false, + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256 + } + }, + { + "name": "cursor", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "limit", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 25 + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BanSafeIncident" + } + }, + "page": { + "$ref": "#/components/schemas/CursorPageMetadata" + } + }, + "required": [ + "data", + "page" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + }, + "post": { + "operationId": "createBanSafeIncident", + "tags": [ + "bansafe" + ], + "summary": "Report a ban", + "description": "Records that WhatsApp restricted or banned one of your numbers. Send the same `Idempotency-Key` to retry safely for the same number; a repeat returns the original report. Reusing the key for a different number returns `409 bansafe_incident_idempotency_scope_conflict`.\n\nOrganization API-key callers require `sessions:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "sessions:manage", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "Idempotency-Key", + "in": "header", + "required": true, + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 255 + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ReportBanSafeIncidentInput" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/BanSafeIncidentReceipt" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + }, + "409": { + "$ref": "#/components/responses/Conflict" + } + } + } + }, + "/v1/bansafe/incidents/{incidentId}/retract": { + "post": { + "operationId": "retractBanSafeIncident", + "tags": [ + "bansafe" + ], + "summary": "Withdraw a ban report", + "description": "Withdraws a customer report and returns its incident record. Repeating the request returns the closed record. An incident observed from WhatsApp cannot be withdrawn and returns `409 bansafe_incident_not_a_report`. An unknown incident returns 404.\n\nOrganization API-key callers require `sessions:manage`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "organization", + "x-excluded-from-public": false, + "x-required-scope": "sessions:manage", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "incidentId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/BanSafeIncident" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + }, + "409": { + "$ref": "#/components/responses/Conflict" + } + } + } + }, + "/v1/bansafe/claims": { + "get": { + "operationId": "listBanSafeClaims", + "tags": [ + "bansafe" + ], + "summary": "List Ban Insurance claims", + "description": "Lists the Ban Insurance claims filed on your numbers, newest first. A claim is filed automatically when a ban is recorded on a number whose plan includes insurance; there is no request to file one.\n\nOrganization API-key callers require `sessions:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "sessions:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "projectId", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "session", + "in": "query", + "required": false, + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 256 + } + }, + { + "name": "status", + "in": "query", + "required": false, + "schema": { + "type": "string", + "enum": [ + "filed", + "under_review", + "approved", + "denied", + "paid", + "reversed" + ] + } + }, + { + "name": "cursor", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "limit", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 25 + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BanSafeClaim" + } + }, + "page": { + "$ref": "#/components/schemas/CursorPageMetadata" + } + }, + "required": [ + "data", + "page" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/v1/bansafe/claims/{claimId}": { + "get": { + "operationId": "getBanSafeClaim", + "tags": [ + "bansafe" + ], + "summary": "Get a Ban Insurance claim", + "description": "Returns one claim: the 30 days it covers, the credits that number consumed in them, the most the plan returns, what the claim returns, what the ban was attributed to, and the evidence counts behind that.\n\nOrganization API-key callers require `sessions:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "sessions:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "claimId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/BanSafeClaim" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/v1/projects/{projectId}/safe-mode": { + "get": { + "operationId": "getProjectSafeModeCeiling", + "tags": [ + "bansafe" + ], + "summary": "Get a project's Safe Mode ceiling", + "description": "Returns the most visible sending behaviour any number in this project may use. Every setting is off by default. `entitled` reports whether the plan includes BanSafe Lite, which Safe Mode is part of, and `entitlementReason` gives the reason a raise would be refused.\n\nOrganization API-key callers require `sessions:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "sessions:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "projectId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/ProjectSafeMode" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + }, + "put": { + "operationId": "updateProjectSafeModeCeiling", + "tags": [ + "bansafe" + ], + "summary": "Set a project's Safe Mode ceiling", + "description": "Sets the most visible behaviour any number in this project may use. Send only the settings you want to change. Presence and read receipts are visible to the people these numbers message: turning them on makes a number appear online, exposes last seen subject to the account's privacy settings, and puts blue ticks on incoming messages. Raising a setting requires a plan that includes BanSafe Lite, and lowering one is always allowed. A signed-in caller must be an organization owner, admin, or developer.\n\nOrganization API-key callers require `sessions:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "sessions:manage", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "projectId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateProjectSafeModeInput" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/ProjectSafeMode" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "402": { + "$ref": "#/components/responses/PaymentRequired" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + }, + "503": { + "$ref": "#/components/responses/PropagationPending" + } + } + } + }, + "/v1/sessions/{sessionId}/safe-mode": { + "get": { + "operationId": "getNumberSafeMode", + "tags": [ + "bansafe" + ], + "summary": "Get a number's Safe Mode", + "description": "Returns the project ceiling, this number's override, the policy in force, and what the number last reported it is running. `mismatch` is true when the two differ. `entitled` reports whether the plan includes BanSafe Lite, which Safe Mode is part of, and `entitlementReason` gives the reason a raise would be refused.\n\nOrganization API-key callers require `sessions:read`; project-token callers require the same action scope and are accepted only for `session` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "session", + "x-excluded-from-public": false, + "x-required-scope": "sessions:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "sessionId", + "in": "path", + "required": true, + "description": "Database session UUID or stable session slug.", + "schema": { + "$ref": "#/components/schemas/SessionIdentifier" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/SessionSafeMode" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + }, + "put": { + "operationId": "updateNumberSafeMode", + "tags": [ + "bansafe" + ], + "summary": "Set a number's Safe Mode", + "description": "Sets one number's Safe Mode. Each setting accepts `inherit` to follow the project ceiling. An override may only be equally or more conservative than the ceiling; a more visible value is refused with `safe_mode_exceeds_project_ceiling`. Raising a setting requires a plan that includes BanSafe Lite, and lowering one is always allowed. A signed-in caller must be an organization owner, admin, or developer.\n\nOrganization API-key callers require `sessions:manage`; project-token callers require the same action scope and are accepted only for `session` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "session", + "x-excluded-from-public": false, + "x-required-scope": "sessions:manage", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "sessionId", + "in": "path", + "required": true, + "description": "Database session UUID or stable session slug.", + "schema": { + "$ref": "#/components/schemas/SessionIdentifier" + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateSessionSafeModeInput" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/SessionSafeMode" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "402": { + "$ref": "#/components/responses/PaymentRequired" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + }, + "503": { + "$ref": "#/components/responses/PropagationPending" + } + } + } + }, + "/v1/projects/{projectId}/warmup-plan": { + "get": { + "operationId": "getProjectWarmupPlanSettings", + "tags": [ + "bansafe" + ], + "summary": "Get a project's warm-up plan", + "description": "Returns whether numbers in this project have a daily allowance, the two settings that shape the ramp, the per-number daily cap it climbs to, and the projected allowance day by day. `entitled` reports whether the plan includes BanSafe Lite, which the warm-up plan is part of.\n\nOrganization API-key callers require `sessions:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "sessions:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "projectId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/ProjectWarmupPlan" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + }, + "put": { + "operationId": "updateProjectWarmupPlanSettings", + "tags": [ + "bansafe" + ], + "summary": "Set a project's warm-up plan", + "description": "Turns the warm-up plan on or off for a project and sets how long the ramp takes and how many messages a number may send on its first day. Send only the settings you want to change. While the plan is on, a send past a number's allowance is refused with `bansafe_daily_allowance_reached` and campaign recipients are deferred to the next reset. Turning the plan on requires a plan that includes BanSafe Lite; turning it off is always allowed. A signed-in caller must be an organization owner, admin, or developer.\n\nOrganization API-key callers require `sessions:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "sessions:manage", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "projectId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateProjectWarmupPlanInput" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/ProjectWarmupPlan" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "402": { + "$ref": "#/components/responses/PaymentRequired" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + }, + "503": { + "$ref": "#/components/responses/PropagationPending" + } + } + } + }, + "/v1/projects/{projectId}/health-policy": { + "get": { + "operationId": "getProjectHealthPolicySettings", + "tags": [ + "bansafe" + ], + "summary": "Get a project's health policy", + "description": "Returns the health threshold and the actions configured for numbers in this project. Integration flags report whether email and webhook delivery are ready to use.\n\nOrganization API-key callers require `sessions:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "sessions:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "projectId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/ProjectHealthPolicy" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + }, + "put": { + "operationId": "updateProjectHealthPolicySettings", + "tags": [ + "bansafe" + ], + "summary": "Set a project's health policy", + "description": "Replaces the project policy when the supplied version matches the stored version. The rule applies only when an available health estimate is below the threshold; an unavailable estimate triggers no action. Stopping disconnects a session and retains its linked credentials. Logging out requires relinking.\n\nOrganization API-key callers require `sessions:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "sessions:manage", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "projectId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateProjectHealthPolicyInput" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/ProjectHealthPolicy" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + }, + "409": { + "$ref": "#/components/responses/Conflict" + } + } + } + }, + "/v1/projects/{projectId}/insurance-evidence": { + "get": { + "operationId": "getInsuranceEvidenceSettings", + "tags": [ + "bansafe" + ], + "summary": "Get a project's insurance evidence setting", + "description": "Returns whether evidence collection about other linked devices is enabled and whether any number in the project has Ban Insurance included in its plan. Collection is off until explicitly enabled.\n\nOrganization API-key callers require `sessions:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "sessions:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "projectId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/ProjectInsuranceEvidence" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + }, + "put": { + "operationId": "updateInsuranceEvidenceSettings", + "tags": [ + "bansafe" + ], + "summary": "Set a project's insurance evidence setting", + "description": "Enables or disables collection of counts about other linked devices. Collection never includes messages, recipient identities, or device names. Disabling collection discards stored device evidence. A 503 `propagation_pending` means the setting was stored but a connected number has not confirmed it; retry the request. A signed-in caller must be an organization owner, admin, or developer.\n\nOrganization API-key callers require `sessions:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "sessions:manage", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "projectId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateProjectInsuranceEvidenceInput" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/ProjectInsuranceEvidence" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + }, + "503": { + "$ref": "#/components/responses/PropagationPending" + } + } + } + }, + "/v1/campaigns": { + "get": { + "operationId": "listPlatformCampaigns", + "tags": [ + "campaigns" + ], + "summary": "List platform campaigns", + "description": "Public Management API. Organization API-key callers require `campaigns:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "campaigns:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "projectId", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "projectSlug", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + }, + "post": { + "operationId": "createPlatformCampaign", + "tags": [ + "campaigns" + ], + "summary": "Create campaign", + "description": "Public Management API. Organization API-key callers require `campaigns:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "campaigns:manage", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/v1/campaigns/{campaignId}": { + "get": { + "operationId": "getPlatformCampaign", + "tags": [ + "campaigns" + ], + "summary": "Get campaign", + "description": "Public Management API. Organization API-key callers require `campaigns:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "campaigns:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "campaignId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + }, + "patch": { + "operationId": "updateCampaign", + "tags": [ + "campaigns" + ], + "summary": "Update campaign", + "description": "Public Management API. Organization API-key callers require `campaigns:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "campaigns:manage", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "campaignId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + }, + "delete": { + "operationId": "deleteCampaign", + "tags": [ + "campaigns" + ], + "summary": "Delete campaign", + "description": "Public Management API. Organization API-key callers require `campaigns:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "campaigns:manage", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "campaignId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/v1/campaigns/{campaignId}/launch": { + "post": { + "operationId": "launchPlatformCampaign", + "tags": [ + "campaigns" + ], + "summary": "Launch campaign", + "description": "Public Management API. Organization API-key callers require `campaigns:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "campaigns:manage", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "campaignId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/v1/campaigns/{campaignId}/pause": { + "post": { + "operationId": "pausePlatformCampaign", + "tags": [ + "campaigns" + ], + "summary": "Pause campaign", + "description": "Public Management API. Organization API-key callers require `campaigns:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "campaigns:manage", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "campaignId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/v1/campaigns/{campaignId}/resume": { + "post": { + "operationId": "resumePlatformCampaign", + "tags": [ + "campaigns" + ], + "summary": "Resume campaign", + "description": "Public Management API. Organization API-key callers require `campaigns:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "campaigns:manage", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "campaignId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/v1/campaigns/{campaignId}/stop": { + "post": { + "operationId": "stopPlatformCampaign", + "tags": [ + "campaigns" + ], + "summary": "Stop campaign", + "description": "Public Management API. Organization API-key callers require `campaigns:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "campaigns:manage", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "campaignId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/v1/campaigns/{campaignId}/archive": { + "post": { + "operationId": "archiveCampaign", + "tags": [ + "campaigns" + ], + "summary": "Archive campaign", + "description": "Public Management API. Organization API-key callers require `campaigns:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "campaigns:manage", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "campaignId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/v1/campaigns/{campaignId}/duplicate": { + "post": { + "operationId": "duplicateCampaign", + "tags": [ + "campaigns" + ], + "summary": "Duplicate campaign", + "description": "Public Management API. Organization API-key callers require `campaigns:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "campaigns:manage", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "campaignId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/v1/campaigns/{campaignId}/requeue": { + "post": { + "operationId": "requeueFailedCampaign", + "tags": [ + "campaigns" + ], + "summary": "Requeue failed campaign", + "description": "Public Management API. Organization API-key callers require `campaigns:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "campaigns:manage", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "campaignId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/v1/campaigns/{campaignId}/analytics": { + "get": { + "operationId": "getPlatformCampaignAnalytics", + "tags": [ + "campaigns" + ], + "summary": "Get campaign analytics", + "description": "Public Management API. Organization API-key callers require `campaigns:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "campaigns:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "campaignId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/v1/campaigns/{campaignId}/events": { + "get": { + "operationId": "listCampaignEvents", + "tags": [ + "campaigns" + ], + "summary": "List campaign events", + "description": "Public Management API. Organization API-key callers require `campaigns:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "campaigns:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "campaignId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/v1/campaigns/{campaignId}/recipients": { + "get": { + "operationId": "listCampaignRecipients", + "tags": [ + "campaigns" + ], + "summary": "List campaign recipients", + "description": "Public Management API. Organization API-key callers require `campaigns:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "campaigns:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "campaignId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/v1/audiences": { + "get": { + "operationId": "listAudiences", + "tags": [ + "audiences" + ], + "summary": "List audiences", + "description": "Public Management API. Organization API-key callers require `campaigns:read`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "organization", + "x-excluded-from-public": false, + "x-required-scope": "campaigns:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + }, + "post": { + "operationId": "createAudience", + "tags": [ + "audiences" + ], + "summary": "Create audience", + "description": "Public Management API. Organization API-key callers require `campaigns:manage`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "organization", + "x-excluded-from-public": false, + "x-required-scope": "campaigns:manage", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/v1/audiences/{listId}": { + "get": { + "operationId": "getAudience", + "tags": [ + "audiences" + ], + "summary": "Get audience", + "description": "Public Management API. Organization API-key callers require `campaigns:read`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "organization", + "x-excluded-from-public": false, + "x-required-scope": "campaigns:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "listId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + }, + "delete": { + "operationId": "deleteAudience", + "tags": [ + "audiences" + ], + "summary": "Delete audience", + "description": "Public Management API. Organization API-key callers require `campaigns:manage`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "organization", + "x-excluded-from-public": false, + "x-required-scope": "campaigns:manage", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "listId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/v1/audiences/uploads": { + "post": { + "operationId": "createAudienceUploadUrl", + "tags": [ + "audiences" + ], + "summary": "Create audience upload url", + "description": "Public Management API. Organization API-key callers require `campaigns:manage`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "organization", + "x-excluded-from-public": false, + "x-required-scope": "campaigns:manage", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/v1/templates": { + "get": { + "operationId": "listMessageTemplates", + "tags": [ + "templates" + ], + "summary": "List message templates", + "description": "Lists the message-template drafts in one project.\n\nOrganization API-key callers require `templates:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "templates:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "projectId", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "type": "array", + "maxItems": 500, + "items": { + "$ref": "#/components/schemas/ManagementTemplate" + } + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + }, + "post": { + "operationId": "createMessageTemplate", + "tags": [ + "templates" + ], + "summary": "Create a message-template draft", + "description": "Creates an incomplete or complete message-template draft in one project.\n\nOrganization API-key callers require `templates:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "templates:manage", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateManagementTemplateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/TemplateId" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/v1/templates/{templateId}": { + "get": { + "operationId": "getMessageTemplate", + "tags": [ + "templates" + ], + "summary": "Get a message-template draft", + "description": "Gets one message-template draft from the specified project.\n\nOrganization API-key callers require `templates:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "templates:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "templateId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "projectId", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "type": "object", + "allOf": [ + { + "$ref": "#/components/schemas/ManagementTemplate" + } + ], + "nullable": true + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + }, + "patch": { + "operationId": "updateMessageTemplate", + "tags": [ + "templates" + ], + "summary": "Update a message-template draft", + "description": "Updates one message-template draft in the project supplied in the request body.\n\nOrganization API-key callers require `templates:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "templates:manage", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "templateId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateManagementTemplateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/ManagementTemplate" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + }, + "delete": { + "operationId": "deleteMessageTemplate", + "tags": [ + "templates" + ], + "summary": "Delete a message-template draft", + "description": "Deletes one message-template draft from the specified project.\n\nOrganization API-key callers require `templates:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "templates:manage", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "templateId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "projectId", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/DeleteManagementTemplateResult" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/v1/flows": { + "get": { + "operationId": "listFlows", + "tags": [ + "flows" + ], + "summary": "List Flow drafts", + "description": "Lists compact WhatsApp Flow draft summaries in one project.\n\nOrganization API-key callers require `sessions:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "sessions:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "projectId", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "type": "array", + "maxItems": 250, + "items": { + "$ref": "#/components/schemas/FlowSummary" + } + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + }, + "post": { + "operationId": "createFlow", + "tags": [ + "flows" + ], + "summary": "Create a Flow draft", + "description": "Creates a project-scoped WhatsApp Flow draft. A supplied draftId makes retries idempotent.\n\nOrganization API-key callers require `sessions:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "sessions:manage", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateFlowRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/FlowDraft" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/v1/flows/{flowId}": { + "get": { + "operationId": "getFlow", + "tags": [ + "flows" + ], + "summary": "Get a Flow draft", + "description": "Gets one project-scoped WhatsApp Flow draft.\n\nOrganization API-key callers require `sessions:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "sessions:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "flowId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "projectId", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "type": "object", + "allOf": [ + { + "$ref": "#/components/schemas/FlowDraft" + } + ], + "nullable": true + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + }, + "patch": { + "operationId": "updateFlow", + "tags": [ + "flows" + ], + "summary": "Update a Flow draft", + "description": "Updates a Flow draft when expectedUpdatedAt matches the stored revision.\n\nOrganization API-key callers require `sessions:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "sessions:manage", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "flowId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateFlowRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/FlowDraft" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + }, + "409": { + "$ref": "#/components/responses/Conflict" + } + } + }, + "delete": { + "operationId": "deleteFlow", + "tags": [ + "flows" + ], + "summary": "Delete a Flow draft", + "description": "Deletes a local Flow draft without deleting linked Meta Flow assets.\n\nOrganization API-key callers require `sessions:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "sessions:manage", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "flowId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "projectId", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/DeleteFlowResult" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/v1/optouts": { + "get": { + "operationId": "listOptOuts", + "tags": [ + "optouts" + ], + "summary": "List opt outs", + "description": "Public Management API. Organization API-key callers require `campaigns:read`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "organization", + "x-excluded-from-public": false, + "x-required-scope": "campaigns:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + }, + "post": { + "operationId": "createOptOut", + "tags": [ + "optouts" + ], + "summary": "Create opt out", + "description": "Public Management API. Organization API-key callers require `campaigns:manage`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "organization", + "x-excluded-from-public": false, + "x-required-scope": "campaigns:manage", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/v1/optouts/batch": { + "post": { + "operationId": "createOptOuts", + "tags": [ + "optouts" + ], + "summary": "Create opt outs", + "description": "Public Management API. Organization API-key callers require `campaigns:manage`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "organization", + "x-excluded-from-public": false, + "x-required-scope": "campaigns:manage", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/v1/optouts/{phone}": { + "delete": { + "operationId": "deleteOptOut", + "tags": [ + "optouts" + ], + "summary": "Delete opt out", + "description": "Public Management API. Organization API-key callers require `campaigns:manage`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "organization", + "x-excluded-from-public": false, + "x-required-scope": "campaigns:manage", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "phone", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/v1/billing": { + "get": { + "operationId": "getBilling", + "tags": [ + "billing" + ], + "summary": "Get billing", + "description": "Public Management API. Organization API-key callers require `sessions:read`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "organization", + "x-excluded-from-public": false, + "x-required-scope": "sessions:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/v1/billing/usage": { + "get": { + "operationId": "listUsageMeters", + "tags": [ + "billing" + ], + "summary": "List usage meters", + "description": "Public Management API. Organization API-key callers require `sessions:read`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "organization", + "x-excluded-from-public": false, + "x-required-scope": "sessions:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/v1/billing/transactions": { + "get": { + "operationId": "listBillingTransactions", + "tags": [ + "billing" + ], + "summary": "List billing transactions", + "description": "Public Management API. Organization API-key callers require `sessions:read`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "organization", + "x-excluded-from-public": false, + "x-required-scope": "sessions:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/v1/billing/pricing": { + "get": { + "operationId": "listTierPricing", + "tags": [ + "billing" + ], + "summary": "List tier pricing", + "description": "Public Management API. Organization API-key callers require `sessions:read`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "organization", + "x-excluded-from-public": false, + "x-required-scope": "sessions:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/v1/billing/reminders": { + "patch": { + "operationId": "updateBillingReminderSettings", + "tags": [ + "billing" + ], + "summary": "Update billing reminder settings", + "description": "Public Management API. Organization API-key callers require `sessions:manage`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "organization", + "x-excluded-from-public": false, + "x-required-scope": "sessions:manage", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/v1/organization": { + "get": { + "operationId": "getOrganization", + "tags": [ + "organization" + ], + "summary": "Get organization", + "description": "Public Management API. Organization API-key callers require `sessions:read`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "organization", + "x-excluded-from-public": false, + "x-required-scope": "sessions:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + }, + "patch": { + "operationId": "updateOrganization", + "tags": [ + "organization" + ], + "summary": "Update organization", + "description": "Public Management API. Requires a verified dashboard bearer and current organization authorization. The signed-in member must be an organization owner or admin. Organization keys and project tokens are not accepted.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": false, + "x-dashboard-only": true, + "x-required-organization-role": "owner_or_admin", + "security": [ + { + "ConsoleSession": [] + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/v1/projects": { + "get": { + "operationId": "listProjects", + "tags": [ + "projects" + ], + "summary": "List projects", + "description": "Public Management API. Organization API-key callers require `sessions:read`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "organization", + "x-excluded-from-public": false, + "x-required-scope": "sessions:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + }, + "post": { + "operationId": "createProject", + "tags": [ + "projects" + ], + "summary": "Create project", + "description": "Public Management API. Organization API-key callers require `sessions:manage`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "organization", + "x-excluded-from-public": false, + "x-required-scope": "sessions:manage", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/v1/projects/{projectId}/promote": { + "post": { + "operationId": "requestProductionEnrollment", + "tags": [ + "projects" + ], + "summary": "Request production enrollment", + "description": "Creates a durable production-enrollment operation. The project stays in development until provisioning succeeds. Poll the returned operationId for progress.\n\nOrganization API-key callers require `sessions:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "sessions:manage", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "projectId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProductionEnrollmentRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/ProductionEnrollmentResult" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + }, + "409": { + "$ref": "#/components/responses/Conflict" + } + } + } + }, + "/v1/projects/{projectId}/customers/status": { + "get": { + "operationId": "getCustomersStatus", + "tags": [ + "customers" + ], + "summary": "Get Customers status", + "description": "Returns whether Customers is enabled for the exact project and its protected default Customer when enabled.\n\nOrganization API-key callers require `customers:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "customers:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "projectId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/CustomersStatus" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/v1/projects/{projectId}/customers/enable": { + "post": { + "operationId": "enableCustomers", + "tags": [ + "customers" + ], + "summary": "Enable Customers", + "description": "Enables Customers once, creates the default Customer, and assigns every existing Number in the project to it atomically.\n\nOrganization API-key callers require `customers:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "customers:manage", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "projectId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "Idempotency-Key", + "in": "header", + "required": true, + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 255 + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/CustomersEnablement" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + }, + "409": { + "$ref": "#/components/responses/Conflict" + } + } + } + }, + "/v1/projects/{projectId}/production-enrollments/{operationId}/approve": { + "post": { + "operationId": "approveProductionEnrollment", + "tags": [ + "projects" + ], + "summary": "Approve production enrollment", + "description": "Resumes a production-enrollment operation that requires approval.\n\nOrganization API-key callers require `sessions:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "sessions:manage", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "projectId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "operationId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/ProductionEnrollmentCommandResult" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "409": { + "$ref": "#/components/responses/Conflict" + } + } + } + }, + "/v1/projects/{projectId}/production-enrollments/{operationId}/cancel": { + "post": { + "operationId": "cancelProductionEnrollment", + "tags": [ + "projects" + ], + "summary": "Cancel production enrollment", + "description": "Requests cancellation of an active production-enrollment operation. Provisioned resources are compensated before cancellation completes.\n\nOrganization API-key callers require `sessions:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "sessions:manage", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "projectId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "operationId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/ProductionEnrollmentCommandResult" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "409": { + "$ref": "#/components/responses/Conflict" + } + } + } + }, + "/v1/webhooks": { + "get": { + "operationId": "listOrganizationWebhooks", + "tags": [ + "webhooks" + ], + "summary": "List organization webhooks", + "description": "Lists only organization-owned webhook endpoints. Project-owned endpoints are excluded.\n\nOrganization API-key callers require `webhooks:read`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "organization", + "x-excluded-from-public": false, + "x-required-scope": "webhooks:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "eventType", + "in": "query", + "required": false, + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 128 + } + }, + { + "name": "enabled", + "in": "query", + "required": false, + "schema": { + "type": "boolean" + } + }, + { + "name": "limit", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 25 + } + }, + { + "name": "cursor", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/OrganizationWebhook" + } + }, + "page": { + "$ref": "#/components/schemas/CursorPageMetadata" + } + }, + "required": [ + "data", + "page" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + } + } + }, + "post": { + "operationId": "createOrganizationWebhook", + "tags": [ + "webhooks" + ], + "summary": "Create an organization webhook", + "description": "Creates an organization-owned webhook and returns its generated signing secret once.\n\nOrganization API-key callers require `webhooks:manage`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "organization", + "x-excluded-from-public": false, + "x-required-scope": "webhooks:manage", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "Idempotency-Key", + "in": "header", + "required": true, + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 255 + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateOrganizationWebhookInput" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/OrganizationWebhookCreationReceipt" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "409": { + "$ref": "#/components/responses/Conflict" + } + } + } + }, + "/v1/webhooks/{webhookId}": { + "get": { + "operationId": "getOrganizationWebhook", + "tags": [ + "webhooks" + ], + "summary": "Get an organization webhook", + "description": "Returns one organization-owned webhook without secret values.\n\nOrganization API-key callers require `webhooks:read`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "organization", + "x-excluded-from-public": false, + "x-required-scope": "webhooks:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "webhookId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/OrganizationWebhook" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + }, + "patch": { + "operationId": "updateOrganizationWebhook", + "tags": [ + "webhooks" + ], + "summary": "Update an organization webhook", + "description": "Updates settings without rotating the signing secret.\n\nOrganization API-key callers require `webhooks:manage`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "organization", + "x-excluded-from-public": false, + "x-required-scope": "webhooks:manage", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "webhookId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "Idempotency-Key", + "in": "header", + "required": true, + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 255 + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateOrganizationWebhookInput" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/OrganizationWebhookMutationReceipt" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + }, + "409": { + "$ref": "#/components/responses/Conflict" + } + } + }, + "delete": { + "operationId": "deleteOrganizationWebhook", + "tags": [ + "webhooks" + ], + "summary": "Delete an organization webhook", + "description": "Deletes one organization-owned webhook.\n\nOrganization API-key callers require `webhooks:manage`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "organization", + "x-excluded-from-public": false, + "x-required-scope": "webhooks:manage", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "webhookId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "Idempotency-Key", + "in": "header", + "required": true, + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 255 + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/OrganizationWebhookDeletionReceipt" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + }, + "409": { + "$ref": "#/components/responses/Conflict" + } + } + } + }, + "/v1/webhooks/{webhookId}/secret-rotations": { + "post": { + "operationId": "rotateOrganizationWebhookSecret", + "tags": [ + "webhooks" + ], + "summary": "Rotate an organization webhook secret", + "description": "Rotates the signing secret and returns the new secret once.\n\nOrganization API-key callers require `webhooks:manage`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "organization", + "x-excluded-from-public": false, + "x-required-scope": "webhooks:manage", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "webhookId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "Idempotency-Key", + "in": "header", + "required": true, + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 255 + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RotateWebhookSecretInput" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/OrganizationWebhookSecretRotationReceipt" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + }, + "409": { + "$ref": "#/components/responses/Conflict" + } + } + } + }, + "/v1/webhooks/{webhookId}/tests": { + "post": { + "operationId": "testOrganizationWebhook", + "tags": [ + "webhooks" + ], + "summary": "Send an organization webhook test", + "description": "Creates a synthetic organization event and a traceable webhook delivery.\n\nOrganization API-key callers require `webhooks:manage`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "organization", + "x-excluded-from-public": false, + "x-required-scope": "webhooks:manage", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "webhookId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "Idempotency-Key", + "in": "header", + "required": true, + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 255 + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TestWebhookInput" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/OrganizationWebhookTestReceipt" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + }, + "409": { + "$ref": "#/components/responses/Conflict" + } + } + } + }, + "/v1/projects/{projectId}/webhooks": { + "get": { + "operationId": "listProjectWebhooks", + "tags": [ + "webhooks" + ], + "summary": "List project webhooks", + "description": "Lists webhooks owned by the exact project in the route.\n\nOrganization API-key callers require `webhooks:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "webhooks:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "projectId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "eventType", + "in": "query", + "required": false, + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 128 + } + }, + { + "name": "enabled", + "in": "query", + "required": false, + "schema": { + "type": "boolean" + } + }, + { + "name": "limit", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 25 + } + }, + { + "name": "cursor", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ProjectWebhook" + } + }, + "page": { + "$ref": "#/components/schemas/CursorPageMetadata" + } + }, + "required": [ + "data", + "page" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + }, + "post": { + "operationId": "createProjectWebhook", + "tags": [ + "webhooks" + ], + "summary": "Create a project webhook", + "description": "Creates a project-owned webhook and returns its generated signing secret once.\n\nOrganization API-key callers require `webhooks:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "webhooks:manage", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "projectId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "Idempotency-Key", + "in": "header", + "required": true, + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 255 + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateProjectWebhookInput" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/ProjectWebhookCreationReceipt" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + }, + "409": { + "$ref": "#/components/responses/Conflict" + } + } + } + }, + "/v1/projects/{projectId}/webhooks/{webhookId}": { + "get": { + "operationId": "getProjectWebhook", + "tags": [ + "webhooks" + ], + "summary": "Get a project webhook", + "description": "Returns one webhook owned by the exact project without secret values.\n\nOrganization API-key callers require `webhooks:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "webhooks:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "projectId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "webhookId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/ProjectWebhook" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + }, + "patch": { + "operationId": "updateProjectWebhook", + "tags": [ + "webhooks" + ], + "summary": "Update a project webhook", + "description": "Updates settings without rotating the signing secret.\n\nOrganization API-key callers require `webhooks:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "webhooks:manage", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "projectId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "webhookId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "Idempotency-Key", + "in": "header", + "required": true, + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 255 + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateProjectWebhookInput" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/ProjectWebhookMutationReceipt" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + }, + "409": { + "$ref": "#/components/responses/Conflict" + } + } + }, + "delete": { + "operationId": "deleteProjectWebhook", + "tags": [ + "webhooks" + ], + "summary": "Delete a project webhook", + "description": "Deletes one webhook owned by the exact project.\n\nOrganization API-key callers require `webhooks:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "webhooks:manage", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "projectId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "webhookId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "Idempotency-Key", + "in": "header", + "required": true, + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 255 + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/ProjectWebhookDeletionReceipt" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + }, + "409": { + "$ref": "#/components/responses/Conflict" + } + } + } + }, + "/v1/projects/{projectId}/webhooks/{webhookId}/secret-rotations": { + "post": { + "operationId": "rotateProjectWebhookSecret", + "tags": [ + "webhooks" + ], + "summary": "Rotate a project webhook secret", + "description": "Rotates the signing secret and returns the new secret once.\n\nOrganization API-key callers require `webhooks:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "webhooks:manage", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "projectId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "webhookId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "Idempotency-Key", + "in": "header", + "required": true, + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 255 + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RotateWebhookSecretInput" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/ProjectWebhookSecretRotationReceipt" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + }, + "409": { + "$ref": "#/components/responses/Conflict" + } + } + } + }, + "/v1/projects/{projectId}/webhooks/{webhookId}/tests": { + "post": { + "operationId": "testProjectWebhook", + "tags": [ + "webhooks" + ], + "summary": "Send a project webhook test", + "description": "Creates a synthetic project event and a traceable webhook delivery. An optional complete native envelope is accepted only with an exact HMS-enabled project session.\n\nOrganization API-key callers require `webhooks:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "webhooks:manage", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "projectId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "webhookId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "Idempotency-Key", + "in": "header", + "required": true, + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 255 + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TestWebhookInput" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/ProjectWebhookTestReceipt" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + }, + "409": { + "$ref": "#/components/responses/Conflict" + }, + "422": { + "$ref": "#/components/responses/Unprocessable" + } + } + } + }, + "/v1/events": { + "get": { + "operationId": "listOrganizationEvents", + "tags": [ + "events" + ], + "summary": "List organization events", + "description": "Lists organization-owned event metadata. Project-owned events are excluded.\n\nOrganization API-key callers require `events:read`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "organization", + "x-excluded-from-public": false, + "x-required-scope": "events:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "type", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "since", + "in": "query", + "required": false, + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "until", + "in": "query", + "required": false, + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "limit", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 25 + } + }, + { + "name": "cursor", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/OrganizationEvent" + } + }, + "page": { + "$ref": "#/components/schemas/CursorPageMetadata" + } + }, + "required": [ + "data", + "page" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + } + } + } + }, + "/v1/events/{eventId}": { + "get": { + "operationId": "getOrganizationEvent", + "tags": [ + "events" + ], + "summary": "Get an organization event", + "description": "Returns one organization-owned event and includes exact payload bytes only when requested and available.\n\nOrganization API-key callers require `events:read`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "organization", + "x-excluded-from-public": false, + "x-required-scope": "events:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "eventId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "includePayload", + "in": "query", + "required": false, + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/OrganizationEvent" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/v1/events/{eventId}/replays": { + "post": { + "operationId": "replayOrganizationEvent", + "tags": [ + "events" + ], + "summary": "Replay an organization event", + "description": "Creates a new logical delivery for a retained organization event.\n\nOrganization API-key callers require `events:replay`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "organization", + "x-excluded-from-public": false, + "x-required-scope": "events:replay", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "eventId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "Idempotency-Key", + "in": "header", + "required": true, + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 255 + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ReplayEventInput" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/OrganizationEventReplayReceipt" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + }, + "409": { + "$ref": "#/components/responses/Conflict" + }, + "422": { + "$ref": "#/components/responses/Unprocessable" + } + } + } + }, + "/v1/projects/{projectId}/events": { + "get": { + "operationId": "listProjectEvents", + "tags": [ + "events" + ], + "summary": "List project events", + "description": "Lists event metadata owned by the exact project in the route.\n\nOrganization API-key callers require `events:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "events:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "projectId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "type", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "since", + "in": "query", + "required": false, + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "until", + "in": "query", + "required": false, + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "limit", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 25 + } + }, + { + "name": "cursor", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ProjectEvent" + } + }, + "page": { + "$ref": "#/components/schemas/CursorPageMetadata" + } + }, + "required": [ + "data", + "page" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/v1/projects/{projectId}/events/{eventId}": { + "get": { + "operationId": "getProjectEvent", + "tags": [ + "events" + ], + "summary": "Get a project event", + "description": "Returns one event owned by the exact project and includes exact payload bytes only when requested and available.\n\nOrganization API-key callers require `events:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "events:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "projectId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "eventId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "includePayload", + "in": "query", + "required": false, + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/ProjectEvent" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/v1/projects/{projectId}/events/{eventId}/replays": { + "post": { + "operationId": "replayProjectEvent", + "tags": [ + "events" + ], + "summary": "Replay a project event", + "description": "Creates a new logical delivery for a retained event owned by the exact project.\n\nOrganization API-key callers require `events:replay`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "events:replay", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "projectId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "eventId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "Idempotency-Key", + "in": "header", + "required": true, + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 255 + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ReplayEventInput" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/ProjectEventReplayReceipt" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + }, + "409": { + "$ref": "#/components/responses/Conflict" + }, + "422": { + "$ref": "#/components/responses/Unprocessable" + } + } + } + }, + "/v1/webhook-deliveries": { + "get": { + "operationId": "listOrganizationWebhookDeliveries", + "tags": [ + "webhook deliveries" + ], + "summary": "List organization webhook deliveries", + "description": "Lists logical deliveries for organization-owned webhooks. Project-owned deliveries are excluded.\n\nOrganization API-key callers require `webhook-deliveries:read`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "organization", + "x-excluded-from-public": false, + "x-required-scope": "webhook-deliveries:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "webhookId", + "in": "query", + "required": false, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "eventId", + "in": "query", + "required": false, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "status", + "in": "query", + "required": false, + "schema": { + "type": "string", + "enum": [ + "pending", + "delivering", + "retrying", + "succeeded", + "failed" + ] + } + }, + { + "name": "since", + "in": "query", + "required": false, + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "until", + "in": "query", + "required": false, + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "limit", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 25 + } + }, + { + "name": "cursor", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/OrganizationWebhookDelivery" + } + }, + "page": { + "$ref": "#/components/schemas/CursorPageMetadata" + } + }, + "required": [ + "data", + "page" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + } + } + } + }, + "/v1/webhook-deliveries/{deliveryId}": { + "get": { + "operationId": "getOrganizationWebhookDelivery", + "tags": [ + "webhook deliveries" + ], + "summary": "Get an organization webhook delivery", + "description": "Returns one logical organization webhook delivery.\n\nOrganization API-key callers require `webhook-deliveries:read`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "organization", + "x-excluded-from-public": false, + "x-required-scope": "webhook-deliveries:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "deliveryId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/OrganizationWebhookDelivery" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/v1/webhook-deliveries/{deliveryId}/retry": { + "post": { + "operationId": "retryOrganizationWebhookDelivery", + "tags": [ + "webhook deliveries" + ], + "summary": "Retry an organization webhook delivery", + "description": "Appends a new immutable attempt to the same logical delivery.\n\nOrganization API-key callers require `webhook-deliveries:retry`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "organization", + "x-excluded-from-public": false, + "x-required-scope": "webhook-deliveries:retry", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "deliveryId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "Idempotency-Key", + "in": "header", + "required": true, + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 255 + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/OrganizationWebhookDeliveryRetryReceipt" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + }, + "409": { + "$ref": "#/components/responses/Conflict" + }, + "422": { + "$ref": "#/components/responses/Unprocessable" + } + } + } + }, + "/v1/webhook-deliveries/{deliveryId}/attempts": { + "get": { + "operationId": "listOrganizationWebhookDeliveryAttempts", + "tags": [ + "webhook deliveries" + ], + "summary": "List organization delivery attempts", + "description": "Lists immutable network attempts for one organization webhook delivery.\n\nOrganization API-key callers require `webhook-deliveries:read`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "organization", + "x-excluded-from-public": false, + "x-required-scope": "webhook-deliveries:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "deliveryId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "limit", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 25 + } + }, + { + "name": "cursor", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/OrganizationWebhookDeliveryAttempt" + } + }, + "page": { + "$ref": "#/components/schemas/CursorPageMetadata" + } + }, + "required": [ + "data", + "page" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/v1/webhook-deliveries/{deliveryId}/attempts/{attemptId}": { + "get": { + "operationId": "getOrganizationWebhookDeliveryAttempt", + "tags": [ + "webhook deliveries" + ], + "summary": "Get organization delivery attempt", + "description": "Returns one immutable network attempt.\n\nOrganization API-key callers require `webhook-deliveries:read`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "organization", + "x-excluded-from-public": false, + "x-required-scope": "webhook-deliveries:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "deliveryId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "attemptId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/OrganizationWebhookDeliveryAttempt" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/v1/projects/{projectId}/webhook-deliveries": { + "get": { + "operationId": "listProjectWebhookDeliveries", + "tags": [ + "webhook deliveries" + ], + "summary": "List project webhook deliveries", + "description": "Lists logical webhook deliveries owned by the exact project in the route.\n\nOrganization API-key callers require `webhook-deliveries:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "webhook-deliveries:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "projectId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "webhookId", + "in": "query", + "required": false, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "eventId", + "in": "query", + "required": false, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "status", + "in": "query", + "required": false, + "schema": { + "type": "string", + "enum": [ + "pending", + "delivering", + "retrying", + "succeeded", + "failed" + ] + } + }, + { + "name": "since", + "in": "query", + "required": false, + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "until", + "in": "query", + "required": false, + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "limit", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 25 + } + }, + { + "name": "cursor", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ProjectWebhookDelivery" + } + }, + "page": { + "$ref": "#/components/schemas/CursorPageMetadata" + } + }, + "required": [ + "data", + "page" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/v1/projects/{projectId}/webhook-deliveries/{deliveryId}": { + "get": { + "operationId": "getProjectWebhookDelivery", + "tags": [ + "webhook deliveries" + ], + "summary": "Get a project webhook delivery", + "description": "Returns one logical webhook delivery owned by the exact project.\n\nOrganization API-key callers require `webhook-deliveries:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "webhook-deliveries:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "projectId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "deliveryId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/ProjectWebhookDelivery" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/v1/projects/{projectId}/webhook-deliveries/{deliveryId}/retry": { + "post": { + "operationId": "retryProjectWebhookDelivery", + "tags": [ + "webhook deliveries" + ], + "summary": "Retry a project webhook delivery", + "description": "Appends a new immutable attempt to the same logical delivery owned by the exact project.\n\nOrganization API-key callers require `webhook-deliveries:retry`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "webhook-deliveries:retry", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "projectId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "deliveryId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "Idempotency-Key", + "in": "header", + "required": true, + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 255 + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/ProjectWebhookDeliveryRetryReceipt" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + }, + "409": { + "$ref": "#/components/responses/Conflict" + }, + "422": { + "$ref": "#/components/responses/Unprocessable" + } + } + } + }, + "/v1/projects/{projectId}/webhook-deliveries/{deliveryId}/attempts": { + "get": { + "operationId": "listProjectWebhookDeliveryAttempts", + "tags": [ + "webhook deliveries" + ], + "summary": "List project webhook delivery attempts", + "description": "Lists immutable network attempts for one project webhook delivery.\n\nOrganization API-key callers require `webhook-deliveries:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "webhook-deliveries:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "projectId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "deliveryId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "limit", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 25 + } + }, + { + "name": "cursor", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ProjectWebhookDeliveryAttempt" + } + }, + "page": { + "$ref": "#/components/schemas/CursorPageMetadata" + } + }, + "required": [ + "data", + "page" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/v1/projects/{projectId}/webhook-deliveries/{deliveryId}/attempts/{attemptId}": { + "get": { + "operationId": "getProjectWebhookDeliveryAttempt", + "tags": [ + "webhook deliveries" + ], + "summary": "Get a project webhook delivery attempt", + "description": "Returns one immutable network attempt owned by the exact project.\n\nOrganization API-key callers require `webhook-deliveries:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "webhook-deliveries:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "projectId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "deliveryId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "attemptId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/ProjectWebhookDeliveryAttempt" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/v1/operations": { + "get": { + "operationId": "listOrganizationOperations", + "tags": [ + "operations" + ], + "summary": "List organization operations", + "description": "Lists only organization-owned asynchronous operations. Project-owned operations are excluded.\n\nOrganization API-key callers require `operations:read`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "organization", + "x-excluded-from-public": false, + "x-required-scope": "operations:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "status", + "in": "query", + "required": false, + "schema": { + "type": "string", + "enum": [ + "pending", + "running", + "action_required", + "cancelling", + "succeeded", + "failed", + "cancelled" + ] + } + }, + { + "name": "kind", + "in": "query", + "required": false, + "schema": { + "type": "string", + "enum": [ + "auth_projection_repair", + "session_lifecycle", + "auth_session_purge", + "label_projection_purge", + "billing_reconciliation", + "auto_top_up", + "campaign", + "production_enrollment", + "retention_sweep", + "webhook_redrive" + ] + } + }, + { + "name": "resourceType", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "resourceId", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "since", + "in": "query", + "required": false, + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "until", + "in": "query", + "required": false, + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "limit", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 25 + } + }, + { + "name": "cursor", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/OrganizationOperation" + } + }, + "page": { + "$ref": "#/components/schemas/CursorPageMetadata" + } + }, + "required": [ + "data", + "page" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + } + } + } + }, + "/v1/operations/{operationId}": { + "get": { + "operationId": "getOrganizationOperation", + "tags": [ + "operations" + ], + "summary": "Get an organization operation", + "description": "Returns one organization-owned asynchronous operation.\n\nOrganization API-key callers require `operations:read`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "organization", + "x-excluded-from-public": false, + "x-required-scope": "operations:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "operationId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/OrganizationOperation" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/v1/operations/{operationId}/transitions": { + "get": { + "operationId": "listOrganizationOperationTransitions", + "tags": [ + "operations" + ], + "summary": "List organization operation transitions", + "description": "Lists immutable transitions for one organization-owned operation in ascending sequence.\n\nOrganization API-key callers require `operations:read`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "organization", + "x-excluded-from-public": false, + "x-required-scope": "operations:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "operationId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "afterSequence", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + }, + { + "name": "limit", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 25 + } + }, + { + "name": "cursor", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/OperationTransition" + } + }, + "page": { + "$ref": "#/components/schemas/CursorPageMetadata" + } + }, + "required": [ + "data", + "page" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/v1/operations/{operationId}/cancel": { + "post": { + "operationId": "cancelOrganizationOperation", + "tags": [ + "operations" + ], + "summary": "Cancel an organization operation", + "description": "Requests cancellation after transactionally rechecking that the operation is cancellable.\n\nOrganization API-key callers require `operations:cancel`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "organization", + "x-excluded-from-public": false, + "x-required-scope": "operations:cancel", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "operationId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "Idempotency-Key", + "in": "header", + "required": true, + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 255 + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/OrganizationOperationCancellationReceipt" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + }, + "409": { + "$ref": "#/components/responses/OperationCancellationConflict" + } + } + } + }, + "/v1/projects/{projectId}/operations": { + "get": { + "operationId": "listProjectOperations", + "tags": [ + "operations" + ], + "summary": "List project operations", + "description": "Lists asynchronous operations owned by the exact project in the route.\n\nOrganization API-key callers require `operations:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "operations:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "projectId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "status", + "in": "query", + "required": false, + "schema": { + "type": "string", + "enum": [ + "pending", + "running", + "action_required", + "cancelling", + "succeeded", + "failed", + "cancelled" + ] + } + }, + { + "name": "kind", + "in": "query", + "required": false, + "schema": { + "type": "string", + "enum": [ + "auth_projection_repair", + "session_lifecycle", + "auth_session_purge", + "label_projection_purge", + "billing_reconciliation", + "auto_top_up", + "campaign", + "production_enrollment", + "retention_sweep", + "webhook_redrive" + ] + } + }, + { + "name": "resourceType", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "resourceId", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "since", + "in": "query", + "required": false, + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "until", + "in": "query", + "required": false, + "schema": { + "type": "string", + "format": "date-time" + } + }, + { + "name": "limit", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 25 + } + }, + { + "name": "cursor", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ProjectOperation" + } + }, + "page": { + "$ref": "#/components/schemas/CursorPageMetadata" + } + }, + "required": [ + "data", + "page" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/v1/projects/{projectId}/operations/{operationId}": { + "get": { + "operationId": "getProjectOperation", + "tags": [ + "operations" + ], + "summary": "Get a project operation", + "description": "Returns one asynchronous operation owned by the exact project in the route.\n\nOrganization API-key callers require `operations:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "operations:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "projectId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "operationId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/ProjectOperation" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/v1/projects/{projectId}/operations/{operationId}/transitions": { + "get": { + "operationId": "listProjectOperationTransitions", + "tags": [ + "operations" + ], + "summary": "List project operation transitions", + "description": "Lists immutable transitions for one project-owned operation in ascending sequence.\n\nOrganization API-key callers require `operations:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "operations:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "projectId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "operationId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "afterSequence", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + }, + { + "name": "limit", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 25 + } + }, + { + "name": "cursor", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/OperationTransition" + } + }, + "page": { + "$ref": "#/components/schemas/CursorPageMetadata" + } + }, + "required": [ + "data", + "page" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/v1/projects/{projectId}/operations/{operationId}/cancel": { + "post": { + "operationId": "cancelProjectOperation", + "tags": [ + "operations" + ], + "summary": "Cancel a project operation", + "description": "Requests cancellation for an operation in the exact project after transactionally rechecking that it is cancellable.\n\nOrganization API-key callers require `operations:cancel`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "operations:cancel", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "projectId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "operationId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "Idempotency-Key", + "in": "header", + "required": true, + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 255 + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/ProjectOperationCancellationReceipt" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + }, + "409": { + "$ref": "#/components/responses/OperationCancellationConflict" + } + } + } + }, + "/v1/customers": { + "get": { + "operationId": "listCustomers", + "tags": [ + "customers" + ], + "summary": "List Customers", + "description": "Lists masked Customer summaries in the exact authenticated project with cursor pagination and filters.\n\nOrganization API-key callers require `customers:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "customers:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "projectId", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "cursor", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "limit", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 25 + } + }, + { + "name": "search", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "status", + "in": "query", + "required": false, + "schema": { + "type": "string", + "enum": [ + "active", + "archiving", + "archived", + "all" + ] + } + }, + { + "name": "isDefault", + "in": "query", + "required": false, + "schema": { + "type": "boolean" + } + }, + { + "name": "hasNumbers", + "in": "query", + "required": false, + "schema": { + "type": "boolean" + } + }, + { + "name": "needsAttention", + "in": "query", + "required": false, + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CustomerSummary" + } + }, + "page": { + "$ref": "#/components/schemas/CursorPageMetadata" + } + }, + "required": [ + "data", + "page" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + }, + "post": { + "operationId": "createCustomer", + "tags": [ + "customers" + ], + "summary": "Create a Customer", + "description": "Creates a Customer with optional name, phone, and caller-defined external identifier.\n\nOrganization API-key callers require `customers:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "customers:manage", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "Idempotency-Key", + "in": "header", + "required": true, + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 255 + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateCustomerRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/Customer" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + }, + "409": { + "$ref": "#/components/responses/Conflict" + } + } + } + }, + "/v1/customers/{customerId}": { + "get": { + "operationId": "getCustomer", + "tags": [ + "customers" + ], + "summary": "Get a Customer", + "description": "Returns one Customer from the exact authenticated project.\n\nOrganization API-key callers require `customers:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "customers:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "customerId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "projectId", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/Customer" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + }, + "patch": { + "operationId": "updateCustomer", + "tags": [ + "customers" + ], + "summary": "Update a Customer", + "description": "Updates supplied Customer profile fields. Null clears an optional field.\n\nOrganization API-key callers require `customers:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "customers:manage", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "customerId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateCustomerRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/Customer" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + }, + "409": { + "$ref": "#/components/responses/Conflict" + } + } + } + }, + "/v1/customers/{customerId}/archive": { + "post": { + "operationId": "archiveCustomer", + "tags": [ + "customers" + ], + "summary": "Archive a Customer", + "description": "Archives a non-default Customer. The default Customer cannot be archived.\n\nOrganization API-key callers require `customers:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "customers:manage", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "customerId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "Idempotency-Key", + "in": "header", + "required": true, + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 255 + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomerProjectRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/Customer" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + }, + "409": { + "$ref": "#/components/responses/Conflict" + } + } + } + }, + "/v1/customers/{customerId}/restore": { + "post": { + "operationId": "restoreCustomer", + "tags": [ + "customers" + ], + "summary": "Restore a Customer", + "description": "Restores an archived Customer.\n\nOrganization API-key callers require `customers:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "customers:manage", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "customerId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "Idempotency-Key", + "in": "header", + "required": true, + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 255 + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomerProjectRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/Customer" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + }, + "409": { + "$ref": "#/components/responses/Conflict" + } + } + } + }, + "/v1/customers/{customerId}/numbers": { + "get": { + "operationId": "listCustomerNumbers", + "tags": [ + "customers" + ], + "summary": "List Customer Numbers", + "description": "Lists Numbers assigned to one Customer in the exact project.\n\nOrganization API-key callers require `customers:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "customers:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "customerId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "projectId", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CustomerNumber" + } + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/v1/customers/{customerId}/events": { + "get": { + "operationId": "listCustomerEvents", + "tags": [ + "customers" + ], + "summary": "List recent Customer events", + "description": "Lists the newest Customer lifecycle events with safe metadata. Actor identities, message content, phone values, invitation tokens, and URLs are excluded.\n\nOrganization API-key callers require `customers:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "customers:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "customerId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "projectId", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "limit", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 25 + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CustomerEvent" + } + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/v1/customers/{customerId}/pairing-links": { + "post": { + "operationId": "createCustomerPairingLink", + "tags": [ + "customers" + ], + "summary": "Create a Customer pairing link", + "description": "Creates a revocable Customer invitation. The raw URL is returned only in this response.\n\nOrganization API-key callers require `customers:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "customers:manage", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "customerId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "Idempotency-Key", + "in": "header", + "required": true, + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 255 + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateCustomerPairingLinkRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/CreatedCustomerPairingLink" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + }, + "409": { + "$ref": "#/components/responses/Conflict" + } + } + }, + "get": { + "operationId": "listCustomerPairingLinks", + "tags": [ + "customers" + ], + "summary": "List Customer pairing links", + "description": "Lists safe pairing-link metadata. Raw invitation tokens and URLs are never returned.\n\nOrganization API-key callers require `customers:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "customers:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "customerId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "projectId", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CustomerPairingLink" + } + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/v1/customers/{customerId}/pairing-links/{pairingLinkId}": { + "delete": { + "operationId": "revokeCustomerPairingLink", + "tags": [ + "customers" + ], + "summary": "Revoke a Customer pairing link", + "description": "Revokes an open pairing link.\n\nOrganization API-key callers require `customers:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "customers:manage", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "customerId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "pairingLinkId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "projectId", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/CustomerPairingLink" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + }, + "409": { + "$ref": "#/components/responses/Conflict" + } + } + } + }, + "/v1/customers/{customerId}/numbers/{sessionId}/transfer": { + "post": { + "operationId": "transferCustomerNumber", + "tags": [ + "customers" + ], + "summary": "Transfer a Customer Number", + "description": "Atomically transfers one eligible Number from the explicitly confirmed source Customer to the destination Customer.\n\nOrganization API-key callers require `customers:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "customers:manage", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "customerId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "sessionId", + "in": "path", + "required": true, + "description": "Database session UUID or stable session slug.", + "schema": { + "$ref": "#/components/schemas/SessionIdentifier" + } + }, + { + "name": "Idempotency-Key", + "in": "header", + "required": true, + "schema": { + "type": "string", + "minLength": 1, + "maxLength": 255 + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TransferCustomerNumberRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/CustomerNumber" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + }, + "409": { + "$ref": "#/components/responses/Conflict" + } + } + } + }, + "/v1/members": { + "get": { + "operationId": "listMembers", + "tags": [ + "members" + ], + "summary": "List members", + "description": "Public Management API. Organization API-key callers require `sessions:read`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "organization", + "x-excluded-from-public": false, + "x-required-scope": "sessions:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/v1/members/invites": { + "post": { + "operationId": "inviteMember", + "tags": [ + "members" + ], + "summary": "Invite member", + "description": "Public Management API. Requires a verified dashboard bearer and current organization authorization. The signed-in member must be an organization owner or admin. Organization keys and project tokens are not accepted.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": false, + "x-dashboard-only": true, + "x-required-organization-role": "owner_or_admin", + "security": [ + { + "ConsoleSession": [] + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/v1/members/{memberId}": { + "patch": { + "operationId": "updateMemberRole", + "tags": [ + "members" + ], + "summary": "Update member role", + "description": "Public Management API. Requires a verified dashboard bearer and current organization authorization. The signed-in member must be an organization owner or admin. Organization keys and project tokens are not accepted.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": false, + "x-dashboard-only": true, + "x-required-organization-role": "owner_or_admin", + "security": [ + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "memberId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + }, + "delete": { + "operationId": "deleteMember", + "tags": [ + "members" + ], + "summary": "Delete member", + "description": "Public Management API. Requires a verified dashboard bearer and current organization authorization. The signed-in member must be an organization owner or admin. Organization keys and project tokens are not accepted.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": false, + "x-dashboard-only": true, + "x-required-organization-role": "owner_or_admin", + "security": [ + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "memberId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/v1/keys": { + "get": { + "operationId": "listApiKeys", + "tags": [ + "keys" + ], + "summary": "List api keys", + "description": "Public Management API. Organization API-key callers require `sessions:read`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "organization", + "x-excluded-from-public": false, + "x-required-scope": "sessions:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/v1/keys/{keyId}": { + "delete": { + "operationId": "deactivateApiKey", + "tags": [ + "keys" + ], + "summary": "Deactivate api key", + "description": "Public Management API. Organization API-key callers require `sessions:manage`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "organization", + "x-excluded-from-public": false, + "x-required-scope": "sessions:manage", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "keyId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/v1/tokens": { + "get": { + "operationId": "listPolymorfaTokens", + "tags": [ + "tokens" + ], + "summary": "List polymorfa tokens", + "description": "Public Management API. Organization API-key callers require `sessions:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "sessions:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "projectId", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/v1/audit": { + "get": { + "operationId": "listAuditLogs", + "tags": [ + "audit" + ], + "summary": "List audit logs", + "description": "Public Management API. Organization API-key callers require `sessions:read`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "organization", + "x-excluded-from-public": false, + "x-required-scope": "sessions:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/v1/incidents": { + "get": { + "operationId": "listSecurityIncidents", + "tags": [ + "incidents" + ], + "summary": "List security incidents", + "description": "Public Management API. Organization API-key callers require `sessions:read`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "organization", + "x-excluded-from-public": false, + "x-required-scope": "sessions:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/v1/incidents/{incidentId}/acknowledge": { + "post": { + "operationId": "acknowledgeSecurityIncident", + "tags": [ + "incidents" + ], + "summary": "Acknowledge security incident", + "description": "Public Management API. Organization API-key callers require `sessions:manage`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "organization", + "x-excluded-from-public": false, + "x-required-scope": "sessions:manage", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "incidentId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/v1/media/{mediaId}": { + "get": { + "operationId": "getMediaUrl", + "tags": [ + "media" + ], + "summary": "Get media url", + "description": "Public Management API. Organization API-key callers require `media:read`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "organization", + "x-excluded-from-public": false, + "x-required-scope": "media:read", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "mediaId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + }, + "delete": { + "operationId": "deleteMedia", + "tags": [ + "media" + ], + "summary": "Delete media", + "description": "Public Management API. Organization API-key callers require `media:manage`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "organization", + "x-excluded-from-public": false, + "x-required-scope": "media:manage", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "mediaId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/v1/media/uploads": { + "post": { + "operationId": "createMediaUploadUrl", + "tags": [ + "media" + ], + "summary": "Create media upload url", + "description": "Public Management API. Organization API-key callers require `media:manage`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "organization", + "x-excluded-from-public": false, + "x-required-scope": "media:manage", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/v1/widget": { + "get": { + "operationId": "getWidgetSettings", + "tags": [ + "widget" + ], + "summary": "Get widget settings", + "description": "Public Management API. Organization API-key callers require `widget:create`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "widget:create", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "projectId", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + }, + "put": { + "operationId": "updateWidgetSettings", + "tags": [ + "widget" + ], + "summary": "Update widget settings", + "description": "Updates the widget settings for the authenticated organization and project.\n\nOrganization API-key callers require `widget:create`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "x-audience": "public", + "x-polymorfa-resource-boundary": "project", + "x-excluded-from-public": false, + "x-required-scope": "widget:create", + "security": [ + { + "ApiKeyAuth": [] + }, + { + "ConsoleSession": [] + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateWidgetSettingsRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "type": "object", + "additionalProperties": true + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + } + } + } + }, + "/console/keys": { + "post": { + "operationId": "mintForConsoleApiKey", + "tags": [ + "keys" + ], + "summary": "Mint for console api key", + "description": "**EXCLUDED from the public API** (`console`). Credential red line: a pmfa_ key must never mint a pmfa_ key. Human session only — keeps revocation meaningful.", + "x-audience": "console", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Credential red line: a pmfa_ key must never mint a pmfa_ key. Human session only — keeps revocation meaningful.", + "security": [ + { + "ConsoleSession": [] + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/console/billing/topup": { + "post": { + "operationId": "topUpBilling", + "tags": [ + "billing" + ], + "summary": "Top up billing", + "description": "**EXCLUDED from the public API** (`console`). Starts a Stripe Checkout browser redirect; human session only. API clients use auto-top-up.", + "x-audience": "console", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Starts a Stripe Checkout browser redirect; human session only. API clients use auto-top-up.", + "security": [ + { + "ConsoleSession": [] + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/console/organizations/{slug}": { + "get": { + "operationId": "getOrganizationBySlug", + "tags": [ + "organizations" + ], + "summary": "Get organization by slug", + "description": "**EXCLUDED from the public API** (`console`). Console org-switcher lookup; a key is already bound to one org.", + "x-audience": "console", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Console org-switcher lookup; a key is already bound to one org.", + "security": [ + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "slug", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/console/organization/avatar/uploads": { + "post": { + "operationId": "generateOrganizationAvatarUploadUrl", + "tags": [ + "organization" + ], + "summary": "Generate organization avatar upload url", + "description": "**EXCLUDED from the public API** (`console`). Browser logo-upload flow.", + "x-audience": "console", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Browser logo-upload flow.", + "security": [ + { + "ConsoleSession": [] + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/console/organization/avatar": { + "put": { + "operationId": "saveAvatarOrganization", + "tags": [ + "organization" + ], + "summary": "Save avatar organization", + "description": "**EXCLUDED from the public API** (`console`). Browser logo-upload flow.", + "x-audience": "console", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Browser logo-upload flow.", + "security": [ + { + "ConsoleSession": [] + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + }, + "delete": { + "operationId": "removeAvatarOrganization", + "tags": [ + "organization" + ], + "summary": "Remove avatar organization", + "description": "**EXCLUDED from the public API** (`console`). Browser logo-upload flow.", + "x-audience": "console", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Browser logo-upload flow.", + "security": [ + { + "ConsoleSession": [] + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/console/organizations/ensure": { + "post": { + "operationId": "ensureForCurrentUserOrganization", + "tags": [ + "organizations" + ], + "summary": "Ensure for current user organization", + "description": "**EXCLUDED from the public API** (`console`). First-sign-in bootstrap for the session user.", + "x-audience": "console", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "First-sign-in bootstrap for the session user.", + "security": [ + { + "ConsoleSession": [] + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/console/projects/{projectId}/icon": { + "post": { + "operationId": "generateProjectUploadUrl", + "tags": [ + "projects" + ], + "summary": "Generate project upload url", + "description": "**EXCLUDED from the public API** (`console`). Browser icon-upload flow.", + "x-audience": "console", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Browser icon-upload flow.", + "security": [ + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "projectId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/console/profile": { + "get": { + "operationId": "getUserProfile", + "tags": [ + "profile" + ], + "summary": "Get user profile", + "description": "**EXCLUDED from the public API** (`console`). 'Current user' only exists for a session; keys are org-scoped, not user-scoped.", + "x-audience": "console", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "'Current user' only exists for a session; keys are org-scoped, not user-scoped.", + "security": [ + { + "ConsoleSession": [] + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + }, + "patch": { + "operationId": "updateUserProfileField", + "tags": [ + "profile" + ], + "summary": "Update user profile field", + "description": "**EXCLUDED from the public API** (`console`). Personal profile edit for the signed-in user.", + "x-audience": "console", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Personal profile edit for the signed-in user.", + "security": [ + { + "ConsoleSession": [] + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/console/profile/ensure": { + "post": { + "operationId": "ensureProfileUserProfile", + "tags": [ + "profile" + ], + "summary": "Ensure profile user profile", + "description": "**EXCLUDED from the public API** (`console`). Sign-in bootstrap.", + "x-audience": "console", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Sign-in bootstrap.", + "security": [ + { + "ConsoleSession": [] + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/console/teams": { + "get": { + "operationId": "listUserProfileTeams", + "tags": [ + "teams" + ], + "summary": "List user profile teams", + "description": "**EXCLUDED from the public API** (`console`). Session user's team switcher.", + "x-audience": "console", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Session user's team switcher.", + "security": [ + { + "ConsoleSession": [] + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/console/profile/avatar/uploads": { + "post": { + "operationId": "generateUserProfileAvatarUploadUrl", + "tags": [ + "profile" + ], + "summary": "Generate user profile avatar upload url", + "description": "**EXCLUDED from the public API** (`console`). Browser avatar-upload flow.", + "x-audience": "console", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Browser avatar-upload flow.", + "security": [ + { + "ConsoleSession": [] + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/console/profile/avatar": { + "put": { + "operationId": "saveAvatarUserProfile", + "tags": [ + "profile" + ], + "summary": "Save avatar user profile", + "description": "**EXCLUDED from the public API** (`console`). Browser avatar-upload flow.", + "x-audience": "console", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Browser avatar-upload flow.", + "security": [ + { + "ConsoleSession": [] + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + }, + "delete": { + "operationId": "removeAvatarUserProfile", + "tags": [ + "profile" + ], + "summary": "Remove avatar user profile", + "description": "**EXCLUDED from the public API** (`console`). Personal profile edit.", + "x-audience": "console", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Personal profile edit.", + "security": [ + { + "ConsoleSession": [] + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/console/auth/methods": { + "get": { + "operationId": "getUserProfileAuthMethods", + "tags": [ + "auth" + ], + "summary": "Get user profile auth methods", + "description": "**EXCLUDED from the public API** (`console`). Account-security introspection for the session user.", + "x-audience": "console", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Account-security introspection for the session user.", + "security": [ + { + "ConsoleSession": [] + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/console/auth/totp": { + "post": { + "operationId": "enrollTotpUserProfile", + "tags": [ + "auth" + ], + "summary": "Enroll totp user profile", + "description": "**EXCLUDED from the public API** (`console`). MFA enrollment via API key = account-takeover vector.", + "x-audience": "console", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "MFA enrollment via API key = account-takeover vector.", + "security": [ + { + "ConsoleSession": [] + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/console/auth/totp/verify": { + "post": { + "operationId": "verifyTotpUserProfile", + "tags": [ + "auth" + ], + "summary": "Verify totp user profile", + "description": "**EXCLUDED from the public API** (`console`). Part of the human MFA step-up flow.", + "x-audience": "console", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Part of the human MFA step-up flow.", + "security": [ + { + "ConsoleSession": [] + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/console/auth/factors/{factorId}": { + "delete": { + "operationId": "deleteUserProfileAuthFactor", + "tags": [ + "auth" + ], + "summary": "Delete user profile auth factor", + "description": "**EXCLUDED from the public API** (`console`). Removing MFA via API key = account-takeover vector.", + "x-audience": "console", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Removing MFA via API key = account-takeover vector.", + "security": [ + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "factorId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/console/auth/providers": { + "get": { + "operationId": "getUserProfileProviderConnectionUrl", + "tags": [ + "auth" + ], + "summary": "Get user profile provider connection url", + "description": "**EXCLUDED from the public API** (`console`). Deferred Better Auth provider-link flow; dashboard identity only.", + "x-audience": "console", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Deferred Better Auth provider-link flow; dashboard identity only.", + "security": [ + { + "ConsoleSession": [] + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/console/auth/providers/{provider}": { + "delete": { + "operationId": "disconnectProviderUserProfile", + "tags": [ + "auth" + ], + "summary": "Disconnect provider user profile", + "description": "**EXCLUDED from the public API** (`console`). Deferred Better Auth provider-unlink flow; dashboard identity only.", + "x-audience": "console", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Deferred Better Auth provider-unlink flow; dashboard identity only.", + "security": [ + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "provider", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/console/teams/leave": { + "post": { + "operationId": "leaveTeamUserProfile", + "tags": [ + "teams" + ], + "summary": "Leave team user profile", + "description": "**EXCLUDED from the public API** (`console`). Acts on the session user's own membership.", + "x-audience": "console", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Acts on the session user's own membership.", + "security": [ + { + "ConsoleSession": [] + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/console/teams/{teamId}/delete": { + "post": { + "operationId": "deleteUserProfileTeam", + "tags": [ + "teams" + ], + "summary": "Delete user profile team", + "description": "**EXCLUDED from the public API** (`console`). Destructive, human-confirmed flow.", + "x-audience": "console", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Destructive, human-confirmed flow.", + "security": [ + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "teamId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/console/notifications": { + "get": { + "operationId": "listNotificationInbox", + "tags": [ + "notifications" + ], + "summary": "List notification inbox", + "description": "**EXCLUDED from the public API** (`console`). User-scoped console inbox.", + "x-audience": "console", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "User-scoped console inbox.", + "security": [ + { + "ConsoleSession": [] + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/console/notifications/archived": { + "get": { + "operationId": "listNotificationArchived", + "tags": [ + "notifications" + ], + "summary": "List notification archived", + "description": "**EXCLUDED from the public API** (`console`). User-scoped console inbox.", + "x-audience": "console", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "User-scoped console inbox.", + "security": [ + { + "ConsoleSession": [] + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/console/notifications/count": { + "get": { + "operationId": "unreadCountNotification", + "tags": [ + "notifications" + ], + "summary": "Unread count notification", + "description": "**EXCLUDED from the public API** (`console`). User-scoped console inbox.", + "x-audience": "console", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "User-scoped console inbox.", + "security": [ + { + "ConsoleSession": [] + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/console/notifications/{notificationId}/read": { + "post": { + "operationId": "markReadNotification", + "tags": [ + "notifications" + ], + "summary": "Mark read notification", + "description": "**EXCLUDED from the public API** (`console`). User-scoped console inbox.", + "x-audience": "console", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "User-scoped console inbox.", + "security": [ + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "notificationId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/console/notifications/read": { + "post": { + "operationId": "markAllReadNotification", + "tags": [ + "notifications" + ], + "summary": "Mark all read notification", + "description": "**EXCLUDED from the public API** (`console`). User-scoped console inbox.", + "x-audience": "console", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "User-scoped console inbox.", + "security": [ + { + "ConsoleSession": [] + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/console/notifications/{notificationId}/archive": { + "post": { + "operationId": "archiveNotification", + "tags": [ + "notifications" + ], + "summary": "Archive notification", + "description": "**EXCLUDED from the public API** (`console`). User-scoped console inbox.", + "x-audience": "console", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "User-scoped console inbox.", + "security": [ + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "notificationId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/console/notifications/archive": { + "post": { + "operationId": "archiveAllNotification", + "tags": [ + "notifications" + ], + "summary": "Archive all notification", + "description": "**EXCLUDED from the public API** (`console`). User-scoped console inbox.", + "x-audience": "console", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "User-scoped console inbox.", + "security": [ + { + "ConsoleSession": [] + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/console/notifications/preferences": { + "get": { + "operationId": "getNotificationPreferences", + "tags": [ + "notifications" + ], + "summary": "Get notification preferences", + "description": "**EXCLUDED from the public API** (`console`). Per-user notification preferences.", + "x-audience": "console", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Per-user notification preferences.", + "security": [ + { + "ConsoleSession": [] + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + }, + "put": { + "operationId": "updateNotificationPreferences", + "tags": [ + "notifications" + ], + "summary": "Update notification preferences", + "description": "**EXCLUDED from the public API** (`console`). Per-user notification preferences.", + "x-audience": "console", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Per-user notification preferences.", + "security": [ + { + "ConsoleSession": [] + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/console/notifications/test": { + "post": { + "operationId": "sendTestNotificationEmail", + "tags": [ + "notifications" + ], + "summary": "Send test notification email", + "description": "**EXCLUDED from the public API** (`console`). Console settings test button.", + "x-audience": "console", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Console settings test button.", + "security": [ + { + "ConsoleSession": [] + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/console/widget/logo/uploads": { + "post": { + "operationId": "generateWidgetSettingsLogoUploadUrl", + "tags": [ + "widget" + ], + "summary": "Generate widget settings logo upload url", + "description": "**EXCLUDED from the public API** (`console`). Browser logo-upload flow.", + "x-audience": "console", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Browser logo-upload flow.", + "security": [ + { + "ConsoleSession": [] + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/console/widget/logo": { + "put": { + "operationId": "attachLogoWidgetSettings", + "tags": [ + "widget" + ], + "summary": "Attach logo widget settings", + "description": "**EXCLUDED from the public API** (`console`). Browser logo-upload flow.", + "x-audience": "console", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Browser logo-upload flow.", + "security": [ + { + "ConsoleSession": [] + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + }, + "delete": { + "operationId": "removeLogoWidgetSettings", + "tags": [ + "widget" + ], + "summary": "Remove logo widget settings", + "description": "**EXCLUDED from the public API** (`console`). Browser logo-upload flow.", + "x-audience": "console", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Browser logo-upload flow.", + "security": [ + { + "ConsoleSession": [] + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/console/widget/logo/org": { + "post": { + "operationId": "useOrgLogoWidgetSettings", + "tags": [ + "widget" + ], + "summary": "Use org logo widget settings", + "description": "**EXCLUDED from the public API** (`console`). Console snapshot flow (copies org logo).", + "x-audience": "console", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Console snapshot flow (copies org logo).", + "security": [ + { + "ConsoleSession": [] + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/console/widget/logo/project": { + "post": { + "operationId": "useProjectIconWidgetSettings", + "tags": [ + "widget" + ], + "summary": "Use project icon widget settings", + "description": "**EXCLUDED from the public API** (`console`). Console snapshot flow (copies project icon).", + "x-audience": "console", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Console snapshot flow (copies project icon).", + "security": [ + { + "ConsoleSession": [] + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/console/webhooks": { + "get": { + "operationId": "listWebhooks", + "tags": [ + "webhooks" + ], + "summary": "List webhook endpoints", + "description": "Lists sanitized webhook endpoint settings for the authenticated organization.\n\nRequires a verified dashboard bearer and current organization authorization. Organization keys and project tokens are not accepted.", + "x-audience": "console", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Dashboard webhook settings for the authenticated organization.", + "security": [ + { + "ConsoleSession": [] + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ConsoleWebhook" + } + } + }, + "required": [ + "data" + ] + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + } + } + }, + "post": { + "operationId": "createWebhook", + "tags": [ + "webhooks" + ], + "summary": "Create a webhook endpoint", + "description": "Creates a webhook endpoint for the authenticated organization. Requires live owner or admin authority.\n\nRequires a verified dashboard bearer and current organization authorization. The signed-in member must be an organization owner or admin. Organization keys and project tokens are not accepted.", + "x-audience": "console", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Dashboard webhook settings for the authenticated organization.", + "x-required-organization-role": "owner_or_admin", + "security": [ + { + "ConsoleSession": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateConsoleWebhookRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/ConsoleWebhook" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + } + } + } + }, + "/console/webhooks/{webhookId}": { + "patch": { + "operationId": "updateWebhook", + "tags": [ + "webhooks" + ], + "summary": "Update a webhook endpoint", + "description": "Updates a webhook endpoint in the authenticated organization. Requires live owner or admin authority.\n\nRequires a verified dashboard bearer and current organization authorization. The signed-in member must be an organization owner or admin. Organization keys and project tokens are not accepted.", + "x-audience": "console", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Dashboard webhook settings for the authenticated organization.", + "x-required-organization-role": "owner_or_admin", + "security": [ + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "webhookId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateConsoleWebhookRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/ConsoleWebhook" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + }, + "delete": { + "operationId": "deleteWebhook", + "tags": [ + "webhooks" + ], + "summary": "Delete a webhook endpoint", + "description": "Deletes a webhook endpoint in the authenticated organization. Requires live owner or admin authority.\n\nRequires a verified dashboard bearer and current organization authorization. The signed-in member must be an organization owner or admin. Organization keys and project tokens are not accepted.", + "x-audience": "console", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Dashboard webhook settings for the authenticated organization.", + "x-required-organization-role": "owner_or_admin", + "security": [ + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "webhookId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "$ref": "#/components/schemas/DeleteConsoleWebhookResult" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/console/sandbox/pool": { + "get": { + "operationId": "getSandboxProjectPool", + "tags": [ + "sandbox" + ], + "summary": "Get sandbox project project pool", + "description": "**EXCLUDED from the public API** (`console`). Console/sandbox internal wiring.", + "x-audience": "console", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Console/sandbox internal wiring.", + "security": [ + { + "ConsoleSession": [] + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/console/deployments": { + "get": { + "operationId": "listDeployments", + "tags": [ + "deployments" + ], + "summary": "List deployments", + "description": "**EXCLUDED from the public API** (`console`). Legacy console surface; not a customer contract.", + "x-audience": "console", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Legacy console surface; not a customer contract.", + "security": [ + { + "ConsoleSession": [] + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/console/insights/logs": { + "get": { + "operationId": "logsInsight", + "tags": [ + "insights" + ], + "summary": "Logs insight", + "description": "**EXCLUDED from the public API** (`console`). Customer console observability for the selected organization and project.", + "x-audience": "console", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Customer console observability for the selected organization and project.", + "security": [ + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "projectId", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "start", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "end", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "limit", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 25 + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/console/insights/usage": { + "get": { + "operationId": "usageInsight", + "tags": [ + "insights" + ], + "summary": "Usage insight", + "description": "**EXCLUDED from the public API** (`console`). Customer console usage and entitlement presentation.", + "x-audience": "console", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Customer console usage and entitlement presentation.", + "security": [ + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "projectId", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "start", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "end", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/console/insights/analytics": { + "get": { + "operationId": "analyticsInsight", + "tags": [ + "insights" + ], + "summary": "Analytics insight", + "description": "**EXCLUDED from the public API** (`console`). Customer console aggregate product analytics; message bodies are never returned.", + "x-audience": "console", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Customer console aggregate product analytics; message bodies are never returned.", + "security": [ + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "projectId", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "start", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "end", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/console/insights/preferences": { + "get": { + "operationId": "getInsightPreferences", + "tags": [ + "insights" + ], + "summary": "Get insight preferences", + "description": "**EXCLUDED from the public API** (`console`). Organization analytics-consent controls for the console.", + "x-audience": "console", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Organization analytics-consent controls for the console.", + "security": [ + { + "ConsoleSession": [] + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + }, + "put": { + "operationId": "updateInsightPreferences", + "tags": [ + "insights" + ], + "summary": "Update insight preferences", + "description": "**EXCLUDED from the public API** (`console`). Organization analytics-consent controls for the console.", + "x-audience": "console", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Organization analytics-consent controls for the console.", + "security": [ + { + "ConsoleSession": [] + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/console/organization-invitations/{invitationId}/accept": { + "post": { + "operationId": "acceptOrganizationInvitation", + "tags": [ + "organization-invitations" + ], + "summary": "Accept organization invitation", + "description": "**EXCLUDED from the public API** (`console`). Deferred Better Auth invitation-acceptance flow; dashboard identity only.", + "x-audience": "console", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Deferred Better Auth invitation-acceptance flow; dashboard identity only.", + "security": [ + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "invitationId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/admin/orgs": { + "get": { + "operationId": "adminListOrganizations", + "tags": [ + "admin/orgs" + ], + "summary": "List organizations", + "description": "**EXCLUDED from the public API** (`staff`). Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "x-audience": "staff", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "security": [ + { + "ConsoleSession": [] + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/admin/orgs/{orgId}": { + "get": { + "operationId": "adminGetOrganization", + "tags": [ + "admin/orgs" + ], + "summary": "Get organization", + "description": "**EXCLUDED from the public API** (`staff`). Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "x-audience": "staff", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "security": [ + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "orgId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + }, + "patch": { + "operationId": "adminRenameOrganization", + "tags": [ + "admin/orgs" + ], + "summary": "Rename organization", + "description": "**EXCLUDED from the public API** (`staff`). Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "x-audience": "staff", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "security": [ + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "orgId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + }, + "delete": { + "operationId": "adminCascadeDeleteOrganization", + "tags": [ + "admin/orgs" + ], + "summary": "Cascade delete organization", + "description": "**EXCLUDED from the public API** (`staff`). Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "x-audience": "staff", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "security": [ + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "orgId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/admin/orgs/{orgId}/freeze": { + "post": { + "operationId": "adminFreezeOrganization", + "tags": [ + "admin/orgs" + ], + "summary": "Freeze organization", + "description": "**EXCLUDED from the public API** (`staff`). Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "x-audience": "staff", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "security": [ + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "orgId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/admin/orgs/{orgId}/unfreeze": { + "post": { + "operationId": "adminUnfreezeOrganization", + "tags": [ + "admin/orgs" + ], + "summary": "Unfreeze organization", + "description": "**EXCLUDED from the public API** (`staff`). Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "x-audience": "staff", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "security": [ + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "orgId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/admin/orgs/features": { + "get": { + "operationId": "adminListOrganizationFeatureGroups", + "tags": [ + "admin/orgs" + ], + "summary": "List organization feature groups", + "description": "**EXCLUDED from the public API** (`staff`). Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "x-audience": "staff", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "security": [ + { + "ConsoleSession": [] + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/admin/orgs/{orgId}/features": { + "patch": { + "operationId": "adminSetOrganizationFeatureGroups", + "tags": [ + "admin/orgs" + ], + "summary": "Set organization feature groups", + "description": "**EXCLUDED from the public API** (`staff`). Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "x-audience": "staff", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "security": [ + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "orgId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/admin/users": { + "get": { + "operationId": "adminSearchUser", + "tags": [ + "admin/users" + ], + "summary": "Search user", + "description": "**EXCLUDED from the public API** (`staff`). Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "x-audience": "staff", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "security": [ + { + "ConsoleSession": [] + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/admin/users/{userId}": { + "get": { + "operationId": "adminGetUser", + "tags": [ + "admin/users" + ], + "summary": "Get user", + "description": "**EXCLUDED from the public API** (`staff`). Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "x-audience": "staff", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "security": [ + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "userId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/admin/users/{userId}/onboarding": { + "delete": { + "operationId": "adminResetOnboardingUser", + "tags": [ + "admin/users" + ], + "summary": "Reset onboarding user", + "description": "**EXCLUDED from the public API** (`staff`). Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "x-audience": "staff", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "security": [ + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "userId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/admin/users/{userId}/suspend": { + "post": { + "operationId": "adminSuspendUser", + "tags": [ + "admin/users" + ], + "summary": "Suspend user user", + "description": "**EXCLUDED from the public API** (`staff`). Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "x-audience": "staff", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "security": [ + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "userId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/admin/users/{userId}/unsuspend": { + "post": { + "operationId": "adminUnsuspendUser", + "tags": [ + "admin/users" + ], + "summary": "Unsuspend user user", + "description": "**EXCLUDED from the public API** (`staff`). Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "x-audience": "staff", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "security": [ + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "userId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/admin/users/{userId}/signout": { + "post": { + "operationId": "adminForceSignOutUser", + "tags": [ + "admin/users" + ], + "summary": "Force sign out user", + "description": "**EXCLUDED from the public API** (`staff`). Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "x-audience": "staff", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "security": [ + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "userId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/admin/members/{memberId}": { + "patch": { + "operationId": "adminSetMemberRole", + "tags": [ + "admin/members" + ], + "summary": "Set member role", + "description": "**EXCLUDED from the public API** (`staff`). Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "x-audience": "staff", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "security": [ + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "memberId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + }, + "delete": { + "operationId": "adminRemoveMember", + "tags": [ + "admin/members" + ], + "summary": "Remove member member", + "description": "**EXCLUDED from the public API** (`staff`). Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "x-audience": "staff", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "security": [ + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "memberId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/admin/members/invites": { + "post": { + "operationId": "adminInviteMember", + "tags": [ + "admin/members" + ], + "summary": "Invite member member", + "description": "**EXCLUDED from the public API** (`staff`). Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "x-audience": "staff", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "security": [ + { + "ConsoleSession": [] + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/admin/bansafe/enforcement/{orgId}/{sessionId}/lift": { + "post": { + "operationId": "adminLiftBanSafeEnforcement", + "tags": [ + "admin/bansafe" + ], + "summary": "Lift ban safe enforcement", + "description": "**EXCLUDED from the public API** (`staff`). Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "x-audience": "staff", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "security": [ + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "orgId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "sessionId", + "in": "path", + "required": true, + "description": "Database session UUID or stable session slug.", + "schema": { + "$ref": "#/components/schemas/SessionIdentifier" + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/admin/bansafe/claims": { + "get": { + "operationId": "adminListBanSafeClaims", + "tags": [ + "admin/bansafe" + ], + "summary": "List ban safe claims", + "description": "**EXCLUDED from the public API** (`staff`). Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "x-audience": "staff", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "security": [ + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "orgId", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "status", + "in": "query", + "required": false, + "schema": { + "type": "string", + "enum": [ + "filed", + "under_review", + "approved", + "denied", + "paid", + "reversed" + ] + } + }, + { + "name": "limit", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 25 + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/admin/bansafe/claims/{claimId}/approve": { + "post": { + "operationId": "adminApproveBanSafeClaim", + "tags": [ + "admin/bansafe" + ], + "summary": "Approve ban safe claim", + "description": "**EXCLUDED from the public API** (`staff`). Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "x-audience": "staff", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "security": [ + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "claimId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/admin/bansafe/claims/{claimId}/deny": { + "post": { + "operationId": "adminDenyBanSafeClaim", + "tags": [ + "admin/bansafe" + ], + "summary": "Deny ban safe claim", + "description": "**EXCLUDED from the public API** (`staff`). Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "x-audience": "staff", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "security": [ + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "claimId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/admin/bansafe/claims/{claimId}/reverse": { + "post": { + "operationId": "adminReverseBanSafeClaim", + "tags": [ + "admin/bansafe" + ], + "summary": "Reverse ban safe claim", + "description": "**EXCLUDED from the public API** (`staff`). Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "x-audience": "staff", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "security": [ + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "claimId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/admin/sessions": { + "get": { + "operationId": "adminListSessions", + "tags": [ + "admin/sessions" + ], + "summary": "List sessions", + "description": "**EXCLUDED from the public API** (`staff`). Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "x-audience": "staff", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "security": [ + { + "ConsoleSession": [] + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/admin/sessions/{sessionId}/stop": { + "post": { + "operationId": "adminForceStopSession", + "tags": [ + "admin/sessions" + ], + "summary": "Force stop session", + "description": "**EXCLUDED from the public API** (`staff`). Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "x-audience": "staff", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "security": [ + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "sessionId", + "in": "path", + "required": true, + "description": "Database session UUID or stable session slug.", + "schema": { + "$ref": "#/components/schemas/SessionIdentifier" + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/admin/sessions/{sessionId}": { + "delete": { + "operationId": "adminForceDeleteSession", + "tags": [ + "admin/sessions" + ], + "summary": "Force delete session", + "description": "**EXCLUDED from the public API** (`staff`). Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "x-audience": "staff", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "security": [ + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "sessionId", + "in": "path", + "required": true, + "description": "Database session UUID or stable session slug.", + "schema": { + "$ref": "#/components/schemas/SessionIdentifier" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/admin/sessions/{sessionId}/comp": { + "post": { + "operationId": "adminCompSessionDaySession", + "tags": [ + "admin/sessions" + ], + "summary": "Comp session day session", + "description": "**EXCLUDED from the public API** (`staff`). Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "x-audience": "staff", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "security": [ + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "sessionId", + "in": "path", + "required": true, + "description": "Database session UUID or stable session slug.", + "schema": { + "$ref": "#/components/schemas/SessionIdentifier" + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/admin/campaigns": { + "get": { + "operationId": "adminListCampaigns", + "tags": [ + "admin/campaigns" + ], + "summary": "List campaigns", + "description": "**EXCLUDED from the public API** (`staff`). Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "x-audience": "staff", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "security": [ + { + "ConsoleSession": [] + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/admin/campaigns/{campaignId}/pause": { + "post": { + "operationId": "adminForcePauseCampaign", + "tags": [ + "admin/campaigns" + ], + "summary": "Force pause campaign", + "description": "**EXCLUDED from the public API** (`staff`). Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "x-audience": "staff", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "security": [ + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "campaignId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/admin/campaigns/{campaignId}/stop": { + "post": { + "operationId": "adminForceStopCampaign", + "tags": [ + "admin/campaigns" + ], + "summary": "Force stop campaign", + "description": "**EXCLUDED from the public API** (`staff`). Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "x-audience": "staff", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "security": [ + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "campaignId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/admin/campaigns/optouts": { + "get": { + "operationId": "adminOptOutLeaderboardCampaign", + "tags": [ + "admin/campaigns" + ], + "summary": "Opt out leaderboard campaign", + "description": "**EXCLUDED from the public API** (`staff`). Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "x-audience": "staff", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "security": [ + { + "ConsoleSession": [] + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/admin/billing/revenue": { + "get": { + "operationId": "adminPlatformRevenueBilling", + "tags": [ + "admin/billing" + ], + "summary": "Platform revenue billing", + "description": "**EXCLUDED from the public API** (`staff`). Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "x-audience": "staff", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "security": [ + { + "ConsoleSession": [] + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/admin/billing/leaderboard": { + "get": { + "operationId": "adminTopOrgsByRevenueBilling", + "tags": [ + "admin/billing" + ], + "summary": "Top orgs by revenue billing", + "description": "**EXCLUDED from the public API** (`staff`). Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "x-audience": "staff", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "security": [ + { + "ConsoleSession": [] + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/admin/billing/lowbalance": { + "get": { + "operationId": "adminLowBalanceOrgsBilling", + "tags": [ + "admin/billing" + ], + "summary": "Low balance orgs billing", + "description": "**EXCLUDED from the public API** (`staff`). Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "x-audience": "staff", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "security": [ + { + "ConsoleSession": [] + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/admin/billing/credits": { + "post": { + "operationId": "adminCompCreditsBilling", + "tags": [ + "admin/billing" + ], + "summary": "Comp credits billing", + "description": "**EXCLUDED from the public API** (`staff`). Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "x-audience": "staff", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "security": [ + { + "ConsoleSession": [] + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/admin/billing/refunds": { + "post": { + "operationId": "adminRefundBilling", + "tags": [ + "admin/billing" + ], + "summary": "Refund billing", + "description": "**EXCLUDED from the public API** (`staff`). Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "x-audience": "staff", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "security": [ + { + "ConsoleSession": [] + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/admin/keys": { + "get": { + "operationId": "adminListApiKeys", + "tags": [ + "admin/keys" + ], + "summary": "List api keys", + "description": "**EXCLUDED from the public API** (`staff`). Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "x-audience": "staff", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "security": [ + { + "ConsoleSession": [] + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/admin/keys/{keyId}": { + "delete": { + "operationId": "adminRevokeApiKeyApiKey", + "tags": [ + "admin/keys" + ], + "summary": "Revoke api key api key", + "description": "**EXCLUDED from the public API** (`staff`). Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "x-audience": "staff", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "security": [ + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "keyId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/admin/tenants": { + "get": { + "operationId": "adminListTenants", + "tags": [ + "admin/tenants" + ], + "summary": "List tenants", + "description": "**EXCLUDED from the public API** (`staff`). Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "x-audience": "staff", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "security": [ + { + "ConsoleSession": [] + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/admin/tenants/{tenantId}": { + "patch": { + "operationId": "adminSetTenantActive", + "tags": [ + "admin/tenants" + ], + "summary": "Set tenant active", + "description": "**EXCLUDED from the public API** (`staff`). Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "x-audience": "staff", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "x-merged-endpoints": [ + "adminUpdateTenantRateLimits", + "adminUpdateTenantLogLevel", + "adminToggleDebugModeTenant" + ], + "security": [ + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "tenantId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/admin/pricing": { + "get": { + "operationId": "adminListPricing", + "tags": [ + "admin/pricing" + ], + "summary": "List pricing", + "description": "**EXCLUDED from the public API** (`staff`). Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "x-audience": "staff", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "security": [ + { + "ConsoleSession": [] + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/admin/pricing/{tier}": { + "put": { + "operationId": "adminUpdatePricing", + "tags": [ + "admin/pricing" + ], + "summary": "Update pricing", + "description": "**EXCLUDED from the public API** (`staff`). Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "x-audience": "staff", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "security": [ + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "tier", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + }, + "patch": { + "operationId": "adminSetPricingActive", + "tags": [ + "admin/pricing" + ], + "summary": "Set pricing active", + "description": "**EXCLUDED from the public API** (`staff`). Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "x-audience": "staff", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "security": [ + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "tier", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/admin/organization-invitations": { + "get": { + "operationId": "adminListOrganizationInvitations", + "tags": [ + "admin/organization-invitations" + ], + "summary": "List organization invitations", + "description": "**EXCLUDED from the public API** (`staff`). Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "x-audience": "staff", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "security": [ + { + "ConsoleSession": [] + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + }, + "post": { + "operationId": "adminCreateOrganizationInvitation", + "tags": [ + "admin/organization-invitations" + ], + "summary": "Create organization invitation", + "description": "**EXCLUDED from the public API** (`staff`). Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "x-audience": "staff", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "security": [ + { + "ConsoleSession": [] + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/admin/organization-invitations/{invitationId}": { + "delete": { + "operationId": "adminRevokeOrganizationInvitation", + "tags": [ + "admin/organization-invitations" + ], + "summary": "Revoke organization invitation", + "description": "**EXCLUDED from the public API** (`staff`). Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "x-audience": "staff", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "security": [ + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "invitationId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/admin/webhooks": { + "get": { + "operationId": "adminListWebhooks", + "tags": [ + "admin/webhooks" + ], + "summary": "List webhooks", + "description": "**EXCLUDED from the public API** (`staff`). Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "x-audience": "staff", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "security": [ + { + "ConsoleSession": [] + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/admin/webhooks/{webhookId}/disable": { + "post": { + "operationId": "adminForceDisableWebhook", + "tags": [ + "admin/webhooks" + ], + "summary": "Force disable webhook", + "description": "**EXCLUDED from the public API** (`staff`). Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "x-audience": "staff", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "security": [ + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "webhookId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/admin/audit": { + "get": { + "operationId": "adminListAuditLogGlobal", + "tags": [ + "admin/audit" + ], + "summary": "List audit log global", + "description": "**EXCLUDED from the public API** (`staff`). Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "x-audience": "staff", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "security": [ + { + "ConsoleSession": [] + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/admin/audit/actions": { + "get": { + "operationId": "adminListAuditLogAdminActions", + "tags": [ + "admin/audit" + ], + "summary": "List audit log admin actions", + "description": "**EXCLUDED from the public API** (`staff`). Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "x-audience": "staff", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "security": [ + { + "ConsoleSession": [] + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/admin/kpis": { + "get": { + "operationId": "adminPlatformKpisPlatform", + "tags": [ + "admin/kpis" + ], + "summary": "Platform kpis platform", + "description": "**EXCLUDED from the public API** (`staff`). Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "x-audience": "staff", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "security": [ + { + "ConsoleSession": [] + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/admin/signups": { + "get": { + "operationId": "adminRecentSignupsPlatform", + "tags": [ + "admin/signups" + ], + "summary": "Recent signups platform", + "description": "**EXCLUDED from the public API** (`staff`). Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "x-audience": "staff", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "security": [ + { + "ConsoleSession": [] + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/admin/sync": { + "post": { + "operationId": "adminEnsureCurrentUserStaffSyncStaffSync", + "tags": [ + "admin/sync" + ], + "summary": "Ensure current user staff sync staff sync", + "description": "**EXCLUDED from the public API** (`staff`). Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "x-audience": "staff", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "security": [ + { + "ConsoleSession": [] + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, + "/admin/bans": { + "get": { + "operationId": "adminListRecentSessionBans", + "tags": [ + "admin/bans" + ], + "summary": "List recent session bans", + "description": "**EXCLUDED from the public API** (`staff`). Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "x-audience": "staff", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Polymorfa staff endpoint (cross-org / platform control). Requires a staff dashboard identity; never key-authenticated.", + "security": [ + { + "ConsoleSession": [] + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + } + }, + "components": { + "securitySchemes": { + "ApiKeyAuth": { + "type": "http", + "scheme": "bearer", + "description": "Polymorfa server credential: a scoped pmfa_ organization key, or a pmfa_pt_ project token on project- and session-bound operations inside its exact authenticated project. Listener and browser client credentials are rejected." + }, + "ConsoleSession": { + "type": "http", + "scheme": "bearer", + "description": "Verified dashboard JWT for signed-in Console requests. This is not a server credential." + } + }, + "schemas": { + "DataEnvelope": { + "type": "object", + "properties": { + "data": { + "description": "Operation result." + } + }, + "required": [ + "data" + ] + }, + "ErrorEnvelope": { + "type": "object", + "properties": { + "error": { + "type": "string", + "description": "Human-readable sentence describing the failure." + }, + "code": { + "type": "string", + "description": "Stable, documented identifier for this failure. Present when the failure has one." + }, + "docs": { + "type": "string", + "format": "uri", + "description": "Documentation for this failure, when one is published." + }, + "retryAfter": { + "type": "integer", + "minimum": 0, + "description": "Seconds to wait before retrying, on a paced refusal or retryable service pause." + } + }, + "required": [ + "error" + ] + }, + "ProjectId": { + "type": "string", + "format": "uuid", + "description": "Project UUID. Optional where an operation can infer or search organization scope; required where the operation creates a project-owned resource." + }, + "CustomerId": { + "type": "string", + "format": "uuid", + "description": "Project-owned Customer UUID." + }, + "Customer": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "$ref": "#/components/schemas/CustomerId" + }, + "orgId": { + "type": "string", + "format": "uuid" + }, + "projectId": { + "$ref": "#/components/schemas/ProjectId" + }, + "name": { + "type": "string", + "nullable": true, + "maxLength": 120 + }, + "phone": { + "type": "string", + "nullable": true, + "pattern": "^\\+[1-9][0-9]{6,14}$" + }, + "externalCustomerId": { + "type": "string", + "nullable": true, + "maxLength": 200 + }, + "status": { + "type": "string", + "enum": [ + "active", + "archiving", + "archived" + ] + }, + "isDefault": { + "type": "boolean" + }, + "archivedAt": { + "type": "integer", + "format": "int64", + "nullable": true + }, + "createdAt": { + "type": "integer", + "format": "int64" + }, + "updatedAt": { + "type": "integer", + "format": "int64" + } + }, + "required": [ + "id", + "orgId", + "projectId", + "name", + "phone", + "externalCustomerId", + "status", + "isDefault", + "archivedAt", + "createdAt", + "updatedAt" + ] + }, + "CustomerSummary": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "$ref": "#/components/schemas/CustomerId" + }, + "orgId": { + "type": "string", + "format": "uuid" + }, + "projectId": { + "$ref": "#/components/schemas/ProjectId" + }, + "name": { + "type": "string", + "nullable": true, + "maxLength": 120 + }, + "phoneMasked": { + "type": "string", + "nullable": true + }, + "externalCustomerId": { + "type": "string", + "nullable": true, + "maxLength": 200 + }, + "status": { + "type": "string", + "enum": [ + "active", + "archiving", + "archived" + ] + }, + "isDefault": { + "type": "boolean" + }, + "archivedAt": { + "type": "integer", + "format": "int64", + "nullable": true + }, + "numberCount": { + "type": "integer", + "minimum": 0 + }, + "connectedNumberCount": { + "type": "integer", + "minimum": 0 + }, + "activePairingLinkState": { + "type": "string", + "nullable": true + }, + "lastActivityAt": { + "type": "integer", + "format": "int64", + "nullable": true + }, + "needsAttention": { + "type": "boolean" + }, + "createdAt": { + "type": "integer", + "format": "int64" + }, + "updatedAt": { + "type": "integer", + "format": "int64" + } + }, + "required": [ + "id", + "orgId", + "projectId", + "name", + "phoneMasked", + "externalCustomerId", + "status", + "isDefault", + "archivedAt", + "numberCount", + "connectedNumberCount", + "activePairingLinkState", + "lastActivityAt", + "needsAttention", + "createdAt", + "updatedAt" + ] + }, + "CustomersStatus": { + "type": "object", + "additionalProperties": false, + "properties": { + "enabled": { + "type": "boolean" + }, + "enabledAt": { + "type": "integer", + "format": "int64", + "nullable": true + }, + "enabledBy": { + "type": "string", + "nullable": true + }, + "defaultCustomer": { + "type": "object", + "allOf": [ + { + "$ref": "#/components/schemas/Customer" + } + ], + "nullable": true + } + }, + "required": [ + "enabled", + "enabledAt", + "enabledBy", + "defaultCustomer" + ] + }, + "CustomersEnablement": { + "type": "object", + "additionalProperties": false, + "properties": { + "enabled": { + "type": "boolean" + }, + "enabledAt": { + "type": "integer", + "format": "int64", + "nullable": true + }, + "enabledBy": { + "type": "string", + "nullable": true + }, + "defaultCustomer": { + "type": "object", + "allOf": [ + { + "$ref": "#/components/schemas/Customer" + } + ], + "nullable": true + }, + "migratedNumberCount": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "enabled", + "enabledAt", + "enabledBy", + "defaultCustomer", + "migratedNumberCount" + ] + }, + "CustomerProjectRequest": { + "type": "object", + "additionalProperties": false, + "properties": { + "projectId": { + "$ref": "#/components/schemas/ProjectId" + } + } + }, + "CreateCustomerRequest": { + "type": "object", + "additionalProperties": false, + "properties": { + "projectId": { + "$ref": "#/components/schemas/ProjectId" + }, + "name": { + "type": "string", + "nullable": true, + "minLength": 1, + "maxLength": 120 + }, + "phone": { + "type": "string", + "nullable": true, + "description": "Phone number normalized to E.164." + }, + "externalCustomerId": { + "type": "string", + "nullable": true, + "minLength": 1, + "maxLength": 200 + } + } + }, + "UpdateCustomerRequest": { + "type": "object", + "additionalProperties": false, + "minProperties": 1, + "properties": { + "projectId": { + "$ref": "#/components/schemas/ProjectId" + }, + "name": { + "type": "string", + "nullable": true, + "minLength": 1, + "maxLength": 120 + }, + "phone": { + "type": "string", + "nullable": true, + "description": "Phone number normalized to E.164." + }, + "externalCustomerId": { + "type": "string", + "nullable": true, + "minLength": 1, + "maxLength": 200 + } + } + }, + "CustomerNumber": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "customerId": { + "$ref": "#/components/schemas/CustomerId" + }, + "sessionId": { + "type": "string" + }, + "name": { + "type": "string", + "nullable": true + }, + "phoneMasked": { + "type": "string", + "nullable": true + }, + "status": { + "type": "string" + }, + "backend": { + "type": "string", + "nullable": true + }, + "createdAt": { + "type": "integer", + "format": "int64" + } + }, + "required": [ + "id", + "customerId", + "sessionId", + "name", + "phoneMasked", + "status", + "backend", + "createdAt" + ] + }, + "CustomerEvent": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "action": { + "type": "string", + "pattern": "^customer(?:\\.[a-z0-9_]+){1,3}$", + "maxLength": 128 + }, + "fromStatus": { + "type": "string", + "nullable": true + }, + "toStatus": { + "type": "string", + "nullable": true + }, + "sessionId": { + "type": "string", + "format": "uuid", + "nullable": true + }, + "pairingLinkId": { + "type": "string", + "format": "uuid", + "nullable": true + }, + "metadata": { + "type": "object", + "additionalProperties": false, + "properties": { + "fields": { + "type": "array", + "uniqueItems": true, + "items": { + "type": "string", + "enum": [ + "name", + "phone", + "externalCustomerId" + ] + } + } + } + }, + "occurredAt": { + "type": "integer", + "format": "int64" + } + }, + "required": [ + "id", + "action", + "fromStatus", + "toStatus", + "sessionId", + "pairingLinkId", + "metadata", + "occurredAt" + ] + }, + "CustomerPairingLink": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "orgId": { + "type": "string", + "format": "uuid" + }, + "projectId": { + "$ref": "#/components/schemas/ProjectId" + }, + "customerId": { + "$ref": "#/components/schemas/CustomerId" + }, + "expectedPhoneMasked": { + "type": "string", + "nullable": true + }, + "methods": { + "type": "array", + "minItems": 1, + "maxItems": 2, + "uniqueItems": true, + "items": { + "type": "string", + "enum": [ + "qr", + "phone" + ] + } + }, + "locale": { + "type": "string", + "enum": [ + "en", + "pt-BR" + ], + "nullable": true + }, + "theme": { + "type": "string", + "enum": [ + "light", + "dark", + "system" + ], + "nullable": true + }, + "expiresAt": { + "type": "integer", + "format": "int64" + }, + "status": { + "type": "string", + "enum": [ + "active", + "opened", + "connecting", + "connected", + "failed", + "expired", + "revoked" + ] + }, + "attemptCount": { + "type": "integer", + "minimum": 0 + }, + "maxAttempts": { + "type": "integer", + "minimum": 1, + "maximum": 20 + }, + "pendingSessionId": { + "type": "string", + "format": "uuid", + "nullable": true + }, + "createdBy": { + "type": "string", + "nullable": true + }, + "reservedAt": { + "type": "integer", + "format": "int64", + "nullable": true + }, + "openedAt": { + "type": "integer", + "format": "int64", + "nullable": true + }, + "connectingAt": { + "type": "integer", + "format": "int64", + "nullable": true + }, + "connectedAt": { + "type": "integer", + "format": "int64", + "nullable": true + }, + "failedAt": { + "type": "integer", + "format": "int64", + "nullable": true + }, + "expiredAt": { + "type": "integer", + "format": "int64", + "nullable": true + }, + "revokedAt": { + "type": "integer", + "format": "int64", + "nullable": true + }, + "lastErrorCode": { + "type": "string", + "nullable": true + }, + "failedExchangeCount": { + "type": "integer", + "minimum": 0, + "maximum": 5 + }, + "phoneMismatchCount": { + "type": "integer", + "minimum": 0, + "maximum": 3 + }, + "createdAt": { + "type": "integer", + "format": "int64" + }, + "updatedAt": { + "type": "integer", + "format": "int64" + } + }, + "required": [ + "id", + "orgId", + "projectId", + "customerId", + "expectedPhoneMasked", + "methods", + "locale", + "theme", + "expiresAt", + "status", + "attemptCount", + "maxAttempts", + "pendingSessionId", + "createdBy", + "reservedAt", + "openedAt", + "connectingAt", + "connectedAt", + "failedAt", + "expiredAt", + "revokedAt", + "lastErrorCode", + "failedExchangeCount", + "phoneMismatchCount", + "createdAt", + "updatedAt" + ] + }, + "CreatedCustomerPairingLink": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "orgId": { + "type": "string", + "format": "uuid" + }, + "projectId": { + "$ref": "#/components/schemas/ProjectId" + }, + "customerId": { + "$ref": "#/components/schemas/CustomerId" + }, + "expectedPhoneMasked": { + "type": "string", + "nullable": true + }, + "methods": { + "type": "array", + "minItems": 1, + "maxItems": 2, + "uniqueItems": true, + "items": { + "type": "string", + "enum": [ + "qr", + "phone" + ] + } + }, + "locale": { + "type": "string", + "enum": [ + "en", + "pt-BR" + ], + "nullable": true + }, + "theme": { + "type": "string", + "enum": [ + "light", + "dark", + "system" + ], + "nullable": true + }, + "expiresAt": { + "type": "integer", + "format": "int64" + }, + "status": { + "type": "string", + "enum": [ + "active", + "opened", + "connecting", + "connected", + "failed", + "expired", + "revoked" + ] + }, + "attemptCount": { + "type": "integer", + "minimum": 0 + }, + "maxAttempts": { + "type": "integer", + "minimum": 1, + "maximum": 20 + }, + "pendingSessionId": { + "type": "string", + "format": "uuid", + "nullable": true + }, + "createdBy": { + "type": "string", + "nullable": true + }, + "reservedAt": { + "type": "integer", + "format": "int64", + "nullable": true + }, + "openedAt": { + "type": "integer", + "format": "int64", + "nullable": true + }, + "connectingAt": { + "type": "integer", + "format": "int64", + "nullable": true + }, + "connectedAt": { + "type": "integer", + "format": "int64", + "nullable": true + }, + "failedAt": { + "type": "integer", + "format": "int64", + "nullable": true + }, + "expiredAt": { + "type": "integer", + "format": "int64", + "nullable": true + }, + "revokedAt": { + "type": "integer", + "format": "int64", + "nullable": true + }, + "lastErrorCode": { + "type": "string", + "nullable": true + }, + "failedExchangeCount": { + "type": "integer", + "minimum": 0, + "maximum": 5 + }, + "phoneMismatchCount": { + "type": "integer", + "minimum": 0, + "maximum": 3 + }, + "createdAt": { + "type": "integer", + "format": "int64" + }, + "updatedAt": { + "type": "integer", + "format": "int64" + }, + "url": { + "type": "string", + "format": "uri", + "nullable": true, + "description": "Returned once; null on an idempotent replay." + } + }, + "required": [ + "id", + "orgId", + "projectId", + "customerId", + "expectedPhoneMasked", + "methods", + "locale", + "theme", + "expiresAt", + "status", + "attemptCount", + "maxAttempts", + "pendingSessionId", + "createdBy", + "reservedAt", + "openedAt", + "connectingAt", + "connectedAt", + "failedAt", + "expiredAt", + "revokedAt", + "lastErrorCode", + "failedExchangeCount", + "phoneMismatchCount", + "createdAt", + "updatedAt", + "url" + ] + }, + "CreateCustomerPairingLinkRequest": { + "type": "object", + "additionalProperties": false, + "properties": { + "projectId": { + "$ref": "#/components/schemas/ProjectId" + }, + "expectedPhone": { + "type": "string", + "nullable": true, + "description": "Optional expected phone, normalized to E.164." + }, + "methods": { + "type": "array", + "minItems": 1, + "maxItems": 2, + "uniqueItems": true, + "items": { + "type": "string", + "enum": [ + "qr", + "phone" + ] + } + }, + "expiresInSeconds": { + "type": "integer", + "minimum": 900, + "maximum": 604800, + "default": 86400 + }, + "locale": { + "type": "string", + "enum": [ + "en", + "pt-BR" + ], + "nullable": true + }, + "theme": { + "type": "string", + "enum": [ + "light", + "dark", + "system" + ], + "nullable": true + } + } + }, + "TransferCustomerNumberRequest": { + "type": "object", + "additionalProperties": false, + "properties": { + "projectId": { + "$ref": "#/components/schemas/ProjectId" + }, + "sourceCustomerId": { + "$ref": "#/components/schemas/CustomerId" + }, + "confirm": { + "type": "boolean", + "enum": [ + true + ] + } + }, + "required": [ + "projectId", + "sourceCustomerId", + "confirm" + ] + }, + "TemplateId": { + "type": "string", + "format": "uuid", + "description": "Message-template draft UUID." + }, + "ConsoleWebhookRetry": { + "type": "object", + "additionalProperties": false, + "properties": { + "attempts": { + "type": "integer", + "minimum": 0, + "maximum": 10 + }, + "delaySeconds": { + "type": "integer", + "minimum": 0, + "maximum": 3600 + }, + "policy": { + "type": "string", + "enum": [ + "constant", + "linear", + "exponential" + ] + } + }, + "required": [ + "attempts", + "delaySeconds", + "policy" + ] + }, + "ConsoleWebhook": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "url": { + "type": "string", + "format": "uri", + "pattern": "^[Hh][Tt][Tt][Pp][Ss]?://", + "minLength": 1, + "maxLength": 2048, + "description": "Public HTTP(S) endpoint. Private, reserved, link-local, multicast, and credential-bearing targets are rejected." + }, + "events": { + "type": "array", + "items": { + "type": "string" + } + }, + "retries": { + "$ref": "#/components/schemas/ConsoleWebhookRetry" + }, + "enabled": { + "type": "boolean" + }, + "format": { + "type": "string", + "enum": [ + "native", + "meta" + ] + }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "hasSigningSecret": { + "type": "boolean" + } + }, + "required": [ + "id", + "url", + "events", + "retries", + "enabled", + "format", + "createdAt", + "hasSigningSecret" + ] + }, + "CreateConsoleWebhookRequest": { + "type": "object", + "additionalProperties": false, + "properties": { + "url": { + "type": "string", + "format": "uri", + "pattern": "^[Hh][Tt][Tt][Pp][Ss]?://", + "minLength": 1, + "maxLength": 2048, + "description": "Public HTTP(S) endpoint. Private, reserved, link-local, multicast, and credential-bearing targets are rejected." + }, + "events": { + "type": "array", + "items": { + "type": "string" + }, + "default": [] + }, + "retries": { + "$ref": "#/components/schemas/ConsoleWebhookRetry" + }, + "signingSecret": { + "type": "string", + "minLength": 16, + "maxLength": 4096, + "writeOnly": true + }, + "format": { + "type": "string", + "enum": [ + "native", + "meta" + ], + "default": "native" + } + }, + "required": [ + "url" + ] + }, + "UpdateConsoleWebhookRequest": { + "type": "object", + "additionalProperties": false, + "minProperties": 1, + "properties": { + "url": { + "type": "string", + "format": "uri", + "pattern": "^[Hh][Tt][Tt][Pp][Ss]?://", + "minLength": 1, + "maxLength": 2048, + "description": "Public HTTP(S) endpoint. Private, reserved, link-local, multicast, and credential-bearing targets are rejected." + }, + "events": { + "type": "array", + "items": { + "type": "string" + } + }, + "retries": { + "$ref": "#/components/schemas/ConsoleWebhookRetry" + }, + "signingSecret": { + "type": "string", + "minLength": 16, + "maxLength": 4096, + "writeOnly": true + }, + "clearSigningSecret": { + "type": "boolean" + }, + "enabled": { + "type": "boolean" + }, + "format": { + "type": "string", + "enum": [ + "native", + "meta" + ] + } + }, + "not": { + "required": [ + "signingSecret", + "clearSigningSecret" + ], + "properties": { + "clearSigningSecret": { + "enum": [ + true + ] + } + } + } + }, + "DeleteConsoleWebhookResult": { + "type": "object", + "additionalProperties": false, + "properties": { + "removed": { + "type": "boolean", + "enum": [ + true + ] + } + }, + "required": [ + "removed" + ] + }, + "WidgetColorPalette": { + "type": "object", + "additionalProperties": false, + "properties": { + "background": { + "type": "string", + "pattern": "^#[0-9A-Fa-f]{6}$" + }, + "foreground": { + "type": "string", + "pattern": "^#[0-9A-Fa-f]{6}$" + }, + "card": { + "type": "string", + "pattern": "^#[0-9A-Fa-f]{6}$" + }, + "cardForeground": { + "type": "string", + "pattern": "^#[0-9A-Fa-f]{6}$" + }, + "primary": { + "type": "string", + "pattern": "^#[0-9A-Fa-f]{6}$" + }, + "primaryForeground": { + "type": "string", + "pattern": "^#[0-9A-Fa-f]{6}$" + }, + "muted": { + "type": "string", + "pattern": "^#[0-9A-Fa-f]{6}$" + }, + "mutedForeground": { + "type": "string", + "pattern": "^#[0-9A-Fa-f]{6}$" + }, + "border": { + "type": "string", + "pattern": "^#[0-9A-Fa-f]{6}$" + }, + "accent": { + "type": "string", + "pattern": "^#[0-9A-Fa-f]{6}$" + }, + "destructive": { + "type": "string", + "pattern": "^#[0-9A-Fa-f]{6}$" + }, + "ring": { + "type": "string", + "pattern": "^#[0-9A-Fa-f]{6}$" + } + } + }, + "UpdateWidgetSettingsRequest": { + "type": "object", + "additionalProperties": false, + "properties": { + "projectId": { + "$ref": "#/components/schemas/ProjectId" + }, + "enabled": { + "type": "boolean" + }, + "modesAllowed": { + "type": "array", + "minItems": 1, + "maxItems": 50, + "uniqueItems": true, + "items": { + "type": "string", + "enum": [ + "embedded", + "redirect" + ] + } + }, + "allowedRedirectUris": { + "type": "array", + "maxItems": 50, + "items": { + "type": "string", + "format": "uri", + "pattern": "^[Hh][Tt][Tt][Pp][Ss]://", + "maxLength": 2048 + }, + "description": "Up to 50 exact HTTPS callback URLs without credentials." + }, + "allowedOrigins": { + "type": "array", + "maxItems": 50, + "items": { + "type": "string", + "format": "uri", + "pattern": "^[Hh][Tt][Tt][Pp][Ss]://[^/?#@,]+/?$", + "maxLength": 2048 + }, + "description": "Up to 50 exact HTTPS origins without credentials, paths, queries, fragments, or commas. A trailing root slash is accepted and removed." + }, + "businessName": { + "type": "string", + "maxLength": 120, + "nullable": true + }, + "accent": { + "type": "string", + "pattern": "^#[0-9A-Fa-f]{6}$", + "nullable": true + }, + "theme": { + "type": "string", + "enum": [ + "light", + "dark", + "system" + ] + }, + "hideWatermark": { + "type": "boolean" + }, + "colors": { + "type": "object", + "additionalProperties": false, + "nullable": true, + "properties": { + "light": { + "$ref": "#/components/schemas/WidgetColorPalette" + }, + "dark": { + "$ref": "#/components/schemas/WidgetColorPalette" + } + } + }, + "shape": { + "type": "string", + "enum": [ + "square", + "rounded", + "pill" + ], + "nullable": true + }, + "radiusPx": { + "type": "number", + "minimum": 0, + "maximum": 999, + "nullable": true + }, + "qrLogoMode": { + "type": "string", + "enum": [ + "none", + "custom", + "organization", + "project" + ] + }, + "qrLogoStorageId": { + "type": "string", + "nullable": true + }, + "qrLogoSourceStorageId": { + "type": "string", + "nullable": true + }, + "historySync": { + "type": "string", + "enum": [ + "ask", + "force_on", + "force_off" + ] + }, + "methods": { + "type": "array", + "nullable": true, + "minItems": 1, + "maxItems": 50, + "uniqueItems": true, + "items": { + "type": "string", + "enum": [ + "qr", + "pairing", + "cloud-api" + ] + } + } + } + }, + "FlowId": { + "type": "string", + "format": "uuid", + "description": "Polymorfa Flow draft UUID." + }, + "FlowSummary": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "$ref": "#/components/schemas/FlowId" + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 120 + }, + "status": { + "type": "string", + "enum": [ + "draft", + "ready", + "archived" + ] + }, + "version": { + "type": "string" + }, + "screenCount": { + "type": "integer", + "minimum": 0, + "maximum": 50 + }, + "metaLinks": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": true + } + }, + "createdAt": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "updatedAt": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + }, + "required": [ + "id", + "name", + "status", + "version", + "screenCount", + "metaLinks", + "createdAt", + "updatedAt" + ] + }, + "FlowDraft": { + "allOf": [ + { + "$ref": "#/components/schemas/FlowSummary" + }, + { + "type": "object", + "properties": { + "definition": { + "type": "object", + "additionalProperties": true + } + }, + "required": [ + "definition" + ] + } + ] + }, + "CreateFlowRequest": { + "type": "object", + "additionalProperties": false, + "properties": { + "projectId": { + "$ref": "#/components/schemas/ProjectId" + }, + "draftId": { + "$ref": "#/components/schemas/FlowId" + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 120 + }, + "definition": { + "type": "object", + "additionalProperties": true + } + }, + "required": [ + "projectId", + "name", + "definition" + ] + }, + "UpdateFlowRequest": { + "type": "object", + "additionalProperties": false, + "properties": { + "projectId": { + "$ref": "#/components/schemas/ProjectId" + }, + "expectedUpdatedAt": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 120 + }, + "status": { + "type": "string", + "enum": [ + "draft", + "ready", + "archived" + ] + }, + "definition": { + "type": "object", + "additionalProperties": true + } + }, + "required": [ + "projectId", + "expectedUpdatedAt" + ] + }, + "DeleteFlowResult": { + "type": "object", + "additionalProperties": false, + "properties": { + "ok": { + "type": "boolean", + "enum": [ + true + ] + } + }, + "required": [ + "ok" + ] + }, + "ManagementTemplate": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "$ref": "#/components/schemas/TemplateId" + }, + "createdAt": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 512 + }, + "category": { + "type": "string" + }, + "language": { + "type": "string" + }, + "status": { + "type": "string" + }, + "kind": { + "type": "string" + }, + "definition": { + "type": "object", + "additionalProperties": true, + "nullable": true + }, + "sampleValues": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "nullable": true + }, + "cloudLinks": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": true + } + }, + "updatedAt": { + "type": "integer", + "format": "int64", + "minimum": 0 + } + }, + "required": [ + "id", + "createdAt", + "name", + "category", + "language", + "status", + "kind", + "definition", + "sampleValues", + "cloudLinks", + "updatedAt" + ] + }, + "CreateManagementTemplateRequest": { + "type": "object", + "additionalProperties": false, + "properties": { + "projectId": { + "$ref": "#/components/schemas/ProjectId" + }, + "draftId": { + "$ref": "#/components/schemas/TemplateId" + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 512 + }, + "definition": { + "type": "object", + "additionalProperties": true + }, + "sampleValues": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "nullable": true + } + }, + "required": [ + "projectId", + "name", + "definition" + ] + }, + "UpdateManagementTemplateRequest": { + "type": "object", + "additionalProperties": false, + "properties": { + "projectId": { + "$ref": "#/components/schemas/ProjectId" + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 512 + }, + "status": { + "type": "string" + }, + "definition": { + "type": "object", + "additionalProperties": true + }, + "sampleValues": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "nullable": true + } + }, + "required": [ + "projectId" + ] + }, + "DeleteManagementTemplateResult": { + "type": "object", + "additionalProperties": false, + "properties": { + "ok": { + "type": "boolean", + "enum": [ + true + ] + } + }, + "required": [ + "ok" + ] + }, + "SessionIdentifier": { + "type": "string", + "minLength": 1, + "maxLength": 64, + "description": "Database session UUID or stable session slug." + }, + "SessionProjectContext": { + "type": "object", + "additionalProperties": false, + "properties": { + "projectId": { + "$ref": "#/components/schemas/ProjectId" + } + } + }, + "SessionTierOverrideRequest": { + "type": "object", + "additionalProperties": false, + "properties": { + "projectId": { + "$ref": "#/components/schemas/ProjectId" + }, + "tierOverride": { + "type": "string", + "enum": [ + "free", + "standard", + "pro" + ], + "nullable": true + } + }, + "required": [ + "tierOverride" + ] + }, + "SessionBatchRequest": { + "type": "object", + "additionalProperties": false, + "properties": { + "projectId": { + "$ref": "#/components/schemas/ProjectId" + }, + "sessionIds": { + "type": "array", + "minItems": 1, + "maxItems": 100, + "uniqueItems": true, + "items": { + "$ref": "#/components/schemas/SessionIdentifier" + } + }, + "ids": { + "type": "array", + "minItems": 1, + "maxItems": 100, + "uniqueItems": true, + "deprecated": true, + "description": "Compatibility alias for sessionIds.", + "items": { + "$ref": "#/components/schemas/SessionIdentifier" + } + } + }, + "anyOf": [ + { + "required": [ + "sessionIds" + ] + }, + { + "required": [ + "ids" + ] + } + ] + }, + "CreateTestingNumberRequest": { + "type": "object", + "additionalProperties": false, + "properties": { + "projectId": { + "$ref": "#/components/schemas/ProjectId" + }, + "customerId": { + "type": "string", + "format": "uuid", + "description": "Customer owner. Defaults to the protected Default customer when Customers is enabled." + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 100, + "description": "Optional Console display name." + }, + "country": { + "type": "string", + "enum": [ + "ES", + "DE", + "MX", + "GB", + "SA", + "IT", + "AF", + "AX", + "AL", + "DZ", + "AS", + "AD", + "AO", + "AI", + "AG", + "AR", + "AM", + "AW", + "AC", + "AU", + "AT", + "AZ", + "BS", + "BH", + "BD", + "BB", + "BY", + "BE", + "BZ", + "BJ", + "BM", + "BT", + "BO", + "BQ", + "BA", + "BW", + "BR", + "IO", + "VG", + "BN", + "BG", + "BF", + "BI", + "CI", + "KH", + "CM", + "CA", + "CV", + "KY", + "CF", + "TD", + "CL", + "CN", + "CX", + "CC", + "CO", + "KM", + "CG", + "CD", + "CK", + "CR", + "HR", + "CU", + "CW", + "CY", + "CZ", + "DK", + "DJ", + "DM", + "DO", + "EC", + "EG", + "SV", + "GQ", + "ER", + "EE", + "ET", + "FK", + "FO", + "FJ", + "FI", + "FR", + "GF", + "PF", + "GA", + "GM", + "GE", + "GH", + "GI", + "GR", + "GL", + "GD", + "GP", + "GU", + "GT", + "GG", + "GN", + "GW", + "GY", + "HT", + "HN", + "HK", + "HU", + "IS", + "IN", + "ID", + "IR", + "IQ", + "IE", + "IM", + "IL", + "JM", + "JP", + "JE", + "JO", + "KZ", + "KE", + "KI", + "KW", + "KG", + "LA", + "LV", + "LB", + "LS", + "LR", + "LY", + "LI", + "LT", + "LU", + "MO", + "MK", + "MG", + "MW", + "MY", + "MV", + "ML", + "MT", + "MH", + "MQ", + "MR", + "MU", + "YT", + "FM", + "MD", + "MC", + "MN", + "ME", + "MS", + "MA", + "MZ", + "MM", + "NA", + "NR", + "NP", + "NL", + "NC", + "NZ", + "NI", + "NE", + "NG", + "NU", + "NF", + "KP", + "MP", + "NO", + "OM", + "PK", + "PW", + "PS", + "PA", + "PG", + "PY", + "PE", + "PH", + "PL", + "PT", + "PR", + "QA", + "RO", + "RU", + "RW", + "RE", + "BL", + "SH", + "KN", + "LC", + "MF", + "PM", + "VC", + "WS", + "SM", + "SN", + "RS", + "SC", + "SL", + "SG", + "SX", + "SK", + "SI", + "SB", + "SO", + "ZA", + "KR", + "SS", + "LK", + "SD", + "SR", + "SJ", + "SZ", + "SE", + "CH", + "SY", + "ST", + "TW", + "TJ", + "TZ", + "TH", + "TL", + "TG", + "TK", + "TO", + "TT", + "TN", + "TR", + "TM", + "TC", + "TV", + "VI", + "UG", + "UA", + "AE", + "US", + "UY", + "UZ", + "VU", + "VA", + "VE", + "VN", + "WF", + "YE", + "ZM", + "ZW", + "XK" + ], + "default": "US", + "description": "WhatsApp-supported ISO 3166-1 alpha-2 country used to generate a realistic E.164 identity." + } + }, + "required": [ + "projectId" + ] + }, + "ManagedSession": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "sessionId": { + "type": "string", + "description": "Stable session slug." + }, + "status": { + "type": "string" + }, + "tierOverride": { + "type": "string", + "enum": [ + "free", + "standard", + "pro" + ], + "nullable": true + } + }, + "required": [ + "id", + "sessionId", + "status", + "tierOverride" + ] + }, + "PlatformSession": { + "type": "object", + "additionalProperties": false, + "properties": { + "_id": { + "type": "string", + "format": "uuid" + }, + "_creationTime": { + "type": "number", + "description": "Creation time as Unix epoch milliseconds." + }, + "projectId": { + "$ref": "#/components/schemas/ProjectId" + }, + "sessionId": { + "$ref": "#/components/schemas/SessionIdentifier" + }, + "name": { + "type": "string", + "nullable": true + }, + "phone": { + "type": "string", + "nullable": true + }, + "platform": { + "type": "string", + "nullable": true + }, + "isBusiness": { + "type": "boolean" + }, + "testMode": { + "type": "boolean" + }, + "tierOverride": { + "type": "string", + "enum": [ + "free", + "standard", + "pro", + "scale" + ], + "nullable": true + }, + "status": { + "type": "string", + "description": "Latest runtime connection status." + }, + "statusReason": { + "type": "string", + "nullable": true, + "description": "Machine-readable reason for the latest connection status, when available." + }, + "messageCount": { + "type": "integer", + "minimum": 0 + }, + "lastActiveAt": { + "type": "number", + "nullable": true, + "description": "Last activity time as Unix epoch milliseconds." + }, + "customer": { + "type": "object", + "nullable": true, + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string", + "nullable": true + }, + "isDefault": { + "type": "boolean" + } + }, + "required": [ + "id", + "name", + "isDefault" + ] + }, + "claim": { + "oneOf": [ + { + "type": "object", + "additionalProperties": false, + "properties": { + "kind": { + "type": "string", + "enum": [ + "unclaimed" + ] + } + }, + "required": [ + "kind" + ] + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "kind": { + "type": "string", + "enum": [ + "claimed-elsewhere" + ] + }, + "displayName": { + "type": "string" + }, + "avatarUrl": { + "type": "string", + "nullable": true + }, + "avatarSeed": { + "type": "string" + }, + "claimedAt": { + "type": "number" + } + }, + "required": [ + "kind", + "displayName", + "avatarUrl", + "avatarSeed", + "claimedAt" + ] + } + ] + } + }, + "required": [ + "_id", + "_creationTime", + "projectId", + "sessionId", + "name", + "phone", + "platform", + "isBusiness", + "testMode", + "tierOverride", + "status", + "statusReason", + "messageCount", + "lastActiveAt", + "customer", + "claim" + ] + }, + "SessionStopResult": { + "type": "object", + "additionalProperties": false, + "properties": { + "stopping": { + "type": "boolean", + "enum": [ + true + ] + }, + "sessionId": { + "type": "string", + "format": "uuid" + } + }, + "required": [ + "stopping", + "sessionId" + ] + }, + "SessionStartResult": { + "type": "object", + "additionalProperties": false, + "properties": { + "starting": { + "type": "boolean", + "enum": [ + true + ] + }, + "sessionId": { + "type": "string", + "format": "uuid" + } + }, + "required": [ + "starting", + "sessionId" + ] + }, + "SessionRemoveResult": { + "type": "object", + "additionalProperties": false, + "properties": { + "removed": { + "type": "boolean", + "enum": [ + true + ] + }, + "sessionId": { + "type": "string", + "format": "uuid" + } + }, + "required": [ + "removed", + "sessionId" + ] + }, + "SessionBatchStopResult": { + "type": "object", + "additionalProperties": false, + "properties": { + "stopping": { + "type": "integer", + "minimum": 0, + "maximum": 100 + } + }, + "required": [ + "stopping" + ] + }, + "SessionBatchRemoveResult": { + "type": "object", + "additionalProperties": false, + "properties": { + "removed": { + "type": "integer", + "minimum": 0, + "maximum": 100 + } + }, + "required": [ + "removed" + ] + }, + "TestingSessionId": { + "type": "string", + "pattern": "^test_[A-Za-z0-9_-]{16}$", + "description": "Generated testing-session slug." + }, + "ProductionEnrollmentRequest": { + "type": "object", + "additionalProperties": false, + "properties": { + "business": { + "type": "object", + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "minLength": 2, + "maxLength": 120 + }, + "website": { + "type": "string", + "format": "uri", + "pattern": "^https://", + "maxLength": 2048 + }, + "supportEmail": { + "type": "string", + "format": "email", + "maxLength": 320 + } + }, + "required": [ + "name", + "website", + "supportEmail" + ] + } + }, + "required": [ + "business" + ] + }, + "ProductionEnrollmentResult": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "$ref": "#/components/schemas/ProjectId" + }, + "orgId": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + }, + "slug": { + "type": "string" + }, + "stage": { + "type": "string", + "enum": [ + "development" + ] + }, + "operationId": { + "type": "string", + "format": "uuid" + }, + "enrollmentStatus": { + "type": "string", + "enum": [ + "requested", + "approval_required", + "provisioning", + "ready" + ] + } + }, + "required": [ + "id", + "orgId", + "name", + "slug", + "stage", + "operationId", + "enrollmentStatus" + ] + }, + "ProductionEnrollmentCommandResult": { + "type": "object", + "additionalProperties": false, + "properties": { + "operationId": { + "type": "string", + "format": "uuid" + }, + "action": { + "type": "string", + "enum": [ + "approve", + "cancel" + ] + }, + "accepted": { + "type": "boolean", + "enum": [ + true + ] + } + }, + "required": [ + "operationId", + "action", + "accepted" + ] + }, + "CursorPageMetadata": { + "type": "object", + "additionalProperties": false, + "properties": { + "nextCursor": { + "type": "string", + "nullable": true + }, + "hasMore": { + "type": "boolean" + } + }, + "required": [ + "nextCursor", + "hasMore" + ] + }, + "BanSafeHealthProbabilities": { + "type": "object", + "additionalProperties": false, + "properties": { + "healthy": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "limited": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "restricted": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "banned": { + "type": "number", + "minimum": 0, + "maximum": 1 + } + }, + "required": [ + "healthy", + "limited", + "restricted", + "banned" + ] + }, + "BanSafeObservedAccountState": { + "type": "object", + "additionalProperties": false, + "description": "Direct account-state evidence. This is not an ML estimate.", + "properties": { + "state": { + "type": "string", + "enum": [ + "healthy", + "limited", + "restricted", + "banned" + ] + }, + "observedAt": { + "type": "string", + "format": "date-time" + }, + "source": { + "type": "string", + "enum": [ + "account_check", + "restriction_event" + ] + } + }, + "required": [ + "state", + "observedAt", + "source" + ] + }, + "BanSafeHealthExplanationFactor": { + "type": "object", + "additionalProperties": false, + "description": "One factual rules-v1 input. penalty is the number of Health points this input subtracts.", + "properties": { + "group": { + "type": "string", + "enum": [ + "direct_condition", + "delivery", + "connection", + "conduct", + "cadence" + ] + }, + "key": { + "type": "string", + "enum": [ + "observed_limited", + "observed_restricted", + "observed_banned", + "send_failures", + "receipt_errors", + "server_ack_tail", + "connection_failures", + "connection_churn", + "connection_disconnected", + "auto_reconnect_errors", + "keep_alive_errors", + "unanswered_first_contacts", + "unsolicited_sends", + "send_burst", + "fixed_send_rhythm" + ] + }, + "penalty": { + "type": "number", + "minimum": 0, + "maximum": 100 + }, + "observedValue": { + "type": "number" + }, + "sampleSize": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "group", + "key", + "penalty", + "observedValue", + "sampleSize" + ] + }, + "BanSafeHealthExplanation": { + "type": "object", + "additionalProperties": false, + "description": "Bounded rules-v1 inputs and deductions. It is not a forecast or confidence score.", + "properties": { + "penalties": { + "type": "object", + "additionalProperties": false, + "properties": { + "conduct": { + "type": "number", + "minimum": 0, + "maximum": 100 + }, + "delivery": { + "type": "number", + "minimum": 0, + "maximum": 100 + }, + "connection": { + "type": "number", + "minimum": 0, + "maximum": 100 + }, + "restriction": { + "type": "number", + "minimum": 0, + "maximum": 100 + }, + "total": { + "type": "number", + "minimum": 0, + "maximum": 100 + } + }, + "required": [ + "conduct", + "delivery", + "connection", + "restriction", + "total" + ] + }, + "factors": { + "type": "array", + "maxItems": 8, + "items": { + "$ref": "#/components/schemas/BanSafeHealthExplanationFactor" + } + }, + "measuredGroups": { + "type": "array", + "maxItems": 5, + "uniqueItems": true, + "items": { + "type": "string", + "enum": [ + "direct_condition", + "delivery", + "connection", + "conduct", + "cadence" + ] + } + }, + "missingGroups": { + "type": "array", + "maxItems": 5, + "uniqueItems": true, + "items": { + "type": "string", + "enum": [ + "direct_condition", + "delivery", + "connection", + "conduct", + "cadence" + ] + } + } + }, + "required": [ + "penalties", + "factors", + "measuredGroups", + "missingGroups" + ] + }, + "BanSafeSignalDefinition": { + "type": "object", + "additionalProperties": false, + "properties": { + "key": { + "type": "string" + }, + "label": { + "type": "string" + }, + "group": { + "type": "string" + }, + "kind": { + "type": "string", + "enum": [ + "number", + "boolean", + "enum", + "histogram", + "code_counts" + ] + }, + "unit": { + "type": "string", + "enum": [ + "count", + "milliseconds", + "unix_milliseconds", + "ratio", + "none" + ] + }, + "description": { + "type": "string" + } + }, + "required": [ + "key", + "label", + "group", + "kind", + "unit", + "description" + ] + }, + "BanSafeSignalCodeCount": { + "type": "object", + "additionalProperties": false, + "properties": { + "code": { + "type": "integer", + "minimum": 0 + }, + "count": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "code", + "count" + ] + }, + "BanSafeSignal": { + "type": "object", + "additionalProperties": false, + "properties": { + "key": { + "type": "string" + }, + "label": { + "type": "string" + }, + "group": { + "type": "string" + }, + "kind": { + "type": "string", + "enum": [ + "number", + "boolean", + "enum", + "histogram", + "code_counts" + ] + }, + "unit": { + "type": "string", + "enum": [ + "count", + "milliseconds", + "unix_milliseconds", + "ratio", + "none" + ] + }, + "description": { + "type": "string" + }, + "measured": { + "type": "boolean" + }, + "value": { + "nullable": true, + "oneOf": [ + { + "type": "number" + }, + { + "type": "boolean" + }, + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "number" + } + } + ] + }, + "sampleSize": { + "type": "integer", + "minimum": 0, + "nullable": true + }, + "codes": { + "type": "array", + "nullable": true, + "items": { + "$ref": "#/components/schemas/BanSafeSignalCodeCount" + } + } + }, + "required": [ + "key", + "label", + "group", + "kind", + "unit", + "description", + "measured", + "value", + "sampleSize", + "codes" + ] + }, + "BanSafeCollectionStatus": { + "type": "object", + "additionalProperties": false, + "properties": { + "state": { + "type": "string", + "enum": [ + "fresh", + "stale", + "not_collected", + "unsupported" + ] + }, + "latestFlushedAt": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "latestReceivedAt": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "freshUntil": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "recordVersion": { + "type": "integer", + "minimum": 0, + "nullable": true + }, + "collectorVersion": { + "type": "integer", + "minimum": 0, + "nullable": true + }, + "partial": { + "type": "boolean", + "nullable": true + }, + "droppedRecords": { + "type": "integer", + "minimum": 0, + "nullable": true + } + }, + "required": [ + "state", + "latestFlushedAt", + "latestReceivedAt", + "freshUntil", + "recordVersion", + "collectorVersion", + "partial", + "droppedRecords" + ] + }, + "BanSafeTelemetrySnapshot": { + "type": "object", + "additionalProperties": false, + "properties": { + "bucketStart": { + "type": "string", + "format": "date-time" + }, + "flushedAt": { + "type": "string", + "format": "date-time" + }, + "receivedAt": { + "type": "string", + "format": "date-time" + }, + "partial": { + "type": "boolean" + }, + "recordVersion": { + "type": "integer", + "minimum": 0, + "nullable": true + }, + "signals": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BanSafeSignal" + } + } + }, + "required": [ + "bucketStart", + "flushedAt", + "receivedAt", + "partial", + "recordVersion", + "signals" + ] + }, + "BanSafeCollectionSession": { + "type": "object", + "additionalProperties": false, + "properties": { + "sessionId": { + "type": "string", + "format": "uuid" + }, + "session": { + "type": "string" + }, + "projectId": { + "type": "string", + "format": "uuid" + }, + "collection": { + "$ref": "#/components/schemas/BanSafeCollectionStatus" + } + }, + "required": [ + "sessionId", + "session", + "projectId", + "collection" + ] + }, + "BanSafeTelemetryDetail": { + "type": "object", + "additionalProperties": false, + "properties": { + "sessionId": { + "type": "string", + "format": "uuid" + }, + "session": { + "type": "string" + }, + "projectId": { + "type": "string", + "format": "uuid" + }, + "collection": { + "$ref": "#/components/schemas/BanSafeCollectionStatus" + }, + "snapshot": { + "nullable": true, + "allOf": [ + { + "$ref": "#/components/schemas/BanSafeTelemetrySnapshot" + } + ] + } + }, + "required": [ + "sessionId", + "session", + "projectId", + "collection", + "snapshot" + ] + }, + "BanSafeHealthAction": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "sessionId": { + "type": "string", + "format": "uuid" + }, + "session": { + "type": "string" + }, + "projectId": { + "type": "string", + "format": "uuid" + }, + "mode": { + "type": "string", + "enum": [ + "apply", + "clear" + ] + }, + "action": { + "type": "string", + "enum": [ + "stop", + "slow_down", + "log_out", + "email", + "webhook" + ] + }, + "status": { + "type": "string", + "enum": [ + "pending", + "running", + "succeeded", + "failed", + "cancelled" + ] + }, + "health": { + "type": "number", + "minimum": 0, + "maximum": 100 + }, + "threshold": { + "type": "number", + "minimum": 0, + "maximum": 100 + }, + "healthSource": { + "type": "string", + "enum": [ + "rules_v1", + "ml_model" + ] + }, + "estimatorVersion": { + "type": "string" + }, + "modelVersion": { + "type": "string", + "nullable": true + }, + "slowDownMps": { + "type": "number", + "minimum": 0, + "exclusiveMinimum": true, + "nullable": true + }, + "evaluatedAt": { + "type": "string", + "format": "date-time" + }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "completedAt": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "outcome": { + "type": "string", + "nullable": true, + "enum": [ + "applied", + "cleared", + "notification_queued", + "superseded", + "expired", + "not_applied", + "delivery_failed" + ] + } + }, + "required": [ + "id", + "sessionId", + "session", + "projectId", + "mode", + "action", + "status", + "health", + "threshold", + "healthSource", + "estimatorVersion", + "modelVersion", + "slowDownMps", + "evaluatedAt", + "createdAt", + "completedAt", + "outcome" + ] + }, + "BanSafeNumberEnforcement": { + "type": "object", + "additionalProperties": false, + "properties": { + "rung": { + "type": "string", + "enum": [ + "none", + "notify", + "throttle", + "block_cold", + "suspend" + ] + }, + "previousRung": { + "type": "string", + "enum": [ + "none", + "notify", + "throttle", + "block_cold", + "suspend" + ] + }, + "organizationFloor": { + "type": "string", + "enum": [ + "none", + "notify", + "throttle", + "block_cold", + "suspend" + ], + "description": "The lowest restriction every number in this workspace is held to." + }, + "reason": { + "type": "string" + }, + "source": { + "type": "string", + "enum": [ + "automatic", + "operator" + ] + }, + "throughputPerMinute": { + "type": "number", + "nullable": true, + "description": "Messages per minute this number is paced to, or null when it is not paced." + }, + "blocksUnsolicited": { + "type": "boolean", + "description": "First messages to people who never wrote to this number are refused outside Campaigns." + }, + "suspended": { + "type": "boolean", + "description": "This number cannot originate a message. It still receives, reads, and shows presence." + }, + "startedAt": { + "type": "string", + "format": "date-time" + }, + "eligibleLiftAt": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "exitProgress": { + "type": "integer", + "minimum": 0, + "description": "Consecutive checks already passed toward lifting." + }, + "blockingFindings": { + "type": "array", + "items": { + "type": "string" + } + }, + "operatorHold": { + "type": "boolean" + }, + "appealState": { + "type": "string", + "enum": [ + "none", + "requested", + "granted", + "denied" + ] + }, + "state": { + "type": "string", + "enum": [ + "applied", + "applying" + ], + "description": "`applying` while the number has not confirmed the restriction." + } + }, + "required": [ + "rung", + "previousRung", + "organizationFloor", + "reason", + "source", + "throughputPerMinute", + "blocksUnsolicited", + "suspended", + "startedAt", + "eligibleLiftAt", + "exitProgress", + "blockingFindings", + "operatorHold", + "appealState", + "state" + ] + }, + "BanSafeNumber": { + "type": "object", + "additionalProperties": false, + "properties": { + "sessionId": { + "type": "string", + "format": "uuid" + }, + "session": { + "type": "string" + }, + "phoneNumber": { + "type": "string" + }, + "projectId": { + "type": "string", + "format": "uuid" + }, + "health": { + "type": "number", + "minimum": 0, + "maximum": 100, + "nullable": true, + "description": "Estimate of present account Health. Higher is healthier. Read healthSource, healthReliability, and healthFeatureCoverage with it." + }, + "band": { + "type": "string", + "enum": [ + "good", + "fair", + "poor", + "failing", + "unknown" + ] + }, + "healthSource": { + "type": "string", + "enum": [ + "rules_v1", + "ml_model", + "unavailable" + ], + "description": "Estimator family. rules_v1 is deterministic; unavailable carries no numeric Health." + }, + "healthEstimatorVersion": { + "type": "string", + "nullable": true, + "description": "Version of the estimator that produced Health." + }, + "healthModelVersion": { + "type": "string", + "nullable": true, + "description": "Learned-model artifact version. Null for rules_v1." + }, + "healthEvaluatedAt": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "healthFeatureCoverage": { + "type": "number", + "minimum": 0, + "maximum": 1, + "nullable": true + }, + "healthReliability": { + "type": "string", + "enum": [ + "rules_based", + "validated", + "unavailable" + ], + "description": "Support category, not a confidence score." + }, + "healthUnavailableReason": { + "type": "string", + "nullable": true, + "enum": [ + "no_active_model", + "invalid_active_model", + "insufficient_fresh_features", + null + ] + }, + "healthProbabilities": { + "nullable": true, + "allOf": [ + { + "$ref": "#/components/schemas/BanSafeHealthProbabilities" + } + ] + }, + "mostLikelyHealthState": { + "type": "string", + "enum": [ + "healthy", + "limited", + "restricted", + "banned" + ], + "nullable": true + }, + "healthExplanation": { + "nullable": true, + "allOf": [ + { + "$ref": "#/components/schemas/BanSafeHealthExplanation" + } + ] + }, + "observedAccountState": { + "nullable": true, + "allOf": [ + { + "$ref": "#/components/schemas/BanSafeObservedAccountState" + } + ] + }, + "enforcement": { + "nullable": true, + "allOf": [ + { + "$ref": "#/components/schemas/BanSafeNumberEnforcement" + } + ] + } + }, + "required": [ + "sessionId", + "session", + "phoneNumber", + "projectId", + "health", + "band", + "healthSource", + "healthEstimatorVersion", + "healthModelVersion", + "healthEvaluatedAt", + "healthFeatureCoverage", + "healthReliability", + "healthUnavailableReason", + "healthProbabilities", + "mostLikelyHealthState", + "healthExplanation", + "observedAccountState", + "enforcement" + ] + }, + "BanSafeFinding": { + "type": "object", + "additionalProperties": false, + "description": "One safety finding, with the sentences to show a customer. A `not_measured` entry has no stored lifecycle and reports null timestamps; it is never reported as resolved and never omitted.", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "nullable": true + }, + "key": { + "type": "string", + "maxLength": 64 + }, + "title": { + "type": "string", + "description": "Customer-visible name of the check. A `not_measured` entry carries the same title as a stored one." + }, + "summary": { + "type": "string", + "description": "The evidence sentence for this finding, with the numbers from `evidence` already filled in. A number the check could not read reads as `unknown`, and a `not_measured` entry therefore reads as the sentence with no numbers in it. Empty for a key Polymorfa has retired." + }, + "fix": { + "type": "string", + "description": "What to change to clear the finding. Empty for a key Polymorfa has retired." + }, + "status": { + "type": "string", + "enum": [ + "open", + "acknowledged", + "resolved", + "not_measured" + ] + }, + "severity": { + "type": "string", + "enum": [ + "info", + "warning", + "critical" + ], + "nullable": true + }, + "occurrences": { + "type": "integer", + "minimum": 0 + }, + "reopenedCount": { + "type": "integer", + "minimum": 0 + }, + "evidence": { + "type": "object", + "additionalProperties": true, + "description": "Numbers only. Never message content, a message identifier, or a recipient identifier." + }, + "sessionId": { + "type": "string", + "format": "uuid" + }, + "session": { + "type": "string" + }, + "phoneNumber": { + "type": "string" + }, + "firstSeenAt": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "lastSeenAt": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "acknowledgedAt": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "acknowledgedBy": { + "type": "string", + "nullable": true + }, + "acknowledgementNote": { + "type": "string", + "nullable": true, + "maxLength": 500 + }, + "snoozedUntil": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "resolvedAt": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "resolveReason": { + "type": "string", + "nullable": true, + "enum": [ + "clean", + "key_retired", + "number_removed", + "stale", + null + ] + } + }, + "required": [ + "id", + "key", + "title", + "summary", + "fix", + "status", + "severity", + "occurrences", + "reopenedCount", + "evidence", + "sessionId", + "session", + "phoneNumber", + "firstSeenAt", + "lastSeenAt", + "acknowledgedAt", + "acknowledgedBy", + "acknowledgementNote", + "snoozedUntil", + "resolvedAt", + "resolveReason" + ] + }, + "BanSafeNumberDetail": { + "type": "object", + "additionalProperties": false, + "properties": { + "health": { + "type": "number", + "minimum": 0, + "maximum": 100, + "nullable": true, + "description": "Estimate of present account Health. Higher is healthier. Read healthSource, healthReliability, and healthFeatureCoverage with it." + }, + "band": { + "type": "string", + "enum": [ + "good", + "fair", + "poor", + "failing", + "unknown" + ] + }, + "healthSource": { + "type": "string", + "enum": [ + "rules_v1", + "ml_model", + "unavailable" + ], + "description": "Estimator family. rules_v1 is deterministic; unavailable carries no numeric Health." + }, + "healthEstimatorVersion": { + "type": "string", + "nullable": true, + "description": "Version of the estimator that produced Health." + }, + "healthModelVersion": { + "type": "string", + "nullable": true, + "description": "Learned-model artifact version. Null for rules_v1." + }, + "healthEvaluatedAt": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "healthFeatureCoverage": { + "type": "number", + "minimum": 0, + "maximum": 1, + "nullable": true + }, + "healthReliability": { + "type": "string", + "enum": [ + "rules_based", + "validated", + "unavailable" + ], + "description": "Support category, not a confidence score." + }, + "healthUnavailableReason": { + "type": "string", + "nullable": true, + "enum": [ + "no_active_model", + "invalid_active_model", + "insufficient_fresh_features", + null + ] + }, + "healthProbabilities": { + "nullable": true, + "allOf": [ + { + "$ref": "#/components/schemas/BanSafeHealthProbabilities" + } + ] + }, + "mostLikelyHealthState": { + "type": "string", + "enum": [ + "healthy", + "limited", + "restricted", + "banned" + ], + "nullable": true + }, + "healthExplanation": { + "nullable": true, + "allOf": [ + { + "$ref": "#/components/schemas/BanSafeHealthExplanation" + } + ] + }, + "observedAccountState": { + "nullable": true, + "allOf": [ + { + "$ref": "#/components/schemas/BanSafeObservedAccountState" + } + ] + }, + "warmup": { + "$ref": "#/components/schemas/BanSafeNumberWarmup" + }, + "findings": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BanSafeFinding" + } + }, + "liftRequires": { + "type": "string", + "nullable": true, + "description": "The exact remaining condition for the restriction to lift." + }, + "appealState": { + "type": "string", + "enum": [ + "none", + "requested", + "granted", + "denied" + ] + } + }, + "required": [ + "sessionId", + "session", + "phoneNumber", + "projectId", + "health", + "band", + "healthSource", + "healthEstimatorVersion", + "healthModelVersion", + "healthEvaluatedAt", + "healthFeatureCoverage", + "healthReliability", + "healthUnavailableReason", + "healthProbabilities", + "mostLikelyHealthState", + "healthExplanation", + "observedAccountState", + "enforcement", + "warmup", + "findings", + "liftRequires", + "appealState" + ] + }, + "BanSafeNumberWarmup": { + "type": "object", + "additionalProperties": false, + "properties": { + "enabled": { + "type": "boolean" + }, + "tenureSource": { + "type": "string", + "enum": [ + "history", + "link", + "plan" + ], + "nullable": true, + "description": "Retained evidence anchoring the ramp; null when legacy evidence cannot be classified." + }, + "tenureDay": { + "type": "integer", + "minimum": 0, + "description": "Whole days since the number's known tenure lower bound; zero when unknown." + }, + "allowance": { + "type": "integer", + "minimum": 0, + "nullable": true, + "description": "Messages allowed today; null when the plan is disabled." + }, + "sentToday": { + "type": "integer", + "minimum": 0, + "nullable": true, + "description": "Durable reservations in the active allowance window. Successful current reads return 0 before the first reservation; null remains accepted for older stored responses." + }, + "resetsAt": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "curve": { + "type": "array", + "items": { + "$ref": "#/components/schemas/WarmupCurvePoint" + } + } + }, + "required": [ + "enabled", + "tenureSource", + "tenureDay", + "allowance", + "sentToday", + "resetsAt", + "curve" + ] + }, + "ProjectInsuranceEvidence": { + "type": "object", + "additionalProperties": false, + "properties": { + "projectId": { + "type": "string", + "format": "uuid" + }, + "enabled": { + "type": "boolean" + }, + "banInsuranceIncluded": { + "type": "boolean" + } + }, + "required": [ + "projectId", + "enabled", + "banInsuranceIncluded" + ] + }, + "UpdateProjectInsuranceEvidenceInput": { + "type": "object", + "additionalProperties": false, + "properties": { + "enabled": { + "type": "boolean" + } + }, + "required": [ + "enabled" + ] + }, + "BanSafeHealthPoint": { + "type": "object", + "additionalProperties": false, + "properties": { + "health": { + "type": "number", + "minimum": 0, + "maximum": 100, + "nullable": true + }, + "band": { + "type": "string", + "enum": [ + "good", + "fair", + "poor", + "failing", + "unknown" + ], + "nullable": true + }, + "healthSource": { + "type": "string", + "enum": [ + "rules_v1", + "ml_model", + "unavailable" + ] + }, + "healthEstimatorVersion": { + "type": "string", + "nullable": true + }, + "healthModelVersion": { + "type": "string", + "nullable": true + }, + "healthEvaluatedAt": { + "type": "string", + "format": "date-time" + }, + "healthFeatureCoverage": { + "type": "number", + "minimum": 0, + "maximum": 1, + "nullable": true + }, + "healthReliability": { + "type": "string", + "enum": [ + "rules_based", + "validated", + "unavailable" + ] + }, + "healthUnavailableReason": { + "type": "string", + "nullable": true, + "enum": [ + "no_active_model", + "invalid_active_model", + "insufficient_fresh_features", + null + ] + }, + "healthProbabilities": { + "nullable": true, + "allOf": [ + { + "$ref": "#/components/schemas/BanSafeHealthProbabilities" + } + ] + }, + "mostLikelyHealthState": { + "type": "string", + "enum": [ + "healthy", + "limited", + "restricted", + "banned" + ], + "nullable": true + }, + "healthExplanation": { + "nullable": true, + "allOf": [ + { + "$ref": "#/components/schemas/BanSafeHealthExplanation" + } + ] + }, + "observedAccountState": { + "nullable": true, + "allOf": [ + { + "$ref": "#/components/schemas/BanSafeObservedAccountState" + } + ] + } + }, + "required": [ + "health", + "band", + "healthSource", + "healthEstimatorVersion", + "healthModelVersion", + "healthEvaluatedAt", + "healthFeatureCoverage", + "healthReliability", + "healthUnavailableReason", + "healthProbabilities", + "mostLikelyHealthState", + "healthExplanation", + "observedAccountState" + ] + }, + "BanSafeHealthHistory": { + "type": "object", + "additionalProperties": false, + "properties": { + "sessionId": { + "type": "string", + "format": "uuid" + }, + "session": { + "type": "string" + }, + "points": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BanSafeHealthPoint" + } + } + }, + "required": [ + "sessionId", + "session", + "points" + ] + }, + "BanSafeFindingAcknowledgement": { + "type": "object", + "additionalProperties": false, + "properties": { + "finding": { + "$ref": "#/components/schemas/BanSafeFinding" + }, + "message": { + "type": "string", + "description": "The exact sentence shown in the console next to the button." + } + }, + "required": [ + "finding", + "message" + ] + }, + "BanSafeEnforcementSummary": { + "type": "object", + "additionalProperties": false, + "properties": { + "sessionId": { + "type": "string", + "format": "uuid" + }, + "session": { + "type": "string" + }, + "phoneNumber": { + "type": "string" + }, + "projectId": { + "type": "string", + "format": "uuid" + }, + "rung": { + "type": "string", + "enum": [ + "none", + "notify", + "throttle", + "block_cold", + "suspend" + ] + }, + "previousRung": { + "type": "string", + "enum": [ + "none", + "notify", + "throttle", + "block_cold", + "suspend" + ] + }, + "organizationFloor": { + "type": "string", + "enum": [ + "none", + "notify", + "throttle", + "block_cold", + "suspend" + ] + }, + "reason": { + "type": "string" + }, + "source": { + "type": "string", + "enum": [ + "automatic", + "operator" + ] + }, + "throughputPerMinute": { + "type": "number", + "nullable": true + }, + "blocksUnsolicited": { + "type": "boolean" + }, + "suspended": { + "type": "boolean" + }, + "health": { + "type": "number", + "minimum": 0, + "maximum": 100, + "nullable": true, + "description": "Estimate of present account Health. Higher is healthier. Read healthSource, healthReliability, and healthFeatureCoverage with it." + }, + "band": { + "type": "string", + "enum": [ + "good", + "fair", + "poor", + "failing", + "unknown" + ] + }, + "healthSource": { + "type": "string", + "enum": [ + "rules_v1", + "ml_model", + "unavailable" + ], + "description": "Estimator family. rules_v1 is deterministic; unavailable carries no numeric Health." + }, + "healthEstimatorVersion": { + "type": "string", + "nullable": true, + "description": "Version of the estimator that produced Health." + }, + "healthModelVersion": { + "type": "string", + "nullable": true, + "description": "Learned-model artifact version. Null for rules_v1." + }, + "healthEvaluatedAt": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "healthFeatureCoverage": { + "type": "number", + "minimum": 0, + "maximum": 1, + "nullable": true + }, + "healthReliability": { + "type": "string", + "enum": [ + "rules_based", + "validated", + "unavailable" + ], + "description": "Support category, not a confidence score." + }, + "healthUnavailableReason": { + "type": "string", + "nullable": true, + "enum": [ + "no_active_model", + "invalid_active_model", + "insufficient_fresh_features", + null + ] + }, + "healthProbabilities": { + "nullable": true, + "allOf": [ + { + "$ref": "#/components/schemas/BanSafeHealthProbabilities" + } + ] + }, + "mostLikelyHealthState": { + "type": "string", + "enum": [ + "healthy", + "limited", + "restricted", + "banned" + ], + "nullable": true + }, + "healthExplanation": { + "nullable": true, + "allOf": [ + { + "$ref": "#/components/schemas/BanSafeHealthExplanation" + } + ] + }, + "observedAccountState": { + "nullable": true, + "allOf": [ + { + "$ref": "#/components/schemas/BanSafeObservedAccountState" + } + ] + }, + "enforcement": { + "nullable": true, + "allOf": [ + { + "$ref": "#/components/schemas/BanSafeNumberEnforcement" + } + ] + }, + "blockingFindings": { + "type": "array", + "items": { + "type": "string" + } + }, + "startedAt": { + "type": "string", + "format": "date-time" + }, + "eligibleLiftAt": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "liftRequires": { + "type": "string" + }, + "operatorHold": { + "type": "boolean" + }, + "appealState": { + "type": "string", + "enum": [ + "none", + "requested", + "granted", + "denied" + ] + }, + "state": { + "type": "string", + "enum": [ + "applied", + "applying" + ] + } + }, + "required": [ + "sessionId", + "session", + "phoneNumber", + "projectId", + "rung", + "previousRung", + "organizationFloor", + "reason", + "source", + "throughputPerMinute", + "blocksUnsolicited", + "suspended", + "health", + "band", + "healthSource", + "healthEstimatorVersion", + "healthModelVersion", + "healthEvaluatedAt", + "healthFeatureCoverage", + "healthReliability", + "healthUnavailableReason", + "healthProbabilities", + "mostLikelyHealthState", + "healthExplanation", + "observedAccountState", + "blockingFindings", + "startedAt", + "eligibleLiftAt", + "liftRequires", + "operatorHold", + "appealState", + "state" + ] + }, + "BanSafeAppealReceipt": { + "type": "object", + "additionalProperties": false, + "properties": { + "sessionId": { + "type": "string", + "format": "uuid" + }, + "session": { + "type": "string" + }, + "rung": { + "type": "string", + "enum": [ + "none", + "notify", + "throttle", + "block_cold", + "suspend" + ] + }, + "appealState": { + "type": "string", + "enum": [ + "none", + "requested", + "granted", + "denied" + ] + }, + "requestedAt": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "liftRequires": { + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": [ + "sessionId", + "session", + "rung", + "appealState", + "requestedAt", + "liftRequires", + "message" + ] + }, + "BanSafeIncident": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "sessionId": { + "type": "string", + "format": "uuid" + }, + "session": { + "type": "string" + }, + "phoneNumber": { + "type": "string" + }, + "projectId": { + "type": "string", + "format": "uuid" + }, + "kind": { + "type": "string", + "enum": [ + "cap_warning", + "cap_reached", + "timelock", + "temporary_ban", + "permanent_ban", + "connect_blocked", + "customer_report" + ] + }, + "source": { + "type": "string", + "enum": [ + "runtime", + "customer" + ] + }, + "resolution": { + "type": "string" + }, + "ambiguous": { + "type": "boolean" + }, + "startedAt": { + "type": "string", + "format": "date-time" + }, + "endsAt": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "closedAt": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "closedBy": { + "type": "string", + "nullable": true + }, + "claimId": { + "type": "string", + "format": "uuid", + "nullable": true + }, + "note": { + "type": "string", + "nullable": true, + "maxLength": 500 + }, + "reportedBy": { + "type": "string", + "nullable": true + }, + "createdAt": { + "type": "string", + "format": "date-time" + } + }, + "required": [ + "id", + "sessionId", + "session", + "phoneNumber", + "projectId", + "kind", + "source", + "resolution", + "ambiguous", + "startedAt", + "endsAt", + "note", + "reportedBy", + "createdAt", + "closedAt", + "closedBy", + "claimId" + ] + }, + "BanSafeIncidentReceipt": { + "type": "object", + "additionalProperties": false, + "properties": { + "incidentId": { + "type": "string", + "format": "uuid" + }, + "created": { + "type": "boolean", + "description": "False when the same Idempotency-Key already recorded this report." + }, + "sessionId": { + "type": "string", + "format": "uuid" + }, + "session": { + "type": "string" + }, + "occurredAt": { + "type": "string", + "format": "date-time" + } + }, + "required": [ + "incidentId", + "created", + "sessionId", + "session", + "occurredAt" + ] + }, + "BanSafeClaimEvidence": { + "type": "object", + "additionalProperties": false, + "description": "Counts behind the attribution. Never a recipient, a message, or a device model.", + "properties": { + "attributionRuleVersion": { + "type": "integer", + "minimum": 1, + "nullable": true, + "description": "Attribution rules used when the claim was filed. Null for claims filed before rule versioning." + }, + "windowDays": { + "type": "integer", + "minimum": 1 + }, + "deviceEvidence": { + "type": "boolean", + "description": "Whether ban insurance evidence collection is on for the project." + }, + "otherDevices": { + "type": "integer", + "minimum": 0 + }, + "restrictedInWindow": { + "type": "boolean", + "description": "Whether Polymorfa was restricting this number's sending inside the window." + }, + "criticalFindingDays": { + "type": "integer", + "minimum": 0, + "description": "Days one safety check stayed at its most serious level inside the window." + }, + "sharedConnection": { + "type": "boolean", + "description": "Whether this number shared its connection with numbers that were being restricted." + }, + "measuredHours": { + "type": "integer", + "minimum": 0, + "description": "Hours of measured activity Polymorfa holds for the window." + } + }, + "required": [ + "attributionRuleVersion", + "windowDays", + "deviceEvidence", + "otherDevices", + "restrictedInWindow", + "criticalFindingDays", + "sharedConnection", + "measuredHours" + ] + }, + "BanSafeClaim": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "incidentId": { + "type": "string", + "format": "uuid" + }, + "sessionId": { + "type": "string", + "format": "uuid" + }, + "session": { + "type": "string" + }, + "phoneNumber": { + "type": "string" + }, + "projectId": { + "type": "string", + "format": "uuid" + }, + "status": { + "type": "string", + "enum": [ + "filed", + "under_review", + "approved", + "denied", + "paid", + "reversed" + ] + }, + "verdict": { + "type": "string", + "enum": [ + "other_device", + "customer_conduct", + "shared_network", + "ours", + "inconclusive" + ] + }, + "windowStart": { + "type": "string", + "format": "date-time" + }, + "windowEnd": { + "type": "string", + "format": "date-time" + }, + "measuredCents": { + "type": "integer", + "minimum": 0, + "description": "Credits this number consumed inside the window, in cents." + }, + "capCents": { + "type": "integer", + "minimum": 0, + "description": "The most a claim on this number's plan can return, in cents." + }, + "amountCents": { + "type": "integer", + "minimum": 0, + "description": "What this claim returns, in cents." + }, + "evidence": { + "$ref": "#/components/schemas/BanSafeClaimEvidence" + }, + "summary": { + "type": "string" + }, + "reason": { + "type": "string" + }, + "decidedAt": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "paidAt": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "createdAt": { + "type": "string", + "format": "date-time" + } + }, + "required": [ + "id", + "incidentId", + "sessionId", + "session", + "phoneNumber", + "projectId", + "status", + "verdict", + "windowStart", + "windowEnd", + "measuredCents", + "capCents", + "amountCents", + "evidence", + "summary", + "reason", + "decidedAt", + "paidAt", + "createdAt" + ] + }, + "AcknowledgeBanSafeFindingInput": { + "type": "object", + "additionalProperties": false, + "properties": { + "note": { + "type": "string", + "maxLength": 500 + }, + "snoozeDays": { + "type": "integer", + "minimum": 1, + "maximum": 30, + "description": "Silence this finding's notifications for this many days." + } + } + }, + "AppealBanSafeEnforcementInput": { + "type": "object", + "additionalProperties": false, + "properties": { + "note": { + "type": "string", + "minLength": 1, + "maxLength": 1000 + } + }, + "required": [ + "note" + ] + }, + "ReportBanSafeIncidentInput": { + "type": "object", + "additionalProperties": false, + "properties": { + "session": { + "type": "string", + "minLength": 1, + "maxLength": 256 + }, + "occurredAt": { + "type": "string", + "format": "date-time" + }, + "note": { + "type": "string", + "maxLength": 500 + } + }, + "required": [ + "session" + ] + }, + "SafeModeSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "presence": { + "type": "string", + "enum": [ + "dark", + "online_while_sending", + "online_hours" + ] + }, + "typing": { + "type": "string", + "enum": [ + "off", + "before_text", + "before_all" + ] + }, + "reads": { + "type": "string", + "enum": [ + "off", + "replied_chats", + "all_inbound" + ] + }, + "pacing": { + "type": "string", + "enum": [ + "off", + "jittered", + "conversation" + ] + }, + "onlineStart": { + "type": "integer", + "minimum": 0, + "maximum": 23 + }, + "onlineEnd": { + "type": "integer", + "minimum": 0, + "maximum": 23 + } + }, + "required": [ + "presence", + "typing", + "reads", + "pacing", + "onlineStart", + "onlineEnd" + ] + }, + "SafeModeOverride": { + "type": "object", + "additionalProperties": false, + "properties": { + "presence": { + "type": "string", + "enum": [ + "inherit", + "dark", + "online_while_sending", + "online_hours" + ] + }, + "typing": { + "type": "string", + "enum": [ + "inherit", + "off", + "before_text", + "before_all" + ] + }, + "reads": { + "type": "string", + "enum": [ + "inherit", + "off", + "replied_chats", + "all_inbound" + ] + }, + "pacing": { + "type": "string", + "enum": [ + "inherit", + "off", + "jittered", + "conversation" + ] + } + }, + "required": [ + "presence", + "typing", + "reads", + "pacing" + ] + }, + "SafeModeApplied": { + "type": "object", + "additionalProperties": false, + "description": "What the number itself last reported it is running. An observation, not a claim.", + "properties": { + "observedAt": { + "type": "string", + "format": "date-time" + }, + "presence": { + "type": "string", + "nullable": true + }, + "typing": { + "type": "string", + "nullable": true + }, + "reads": { + "type": "string", + "nullable": true + }, + "pacing": { + "type": "string", + "nullable": true + } + }, + "required": [ + "observedAt", + "presence", + "typing", + "reads", + "pacing" + ] + }, + "ProjectSafeMode": { + "type": "object", + "additionalProperties": false, + "properties": { + "projectId": { + "type": "string", + "format": "uuid" + }, + "ceiling": { + "$ref": "#/components/schemas/SafeModeSettings" + }, + "entitled": { + "type": "boolean", + "description": "Whether this project's plan includes BanSafe Lite, which Safe Mode is part of. When false, a request that raises a setting is refused." + }, + "entitlementReason": { + "type": "string", + "nullable": true, + "description": "Why a raise would be refused. Null when the plan includes BanSafe Lite." + } + }, + "required": [ + "projectId", + "ceiling", + "entitled", + "entitlementReason" + ] + }, + "SessionSafeMode": { + "type": "object", + "additionalProperties": false, + "properties": { + "session": { + "type": "string" + }, + "projectId": { + "type": "string", + "format": "uuid" + }, + "project": { + "$ref": "#/components/schemas/SafeModeSettings" + }, + "override": { + "$ref": "#/components/schemas/SafeModeOverride" + }, + "effective": { + "$ref": "#/components/schemas/SafeModeSettings" + }, + "applied": { + "type": "object", + "allOf": [ + { + "$ref": "#/components/schemas/SafeModeApplied" + } + ], + "nullable": true + }, + "mismatch": { + "type": "boolean", + "description": "True when the number reports something other than the policy in force." + }, + "entitled": { + "type": "boolean", + "description": "Whether this number's plan includes BanSafe Lite, which Safe Mode is part of. When false, a request that raises a setting is refused." + }, + "entitlementReason": { + "type": "string", + "nullable": true, + "description": "Why a raise would be refused. Null when the plan includes BanSafe Lite." + } + }, + "required": [ + "session", + "projectId", + "project", + "override", + "effective", + "applied", + "mismatch", + "entitled", + "entitlementReason" + ] + }, + "UpdateProjectSafeModeInput": { + "type": "object", + "additionalProperties": false, + "description": "A partial update: send only the settings you want to change.", + "properties": { + "presence": { + "type": "string", + "enum": [ + "dark", + "online_while_sending", + "online_hours" + ] + }, + "typing": { + "type": "string", + "enum": [ + "off", + "before_text", + "before_all" + ] + }, + "reads": { + "type": "string", + "enum": [ + "off", + "replied_chats", + "all_inbound" + ] + }, + "pacing": { + "type": "string", + "enum": [ + "off", + "jittered", + "conversation" + ] + }, + "onlineStart": { + "type": "integer", + "minimum": 0, + "maximum": 23 + }, + "onlineEnd": { + "type": "integer", + "minimum": 0, + "maximum": 23 + } + } + }, + "UpdateSessionSafeModeInput": { + "type": "object", + "additionalProperties": false, + "description": "A partial update. `inherit` follows the project ceiling.", + "properties": { + "presence": { + "type": "string", + "enum": [ + "inherit", + "dark", + "online_while_sending", + "online_hours" + ] + }, + "typing": { + "type": "string", + "enum": [ + "inherit", + "off", + "before_text", + "before_all" + ] + }, + "reads": { + "type": "string", + "enum": [ + "inherit", + "off", + "replied_chats", + "all_inbound" + ] + }, + "pacing": { + "type": "string", + "enum": [ + "inherit", + "off", + "jittered", + "conversation" + ] + } + } + }, + "WarmupPlanSettings": { + "type": "object", + "additionalProperties": false, + "properties": { + "enabled": { + "type": "boolean", + "description": "Whether every number in this project has a daily allowance." + }, + "warmupDays": { + "type": "integer", + "minimum": 1, + "maximum": 90, + "description": "Days the ramp takes to reach the per-number daily cap." + }, + "dailyStart": { + "type": "integer", + "minimum": 1, + "maximum": 2000, + "description": "Messages a number may send on its first day." + } + }, + "required": [ + "enabled", + "warmupDays", + "dailyStart" + ] + }, + "WarmupCurvePoint": { + "type": "object", + "additionalProperties": false, + "properties": { + "day": { + "type": "integer", + "minimum": 0, + "description": "Days since the number's first proven activity." + }, + "allowance": { + "type": "integer", + "minimum": 0, + "description": "Messages allowed on that day." + } + }, + "required": [ + "day", + "allowance" + ] + }, + "ProjectWarmupPlan": { + "type": "object", + "additionalProperties": false, + "properties": { + "projectId": { + "type": "string", + "format": "uuid" + }, + "plan": { + "$ref": "#/components/schemas/WarmupPlanSettings" + }, + "ceiling": { + "type": "integer", + "minimum": 1, + "description": "The per-number daily cap the ramp climbs to." + }, + "curve": { + "type": "array", + "maxItems": 91, + "items": { + "$ref": "#/components/schemas/WarmupCurvePoint" + }, + "description": "The projected allowance day by day for a number whose health is good. A number in a lower health band gets less." + }, + "entitled": { + "type": "boolean", + "description": "Whether this project's plan includes BanSafe Lite, which the warm-up plan is part of. When false, turning the warm-up plan on is refused." + }, + "entitlementReason": { + "type": "string", + "nullable": true, + "description": "Why turning the plan on would be refused. Null when the plan includes BanSafe Lite." + } + }, + "required": [ + "projectId", + "plan", + "ceiling", + "curve", + "entitled", + "entitlementReason" + ] + }, + "UpdateProjectWarmupPlanInput": { + "type": "object", + "additionalProperties": false, + "description": "A partial update: send only the settings you want to change.", + "properties": { + "enabled": { + "type": "boolean" + }, + "warmupDays": { + "type": "integer", + "minimum": 1, + "maximum": 90 + }, + "dailyStart": { + "type": "integer", + "minimum": 1, + "maximum": 2000 + } + } + }, + "ProjectHealthPolicyIntegrations": { + "type": "object", + "additionalProperties": false, + "properties": { + "emailConfigured": { + "type": "boolean", + "description": "Whether notification email delivery is configured." + }, + "webhookConfigured": { + "type": "boolean", + "description": "Whether an enabled webhook exists for this organization or project." + } + }, + "required": [ + "emailConfigured", + "webhookConfigured" + ] + }, + "ProjectHealthPolicy": { + "type": "object", + "additionalProperties": false, + "properties": { + "projectId": { + "type": "string", + "format": "uuid" + }, + "version": { + "type": "integer", + "minimum": 0, + "description": "Revision required by the next update." + }, + "enabled": { + "type": "boolean" + }, + "threshold": { + "type": "integer", + "minimum": 0, + "maximum": 100, + "description": "Actions trigger only when an available health estimate is below this value." + }, + "sessionAction": { + "type": "string", + "enum": [ + "none", + "stop", + "slow_down", + "log_out" + ] + }, + "slowDownMps": { + "type": "number", + "minimum": 0, + "exclusiveMinimum": true, + "nullable": true + }, + "emailNotification": { + "type": "boolean" + }, + "webhookNotification": { + "type": "boolean" + }, + "integrations": { + "$ref": "#/components/schemas/ProjectHealthPolicyIntegrations" + } + }, + "required": [ + "projectId", + "version", + "enabled", + "threshold", + "sessionAction", + "slowDownMps", + "emailNotification", + "webhookNotification", + "integrations" + ] + }, + "UpdateProjectHealthPolicyInput": { + "type": "object", + "additionalProperties": false, + "properties": { + "version": { + "type": "integer", + "minimum": 0 + }, + "enabled": { + "type": "boolean" + }, + "threshold": { + "type": "integer", + "minimum": 0, + "maximum": 100 + }, + "sessionAction": { + "type": "string", + "enum": [ + "none", + "stop", + "slow_down", + "log_out" + ] + }, + "slowDownMps": { + "type": "number", + "minimum": 0, + "exclusiveMinimum": true, + "nullable": true + }, + "emailNotification": { + "type": "boolean" + }, + "webhookNotification": { + "type": "boolean" + } + }, + "required": [ + "version", + "enabled", + "threshold", + "sessionAction", + "slowDownMps", + "emailNotification", + "webhookNotification" + ] + }, + "WebhookRetryPolicyInput": { + "type": "object", + "additionalProperties": false, + "properties": { + "maximumAttempts": { + "type": "integer", + "minimum": 1, + "maximum": 10 + }, + "backoff": { + "type": "string", + "enum": [ + "constant", + "linear", + "exponential" + ] + }, + "initialDelaySeconds": { + "type": "integer", + "minimum": 1, + "maximum": 3600 + } + }, + "required": [ + "maximumAttempts", + "backoff", + "initialDelaySeconds" + ] + }, + "WebhookRetryPolicy": { + "type": "object", + "additionalProperties": false, + "properties": { + "maximumAttempts": { + "type": "integer", + "minimum": 1, + "maximum": 10 + }, + "backoff": { + "type": "string", + "enum": [ + "constant", + "linear", + "exponential" + ] + }, + "initialDelaySeconds": { + "type": "integer", + "minimum": 1, + "maximum": 3600 + } + }, + "required": [ + "maximumAttempts", + "backoff", + "initialDelaySeconds" + ] + }, + "WebhookHeaderInput": { + "type": "object", + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "minLength": 1, + "maxLength": 128, + "pattern": "^[!#$%&'*+\\-.^_`|~0-9A-Za-z]+$" + }, + "value": { + "type": "string", + "maxLength": 4096, + "pattern": "^(?![\\s\\S]*[\\u0000-\\u0008\\u000A-\\u001F\\u007F])[\\s\\S]*$", + "x-polymorfa-max-utf8-bytes": 4096, + "writeOnly": true, + "description": "Encrypted write-only HTTP field value. Limited to 4096 UTF-8 bytes. Line breaks, NUL, and other control characters except horizontal tab are rejected." + } + }, + "required": [ + "name", + "value" + ] + }, + "WebhookHeaderMetadata": { + "type": "object", + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "minLength": 1, + "maxLength": 128 + } + }, + "required": [ + "name" + ] + }, + "WebhookSigningSecretMetadata": { + "type": "object", + "additionalProperties": false, + "properties": { + "version": { + "type": "integer", + "minimum": 1 + }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "previousValidUntil": { + "type": "string", + "format": "date-time", + "nullable": true + } + }, + "required": [ + "version", + "createdAt", + "previousValidUntil" + ] + }, + "CreateOrganizationWebhookInput": { + "type": "object", + "additionalProperties": false, + "properties": { + "url": { + "type": "string", + "format": "uri", + "minLength": 1, + "maxLength": 2048 + }, + "eventTypes": { + "type": "array", + "minItems": 1, + "maxItems": 100, + "uniqueItems": true, + "items": { + "type": "string", + "minLength": 1, + "maxLength": 128 + } + }, + "enabled": { + "type": "boolean", + "default": true + }, + "format": { + "type": "string", + "enum": [ + "native", + "meta" + ], + "default": "native" + }, + "retryPolicy": { + "$ref": "#/components/schemas/WebhookRetryPolicyInput" + }, + "headers": { + "type": "array", + "maxItems": 10, + "items": { + "$ref": "#/components/schemas/WebhookHeaderInput" + } + } + }, + "required": [ + "url", + "eventTypes" + ] + }, + "CreateProjectWebhookInput": { + "type": "object", + "additionalProperties": false, + "properties": { + "url": { + "type": "string", + "format": "uri", + "minLength": 1, + "maxLength": 2048 + }, + "eventTypes": { + "type": "array", + "minItems": 1, + "maxItems": 100, + "uniqueItems": true, + "items": { + "type": "string", + "minLength": 1, + "maxLength": 128 + } + }, + "enabled": { + "type": "boolean", + "default": true + }, + "format": { + "type": "string", + "enum": [ + "native", + "meta" + ], + "default": "native" + }, + "retryPolicy": { + "$ref": "#/components/schemas/WebhookRetryPolicyInput" + }, + "headers": { + "type": "array", + "maxItems": 10, + "items": { + "$ref": "#/components/schemas/WebhookHeaderInput" + } + } + }, + "required": [ + "url", + "eventTypes" + ] + }, + "UpdateOrganizationWebhookInput": { + "type": "object", + "additionalProperties": false, + "properties": { + "url": { + "type": "string", + "format": "uri", + "minLength": 1, + "maxLength": 2048 + }, + "eventTypes": { + "type": "array", + "minItems": 1, + "maxItems": 100, + "uniqueItems": true, + "items": { + "type": "string", + "minLength": 1, + "maxLength": 128 + } + }, + "enabled": { + "type": "boolean" + }, + "format": { + "type": "string", + "enum": [ + "native", + "meta" + ] + }, + "retryPolicy": { + "$ref": "#/components/schemas/WebhookRetryPolicyInput" + }, + "headers": { + "type": "array", + "maxItems": 10, + "items": { + "$ref": "#/components/schemas/WebhookHeaderInput" + } + } + }, + "minProperties": 1 + }, + "UpdateProjectWebhookInput": { + "type": "object", + "additionalProperties": false, + "properties": { + "url": { + "type": "string", + "format": "uri", + "minLength": 1, + "maxLength": 2048 + }, + "eventTypes": { + "type": "array", + "minItems": 1, + "maxItems": 100, + "uniqueItems": true, + "items": { + "type": "string", + "minLength": 1, + "maxLength": 128 + } + }, + "enabled": { + "type": "boolean" + }, + "format": { + "type": "string", + "enum": [ + "native", + "meta" + ] + }, + "retryPolicy": { + "$ref": "#/components/schemas/WebhookRetryPolicyInput" + }, + "headers": { + "type": "array", + "maxItems": 10, + "items": { + "$ref": "#/components/schemas/WebhookHeaderInput" + } + } + }, + "minProperties": 1 + }, + "RotateWebhookSecretInput": { + "type": "object", + "additionalProperties": false, + "properties": { + "overlapSeconds": { + "type": "integer", + "minimum": 0, + "maximum": 86400, + "default": 3600 + } + } + }, + "OrganizationWebhook": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "organizationId": { + "type": "string", + "format": "uuid" + }, + "owner": { + "type": "string", + "enum": [ + "organization" + ] + }, + "projectId": { + "type": "string", + "nullable": true, + "enum": [ + null + ] + }, + "url": { + "type": "string", + "format": "uri", + "maxLength": 2048 + }, + "eventTypes": { + "type": "array", + "minItems": 1, + "maxItems": 100, + "uniqueItems": true, + "items": { + "type": "string", + "minLength": 1, + "maxLength": 128 + } + }, + "enabled": { + "type": "boolean" + }, + "format": { + "type": "string", + "enum": [ + "native", + "meta" + ] + }, + "retryPolicy": { + "$ref": "#/components/schemas/WebhookRetryPolicy" + }, + "headers": { + "type": "array", + "maxItems": 10, + "items": { + "$ref": "#/components/schemas/WebhookHeaderMetadata" + } + }, + "secret": { + "$ref": "#/components/schemas/WebhookSigningSecretMetadata" + }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "updatedAt": { + "type": "string", + "format": "date-time" + } + }, + "required": [ + "id", + "organizationId", + "owner", + "projectId", + "url", + "eventTypes", + "enabled", + "format", + "retryPolicy", + "headers", + "secret", + "createdAt", + "updatedAt" + ] + }, + "ProjectWebhook": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "organizationId": { + "type": "string", + "format": "uuid" + }, + "owner": { + "type": "string", + "enum": [ + "project" + ] + }, + "projectId": { + "type": "string", + "format": "uuid" + }, + "url": { + "type": "string", + "format": "uri", + "maxLength": 2048 + }, + "eventTypes": { + "type": "array", + "minItems": 1, + "maxItems": 100, + "uniqueItems": true, + "items": { + "type": "string", + "minLength": 1, + "maxLength": 128 + } + }, + "enabled": { + "type": "boolean" + }, + "format": { + "type": "string", + "enum": [ + "native", + "meta" + ] + }, + "retryPolicy": { + "$ref": "#/components/schemas/WebhookRetryPolicy" + }, + "headers": { + "type": "array", + "maxItems": 10, + "items": { + "$ref": "#/components/schemas/WebhookHeaderMetadata" + } + }, + "secret": { + "$ref": "#/components/schemas/WebhookSigningSecretMetadata" + }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "updatedAt": { + "type": "string", + "format": "date-time" + } + }, + "required": [ + "id", + "organizationId", + "owner", + "projectId", + "url", + "eventTypes", + "enabled", + "format", + "retryPolicy", + "headers", + "secret", + "createdAt", + "updatedAt" + ] + }, + "OrganizationWebhookCreationReceipt": { + "type": "object", + "additionalProperties": false, + "properties": { + "webhook": { + "$ref": "#/components/schemas/OrganizationWebhook" + }, + "operationId": { + "type": "string", + "nullable": true, + "enum": [ + null + ] + }, + "idempotency": { + "$ref": "#/components/schemas/IdempotencyReceipt" + }, + "secret": { + "type": "string", + "nullable": true, + "writeOnly": true + }, + "secretAvailable": { + "type": "boolean" + } + }, + "required": [ + "webhook", + "operationId", + "idempotency", + "secret", + "secretAvailable" + ] + }, + "ProjectWebhookCreationReceipt": { + "type": "object", + "additionalProperties": false, + "properties": { + "webhook": { + "$ref": "#/components/schemas/ProjectWebhook" + }, + "operationId": { + "type": "string", + "nullable": true, + "enum": [ + null + ] + }, + "idempotency": { + "$ref": "#/components/schemas/IdempotencyReceipt" + }, + "secret": { + "type": "string", + "nullable": true, + "writeOnly": true + }, + "secretAvailable": { + "type": "boolean" + } + }, + "required": [ + "webhook", + "operationId", + "idempotency", + "secret", + "secretAvailable" + ] + }, + "OrganizationWebhookMutationReceipt": { + "type": "object", + "additionalProperties": false, + "properties": { + "webhook": { + "$ref": "#/components/schemas/OrganizationWebhook" + }, + "operationId": { + "type": "string", + "nullable": true, + "enum": [ + null + ] + }, + "idempotency": { + "$ref": "#/components/schemas/IdempotencyReceipt" + } + }, + "required": [ + "webhook", + "operationId", + "idempotency" + ] + }, + "ProjectWebhookMutationReceipt": { + "type": "object", + "additionalProperties": false, + "properties": { + "webhook": { + "$ref": "#/components/schemas/ProjectWebhook" + }, + "operationId": { + "type": "string", + "nullable": true, + "enum": [ + null + ] + }, + "idempotency": { + "$ref": "#/components/schemas/IdempotencyReceipt" + } + }, + "required": [ + "webhook", + "operationId", + "idempotency" + ] + }, + "OrganizationWebhookDeletionReceipt": { + "type": "object", + "additionalProperties": false, + "properties": { + "webhookId": { + "type": "string", + "format": "uuid" + }, + "deleted": { + "type": "boolean", + "enum": [ + true + ] + }, + "operationId": { + "type": "string", + "nullable": true, + "enum": [ + null + ] + }, + "idempotency": { + "$ref": "#/components/schemas/IdempotencyReceipt" + } + }, + "required": [ + "webhookId", + "deleted", + "operationId", + "idempotency" + ] + }, + "ProjectWebhookDeletionReceipt": { + "type": "object", + "additionalProperties": false, + "properties": { + "webhookId": { + "type": "string", + "format": "uuid" + }, + "deleted": { + "type": "boolean", + "enum": [ + true + ] + }, + "operationId": { + "type": "string", + "nullable": true, + "enum": [ + null + ] + }, + "idempotency": { + "$ref": "#/components/schemas/IdempotencyReceipt" + } + }, + "required": [ + "webhookId", + "deleted", + "operationId", + "idempotency" + ] + }, + "OrganizationWebhookSecretRotationReceipt": { + "type": "object", + "additionalProperties": false, + "properties": { + "webhookId": { + "type": "string", + "format": "uuid" + }, + "operationId": { + "type": "string", + "nullable": true, + "enum": [ + null + ] + }, + "secret": { + "type": "string", + "nullable": true, + "writeOnly": true + }, + "secretAvailable": { + "type": "boolean" + }, + "secretMetadata": { + "$ref": "#/components/schemas/WebhookSigningSecretMetadata" + }, + "idempotency": { + "$ref": "#/components/schemas/IdempotencyReceipt" + } + }, + "required": [ + "webhookId", + "operationId", + "secret", + "secretAvailable", + "secretMetadata", + "idempotency" + ] + }, + "ProjectWebhookSecretRotationReceipt": { + "type": "object", + "additionalProperties": false, + "properties": { + "webhookId": { + "type": "string", + "format": "uuid" + }, + "operationId": { + "type": "string", + "nullable": true, + "enum": [ + null + ] + }, + "secret": { + "type": "string", + "nullable": true, + "writeOnly": true + }, + "secretAvailable": { + "type": "boolean" + }, + "secretMetadata": { + "$ref": "#/components/schemas/WebhookSigningSecretMetadata" + }, + "idempotency": { + "$ref": "#/components/schemas/IdempotencyReceipt" + } + }, + "required": [ + "webhookId", + "operationId", + "secret", + "secretAvailable", + "secretMetadata", + "idempotency" + ] + }, + "EncodedEventPayload": { + "type": "object", + "additionalProperties": false, + "properties": { + "encoding": { + "type": "string", + "enum": [ + "base64" + ] + }, + "contentType": { + "type": "string", + "enum": [ + "application/json" + ] + }, + "data": { + "type": "string", + "format": "byte", + "maxLength": 87384, + "description": "Canonical base64 for the complete native webhook body; decoded bytes are limited to 65,536 bytes." + } + }, + "required": [ + "encoding", + "contentType", + "data" + ] + }, + "PayloadAvailability": { + "type": "string", + "enum": [ + "available", + "not_retained", + "expired", + "redacted", + "unavailable" + ] + }, + "OrganizationEvent": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "organizationId": { + "type": "string", + "format": "uuid" + }, + "projectId": { + "type": "string", + "nullable": true, + "enum": [ + null + ] + }, + "type": { + "type": "string", + "minLength": 1, + "maxLength": 128 + }, + "source": { + "type": "string", + "enum": [ + "runtime", + "platform", + "test" + ] + }, + "environment": { + "type": "string", + "enum": [ + "development", + "production" + ] + }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "payloadAvailability": { + "type": "string", + "enum": [ + "available", + "not_retained", + "expired", + "redacted", + "unavailable" + ] + }, + "payload": { + "nullable": true, + "allOf": [ + { + "$ref": "#/components/schemas/EncodedEventPayload" + } + ] + }, + "replayableUntil": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "metadataExpiresAt": { + "type": "string", + "format": "date-time" + } + }, + "required": [ + "id", + "organizationId", + "projectId", + "type", + "source", + "environment", + "createdAt", + "payloadAvailability", + "payload", + "replayableUntil", + "metadataExpiresAt" + ] + }, + "ProjectEvent": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "organizationId": { + "type": "string", + "format": "uuid" + }, + "projectId": { + "type": "string", + "format": "uuid" + }, + "type": { + "type": "string", + "minLength": 1, + "maxLength": 128 + }, + "source": { + "type": "string", + "enum": [ + "runtime", + "platform", + "test" + ] + }, + "environment": { + "type": "string", + "enum": [ + "development", + "production" + ] + }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "payloadAvailability": { + "type": "string", + "enum": [ + "available", + "not_retained", + "expired", + "redacted", + "unavailable" + ] + }, + "payload": { + "nullable": true, + "allOf": [ + { + "$ref": "#/components/schemas/EncodedEventPayload" + } + ] + }, + "replayableUntil": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "metadataExpiresAt": { + "type": "string", + "format": "date-time" + } + }, + "required": [ + "id", + "organizationId", + "projectId", + "type", + "source", + "environment", + "createdAt", + "payloadAvailability", + "payload", + "replayableUntil", + "metadataExpiresAt" + ] + }, + "OrganizationWebhookDelivery": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "organizationId": { + "type": "string", + "format": "uuid" + }, + "projectId": { + "type": "string", + "nullable": true, + "enum": [ + null + ] + }, + "eventId": { + "type": "string", + "format": "uuid" + }, + "webhookId": { + "type": "string", + "format": "uuid" + }, + "status": { + "type": "string", + "enum": [ + "pending", + "delivering", + "retrying", + "succeeded", + "failed" + ] + }, + "attemptCount": { + "type": "integer", + "minimum": 0 + }, + "capabilities": { + "type": "object", + "additionalProperties": false, + "properties": { + "retryable": { + "type": "boolean" + } + }, + "required": [ + "retryable" + ] + }, + "payloadAvailability": { + "type": "string", + "enum": [ + "available", + "not_retained", + "expired", + "redacted", + "unavailable" + ] + }, + "replayableUntil": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "metadataExpiresAt": { + "type": "string", + "format": "date-time" + }, + "nextAttemptAt": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "lastAttemptAt": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "completedAt": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "updatedAt": { + "type": "string", + "format": "date-time" + }, + "lastOutcome": { + "type": "object", + "nullable": true, + "additionalProperties": false, + "properties": { + "statusCode": { + "type": "integer", + "minimum": 100, + "maximum": 599, + "nullable": true + }, + "errorCode": { + "type": "string", + "nullable": true + } + }, + "required": [ + "statusCode", + "errorCode" + ] + } + }, + "required": [ + "id", + "organizationId", + "projectId", + "eventId", + "webhookId", + "status", + "attemptCount", + "capabilities", + "payloadAvailability", + "replayableUntil", + "metadataExpiresAt", + "nextAttemptAt", + "lastAttemptAt", + "completedAt", + "createdAt", + "updatedAt", + "lastOutcome" + ] + }, + "ProjectWebhookDelivery": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "organizationId": { + "type": "string", + "format": "uuid" + }, + "projectId": { + "type": "string", + "format": "uuid" + }, + "eventId": { + "type": "string", + "format": "uuid" + }, + "webhookId": { + "type": "string", + "format": "uuid" + }, + "status": { + "type": "string", + "enum": [ + "pending", + "delivering", + "retrying", + "succeeded", + "failed" + ] + }, + "attemptCount": { + "type": "integer", + "minimum": 0 + }, + "capabilities": { + "type": "object", + "additionalProperties": false, + "properties": { + "retryable": { + "type": "boolean" + } + }, + "required": [ + "retryable" + ] + }, + "payloadAvailability": { + "type": "string", + "enum": [ + "available", + "not_retained", + "expired", + "redacted", + "unavailable" + ] + }, + "replayableUntil": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "metadataExpiresAt": { + "type": "string", + "format": "date-time" + }, + "nextAttemptAt": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "lastAttemptAt": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "completedAt": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "updatedAt": { + "type": "string", + "format": "date-time" + }, + "lastOutcome": { + "type": "object", + "nullable": true, + "additionalProperties": false, + "properties": { + "statusCode": { + "type": "integer", + "minimum": 100, + "maximum": 599, + "nullable": true + }, + "errorCode": { + "type": "string", + "nullable": true + } + }, + "required": [ + "statusCode", + "errorCode" + ] + } + }, + "required": [ + "id", + "organizationId", + "projectId", + "eventId", + "webhookId", + "status", + "attemptCount", + "capabilities", + "payloadAvailability", + "replayableUntil", + "metadataExpiresAt", + "nextAttemptAt", + "lastAttemptAt", + "completedAt", + "createdAt", + "updatedAt", + "lastOutcome" + ] + }, + "OrganizationWebhookDeliveryAttempt": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "organizationId": { + "type": "string", + "format": "uuid" + }, + "projectId": { + "type": "string", + "nullable": true, + "enum": [ + null + ] + }, + "deliveryId": { + "type": "string", + "format": "uuid" + }, + "number": { + "type": "integer", + "minimum": 1 + }, + "status": { + "type": "string", + "enum": [ + "pending", + "delivering", + "succeeded", + "failed" + ] + }, + "startedAt": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "completedAt": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "nextRetryAt": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "durationMs": { + "type": "integer", + "minimum": 0, + "nullable": true + }, + "statusCode": { + "type": "integer", + "minimum": 100, + "maximum": 599, + "nullable": true + }, + "errorCode": { + "type": "string", + "nullable": true + }, + "metadataExpiresAt": { + "type": "string", + "format": "date-time" + } + }, + "required": [ + "id", + "organizationId", + "projectId", + "deliveryId", + "number", + "status", + "startedAt", + "completedAt", + "nextRetryAt", + "durationMs", + "statusCode", + "errorCode", + "metadataExpiresAt" + ] + }, + "ProjectWebhookDeliveryAttempt": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "organizationId": { + "type": "string", + "format": "uuid" + }, + "projectId": { + "type": "string", + "format": "uuid" + }, + "deliveryId": { + "type": "string", + "format": "uuid" + }, + "number": { + "type": "integer", + "minimum": 1 + }, + "status": { + "type": "string", + "enum": [ + "pending", + "delivering", + "succeeded", + "failed" + ] + }, + "startedAt": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "completedAt": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "nextRetryAt": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "durationMs": { + "type": "integer", + "minimum": 0, + "nullable": true + }, + "statusCode": { + "type": "integer", + "minimum": 100, + "maximum": 599, + "nullable": true + }, + "errorCode": { + "type": "string", + "nullable": true + }, + "metadataExpiresAt": { + "type": "string", + "format": "date-time" + } + }, + "required": [ + "id", + "organizationId", + "projectId", + "deliveryId", + "number", + "status", + "startedAt", + "completedAt", + "nextRetryAt", + "durationMs", + "statusCode", + "errorCode", + "metadataExpiresAt" + ] + }, + "JsonValue": { + "nullable": true, + "oneOf": [ + { + "type": "string", + "nullable": true, + "enum": [ + null + ] + }, + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + }, + { + "type": "array", + "items": { + "$ref": "#/components/schemas/JsonValue" + } + }, + { + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/JsonValue" + } + } + ] + }, + "OperationCapabilities": { + "type": "object", + "additionalProperties": false, + "properties": { + "cancellable": { + "type": "boolean" + }, + "watchable": { + "type": "boolean" + } + }, + "required": [ + "cancellable", + "watchable" + ] + }, + "OperationProgress": { + "type": "object", + "additionalProperties": false, + "properties": { + "code": { + "type": "string" + }, + "current": { + "type": "integer", + "nullable": true + }, + "total": { + "type": "integer", + "nullable": true + } + }, + "required": [ + "code", + "current", + "total" + ] + }, + "OperationError": { + "type": "object", + "additionalProperties": false, + "properties": { + "code": { + "type": "string" + }, + "retryable": { + "type": "boolean" + }, + "details": { + "type": "object", + "nullable": true, + "additionalProperties": { + "$ref": "#/components/schemas/JsonValue" + } + } + }, + "required": [ + "code", + "retryable", + "details" + ] + }, + "OperationActionRequired": { + "type": "object", + "additionalProperties": false, + "properties": { + "code": { + "type": "string" + }, + "details": { + "type": "object", + "nullable": true, + "additionalProperties": { + "$ref": "#/components/schemas/JsonValue" + } + } + }, + "required": [ + "code", + "details" + ] + }, + "OrganizationOperation": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "organizationId": { + "type": "string", + "format": "uuid" + }, + "projectId": { + "type": "string", + "nullable": true, + "enum": [ + null + ] + }, + "kind": { + "type": "string", + "enum": [ + "auth_projection_repair", + "session_lifecycle", + "auth_session_purge", + "label_projection_purge", + "billing_reconciliation", + "auto_top_up", + "campaign", + "production_enrollment", + "retention_sweep", + "webhook_redrive" + ] + }, + "resource": { + "type": "object", + "additionalProperties": false, + "properties": { + "type": { + "type": "string" + }, + "id": { + "type": "string" + } + }, + "required": [ + "type", + "id" + ] + }, + "status": { + "type": "string", + "enum": [ + "pending", + "running", + "action_required", + "cancelling", + "succeeded", + "failed", + "cancelled" + ] + }, + "sequence": { + "type": "integer", + "format": "int64", + "minimum": 1 + }, + "capabilities": { + "$ref": "#/components/schemas/OperationCapabilities" + }, + "progress": { + "nullable": true, + "allOf": [ + { + "$ref": "#/components/schemas/OperationProgress" + } + ] + }, + "result": { + "nullable": true, + "allOf": [ + { + "$ref": "#/components/schemas/JsonValue" + } + ] + }, + "error": { + "nullable": true, + "allOf": [ + { + "$ref": "#/components/schemas/OperationError" + } + ] + }, + "actionRequired": { + "nullable": true, + "allOf": [ + { + "$ref": "#/components/schemas/OperationActionRequired" + } + ] + }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "updatedAt": { + "type": "string", + "format": "date-time" + }, + "completedAt": { + "type": "string", + "format": "date-time", + "nullable": true + } + }, + "required": [ + "id", + "organizationId", + "projectId", + "kind", + "resource", + "status", + "sequence", + "capabilities", + "progress", + "result", + "error", + "actionRequired", + "createdAt", + "updatedAt", + "completedAt" + ] + }, + "ProjectOperation": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "organizationId": { + "type": "string", + "format": "uuid" + }, + "projectId": { + "type": "string", + "format": "uuid" + }, + "kind": { + "type": "string", + "enum": [ + "auth_projection_repair", + "session_lifecycle", + "auth_session_purge", + "label_projection_purge", + "billing_reconciliation", + "auto_top_up", + "campaign", + "production_enrollment", + "retention_sweep", + "webhook_redrive" + ] + }, + "resource": { + "type": "object", + "additionalProperties": false, + "properties": { + "type": { + "type": "string" + }, + "id": { + "type": "string" + } + }, + "required": [ + "type", + "id" + ] + }, + "status": { + "type": "string", + "enum": [ + "pending", + "running", + "action_required", + "cancelling", + "succeeded", + "failed", + "cancelled" + ] + }, + "sequence": { + "type": "integer", + "format": "int64", + "minimum": 1 + }, + "capabilities": { + "$ref": "#/components/schemas/OperationCapabilities" + }, + "progress": { + "nullable": true, + "allOf": [ + { + "$ref": "#/components/schemas/OperationProgress" + } + ] + }, + "result": { + "nullable": true, + "allOf": [ + { + "$ref": "#/components/schemas/JsonValue" + } + ] + }, + "error": { + "nullable": true, + "allOf": [ + { + "$ref": "#/components/schemas/OperationError" + } + ] + }, + "actionRequired": { + "nullable": true, + "allOf": [ + { + "$ref": "#/components/schemas/OperationActionRequired" + } + ] + }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "updatedAt": { + "type": "string", + "format": "date-time" + }, + "completedAt": { + "type": "string", + "format": "date-time", + "nullable": true + } + }, + "required": [ + "id", + "organizationId", + "projectId", + "kind", + "resource", + "status", + "sequence", + "capabilities", + "progress", + "result", + "error", + "actionRequired", + "createdAt", + "updatedAt", + "completedAt" + ] + }, + "OperationTransition": { + "type": "object", + "additionalProperties": false, + "properties": { + "operationId": { + "type": "string", + "format": "uuid" + }, + "sequence": { + "type": "integer", + "format": "int64", + "minimum": 1 + }, + "fromStatus": { + "type": "string", + "enum": [ + "pending", + "running", + "action_required", + "cancelling", + "succeeded", + "failed", + "cancelled" + ], + "nullable": true + }, + "toStatus": { + "type": "string", + "enum": [ + "pending", + "running", + "action_required", + "cancelling", + "succeeded", + "failed", + "cancelled" + ] + }, + "reasonCode": { + "type": "string", + "nullable": true + }, + "occurredAt": { + "type": "string", + "format": "date-time" + }, + "snapshot": { + "type": "object", + "additionalProperties": false, + "properties": { + "progress": { + "nullable": true, + "allOf": [ + { + "$ref": "#/components/schemas/OperationProgress" + } + ] + }, + "error": { + "nullable": true, + "allOf": [ + { + "$ref": "#/components/schemas/OperationError" + } + ] + }, + "actionRequired": { + "nullable": true, + "allOf": [ + { + "$ref": "#/components/schemas/OperationActionRequired" + } + ] + } + }, + "required": [ + "progress", + "error", + "actionRequired" + ] + } + }, + "required": [ + "operationId", + "sequence", + "fromStatus", + "toStatus", + "reasonCode", + "occurredAt", + "snapshot" + ] + }, + "IdempotencyReceipt": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "key": { + "type": "string", + "minLength": 1, + "maxLength": 255 + }, + "replayed": { + "type": "boolean" + }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "expiresAt": { + "type": "string", + "format": "date-time" + } + }, + "required": [ + "id", + "key", + "replayed", + "createdAt", + "expiresAt" + ] + }, + "ReplayEventInput": { + "type": "object", + "additionalProperties": false, + "properties": { + "webhookId": { + "type": "string", + "format": "uuid" + } + }, + "required": [ + "webhookId" + ] + }, + "RetryWebhookDeliveryInput": { + "type": "object", + "additionalProperties": false, + "maxProperties": 0 + }, + "TestWebhookInput": { + "oneOf": [ + { + "type": "object", + "additionalProperties": false, + "properties": { + "eventType": { + "type": "string", + "default": "polymorfa.test", + "pattern": "^[a-z0-9][a-z0-9_.-]{0,127}$" + } + } + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "eventType": { + "type": "string", + "pattern": "^[a-z0-9][a-z0-9_.-]{0,127}$" + }, + "body": { + "$ref": "#/components/schemas/EncodedEventPayload" + }, + "sessionId": { + "type": "string", + "format": "uuid" + } + }, + "required": [ + "body", + "sessionId" + ] + } + ] + }, + "OrganizationEventReplayReceipt": { + "type": "object", + "additionalProperties": false, + "properties": { + "operationId": { + "type": "string", + "format": "uuid" + }, + "idempotency": { + "$ref": "#/components/schemas/IdempotencyReceipt" + }, + "eventId": { + "type": "string", + "format": "uuid" + }, + "deliveryId": { + "type": "string", + "format": "uuid" + } + }, + "required": [ + "eventId", + "deliveryId", + "operationId", + "idempotency" + ] + }, + "ProjectEventReplayReceipt": { + "type": "object", + "additionalProperties": false, + "properties": { + "operationId": { + "type": "string", + "format": "uuid" + }, + "idempotency": { + "$ref": "#/components/schemas/IdempotencyReceipt" + }, + "eventId": { + "type": "string", + "format": "uuid" + }, + "deliveryId": { + "type": "string", + "format": "uuid" + } + }, + "required": [ + "eventId", + "deliveryId", + "operationId", + "idempotency" + ] + }, + "OrganizationWebhookDeliveryRetryReceipt": { + "type": "object", + "additionalProperties": false, + "properties": { + "operationId": { + "type": "string", + "format": "uuid" + }, + "idempotency": { + "$ref": "#/components/schemas/IdempotencyReceipt" + }, + "deliveryId": { + "type": "string", + "format": "uuid" + }, + "attemptId": { + "type": "string", + "format": "uuid" + } + }, + "required": [ + "deliveryId", + "attemptId", + "operationId", + "idempotency" + ] + }, + "ProjectWebhookDeliveryRetryReceipt": { + "type": "object", + "additionalProperties": false, + "properties": { + "operationId": { + "type": "string", + "format": "uuid" + }, + "idempotency": { + "$ref": "#/components/schemas/IdempotencyReceipt" + }, + "deliveryId": { + "type": "string", + "format": "uuid" + }, + "attemptId": { + "type": "string", + "format": "uuid" + } + }, + "required": [ + "deliveryId", + "attemptId", + "operationId", + "idempotency" + ] + }, + "OrganizationWebhookTestReceipt": { + "type": "object", + "additionalProperties": false, + "properties": { + "operationId": { + "type": "string", + "format": "uuid" + }, + "idempotency": { + "$ref": "#/components/schemas/IdempotencyReceipt" + }, + "eventId": { + "type": "string", + "format": "uuid" + }, + "deliveryId": { + "type": "string", + "format": "uuid" + } + }, + "required": [ + "eventId", + "deliveryId", + "operationId", + "idempotency" + ] + }, + "ProjectWebhookTestReceipt": { + "type": "object", + "additionalProperties": false, + "properties": { + "operationId": { + "type": "string", + "format": "uuid" + }, + "idempotency": { + "$ref": "#/components/schemas/IdempotencyReceipt" + }, + "eventId": { + "type": "string", + "format": "uuid" + }, + "deliveryId": { + "type": "string", + "format": "uuid" + } + }, + "required": [ + "eventId", + "deliveryId", + "operationId", + "idempotency" + ] + }, + "OrganizationOperationCancellationReceipt": { + "type": "object", + "additionalProperties": false, + "properties": { + "operation": { + "$ref": "#/components/schemas/OrganizationOperation" + }, + "operationId": { + "type": "string", + "format": "uuid" + }, + "idempotency": { + "$ref": "#/components/schemas/IdempotencyReceipt" + } + }, + "required": [ + "operation", + "operationId", + "idempotency" + ] + }, + "ProjectOperationCancellationReceipt": { + "type": "object", + "additionalProperties": false, + "properties": { + "operation": { + "$ref": "#/components/schemas/ProjectOperation" + }, + "operationId": { + "type": "string", + "format": "uuid" + }, + "idempotency": { + "$ref": "#/components/schemas/IdempotencyReceipt" + } + }, + "required": [ + "operation", + "operationId", + "idempotency" + ] + }, + "OperationConflictEnvelope": { + "type": "object", + "additionalProperties": false, + "properties": { + "error": { + "type": "string", + "enum": [ + "operation_conflict" + ] + }, + "code": { + "type": "string", + "enum": [ + "operation_conflict" + ] + }, + "operation": { + "oneOf": [ + { + "$ref": "#/components/schemas/OrganizationOperation" + }, + { + "$ref": "#/components/schemas/ProjectOperation" + } + ] + } + }, + "required": [ + "error", + "code", + "operation" + ] + }, + "IdempotencyConflictEnvelope": { + "type": "object", + "additionalProperties": false, + "properties": { + "error": { + "type": "string", + "enum": [ + "idempotency_conflict" + ] + }, + "code": { + "type": "string", + "enum": [ + "idempotency_conflict" + ] + } + }, + "required": [ + "error", + "code" + ] + }, + "OperationCancellationConflictEnvelope": { + "oneOf": [ + { + "$ref": "#/components/schemas/OperationConflictEnvelope" + }, + { + "$ref": "#/components/schemas/IdempotencyConflictEnvelope" + } + ] + } + }, + "responses": { + "Unauthorized": { + "description": "Missing/invalid credential for this audience.", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorEnvelope" + } + } + } + }, + "Forbidden": { + "description": "Authenticated but lacks the required scope/role/audience.", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorEnvelope" + } + } + } + }, + "Gone": { + "description": "The requested retained payload is no longer available.", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorEnvelope" + } + } + } + }, + "BadRequest": { + "description": "A path, query, or request-body value did not pass validation.", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorEnvelope" + } + } + } + }, + "PaymentRequired": { + "description": "The number's plan does not include this capability.", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorEnvelope" + } + } + } + }, + "PropagationPending": { + "description": "The change was stored, but a connected number has not confirmed it. Retry the request; the stored setting is already correct and is retried automatically.", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorEnvelope" + } + } + } + }, + "NotFound": { + "description": "The requested resource was not found inside the authenticated organization or project scope.", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorEnvelope" + } + } + } + }, + "Conflict": { + "description": "The request conflicts with the resource's current state.", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorEnvelope" + } + } + } + }, + "Unprocessable": { + "description": "The retained payload is unavailable or no longer replayable.", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorEnvelope" + } + } + } + }, + "OperationCancellationConflict": { + "description": "The operation cannot accept cancellation, or the idempotency key was reused for a different request.", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OperationCancellationConflictEnvelope" + } + } + } + }, + "InternalError": { + "description": "The session-control publisher or testing-number persistence path is temporarily unavailable.", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorEnvelope" + } + } + } + }, + "NotImplemented": { + "description": "Endpoint registered; handler not yet wired to a repository.", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorEnvelope" + } + } + } + } + } + } +} diff --git a/contracts/drafts/bansafe/source.json b/contracts/drafts/bansafe/source.json new file mode 100644 index 0000000..2a86a3a --- /dev/null +++ b/contracts/drafts/bansafe/source.json @@ -0,0 +1,17 @@ +{ + "repository": "polymorfa/polymorfa", + "sourceBaseCommit": "9dded587b159a97038b1e4536e3b6d26d002f434", + "sourceState": "uncommitted-bansafe-draft", + "contracts": { + "messaging": { + "sourcePath": "apps/api/docs/openapi.json", + "snapshotPath": "contracts/drafts/bansafe/openapi.messaging.json", + "sha256": "b412ca4506e5920c5b6b61548dfb19c42b9168d5b067558bb55ac1cca64905d5" + }, + "platform": { + "sourcePath": "apps/api/docs/openapi.management.json", + "snapshotPath": "contracts/drafts/bansafe/openapi.platform.json", + "sha256": "9b37273ee85a1ce07d456060d46ce18a70832895f03e20ad83319d053232e0c5" + } + } +} diff --git a/packages/typescript/README.md b/packages/typescript/README.md index 649e7e8..b913a9f 100644 --- a/packages/typescript/README.md +++ b/packages/typescript/README.md @@ -60,6 +60,48 @@ The pairing URL is returned once. An idempotent replay returns the same link record with `url: null`. `customers.list()` preserves both the Customer array and the cursor metadata from the API response. +## BanSafe Health and telemetry + +`PlatformClient.banSafe` reads Health, telemetry collection status, the fixed +signal catalogue, findings, restrictions, incidents, claims, and Health action +history. Paged methods preserve the API's `data` array and `page` metadata. + +```ts +const health = await platform.banSafe.getHealth("support"); +const telemetry = await platform.banSafe.getTelemetry("support"); +const actions = await platform.banSafe.listHealthActions({ + projectId: "project_123", + session: "support", + status: "succeeded", +}); + +console.log( + health.data.data.health, + telemetry.data.data.collection.state, + actions.data.page.hasMore, +); +``` + +Use `platform.projects` for project Safe Mode, warm-up, Ban Insurance evidence, +and Health policy settings. Use `platform.sessions` for one number's Safe Mode +override. + +```ts +const policy = await platform.projects.getHealthPolicy("project_123"); +await platform.projects.updateHealthPolicy("project_123", { + version: policy.data.data.version, + enabled: true, + threshold: 50, + sessionAction: "slow_down", + slowDownMps: 0.5, + emailNotification: true, + webhookNotification: true, +}); +``` + +Finding acknowledgement and restriction appeals require a signed-in dashboard +user. The organization-key SDK does not expose those two mutations. + ## Browser client tokens `MessagingClient.clientTokens` mints short-lived tokens and manages the live diff --git a/packages/typescript/src/index.ts b/packages/typescript/src/index.ts index 6fd2d7e..d92290b 100644 --- a/packages/typescript/src/index.ts +++ b/packages/typescript/src/index.ts @@ -419,6 +419,7 @@ export { AudiencesResource } from "./platform/audiences.js"; export { ApiKeysResource } from "./platform/api-keys.js"; export { AuditLogsResource } from "./platform/audit-logs.js"; export { BillingResource } from "./platform/billing.js"; +export { BanSafeResource } from "./platform/bansafe.js"; export { CampaignsResource } from "./platform/campaigns.js"; export { CustomersResource } from "./platform/customers.js"; export { PlatformClient } from "./platform/client.js"; @@ -514,6 +515,93 @@ export type { WidgetShape, WidgetTheme, } from "./platform/types.js"; +export type { + BanSafeAppealState, + BanSafeClaim, + BanSafeClaimEvidence, + BanSafeClaimsEnvelope, + BanSafeClaimStatus, + BanSafeClaimVerdict, + BanSafeCollectionEnvelope, + BanSafeCollectionSession, + BanSafeCollectionState, + BanSafeCollectionStatus, + BanSafeEnforcementEnvelope, + BanSafeEnforcementRung, + BanSafeEnforcementSummary, + BanSafeFinding, + BanSafeFindingsEnvelope, + BanSafeFindingSeverity, + BanSafeFindingStatus, + BanSafeHealthAction, + BanSafeHealthActionKind, + BanSafeHealthActionMode, + BanSafeHealthActionOutcome, + BanSafeHealthActionsEnvelope, + BanSafeHealthActionStatus, + BanSafeHealthBand, + BanSafeHealthEnvelope, + BanSafeHealthExplanation, + BanSafeHealthExplanationFactor, + BanSafeHealthExplanationGroup, + BanSafeHealthHistory, + BanSafeHealthPoint, + BanSafeHealthProbabilities, + BanSafeHealthProjection, + BanSafeHealthReliability, + BanSafeHealthSource, + BanSafeHealthState, + BanSafeHealthUnavailableReason, + BanSafeIncident, + BanSafeIncidentKind, + BanSafeIncidentReceipt, + BanSafeIncidentsEnvelope, + BanSafeNumber, + BanSafeNumberDetail, + BanSafeNumberEnforcement, + BanSafeNumberWarmup, + BanSafeObservedAccountState, + BanSafeSignal, + BanSafeSignalDefinition, + BanSafeSignalKind, + BanSafeSignalUnit, + BanSafeTelemetryDetail, + BanSafeTelemetryHistoryEnvelope, + BanSafeTelemetrySnapshot, + CursorEnvelope, + CursorPageMetadata, + ListBanSafeClaimsParams, + ListBanSafeCollectionParams, + ListBanSafeEnforcementParams, + ListBanSafeFindingsParams, + ListBanSafeHealthActionsParams, + ListBanSafeHealthHistoryParams, + ListBanSafeHealthParams, + ListBanSafeIncidentsParams, + ListBanSafeTelemetryHistoryParams, + ProjectHealthPolicy, + ProjectHealthPolicyIntegrations, + ProjectHealthSessionAction, + ProjectInsuranceEvidence, + ProjectSafeMode, + ProjectWarmupPlan, + ReportBanSafeIncidentRequest, + SafeModeApplied, + SafeModeOverride, + SafeModePacing, + SafeModePresence, + SafeModeReads, + SafeModeSettings, + SafeModeTyping, + SessionSafeMode, + UpdateProjectHealthPolicyRequest, + UpdateProjectInsuranceEvidenceRequest, + UpdateProjectSafeModeRequest, + UpdateProjectWarmupPlanRequest, + UpdateSessionSafeModeRequest, + WarmupCurvePoint, + WarmupPlanSettings, +} from "./platform/types.js"; export { RawClient } from "./raw.js"; export type { ApiResponse, diff --git a/packages/typescript/src/platform/bansafe.ts b/packages/typescript/src/platform/bansafe.ts new file mode 100644 index 0000000..951a3fe --- /dev/null +++ b/packages/typescript/src/platform/bansafe.ts @@ -0,0 +1,186 @@ +import { HttpTransport } from "../transport/http.js"; +import type { + ApiResponse, + QueryValue, + RequestOptions, +} from "../transport/types.js"; +import type { + BanSafeClaim, + BanSafeClaimsEnvelope, + BanSafeCollectionEnvelope, + BanSafeEnforcementEnvelope, + BanSafeFindingsEnvelope, + BanSafeHealthActionsEnvelope, + BanSafeHealthEnvelope, + BanSafeHealthHistory, + BanSafeIncident, + BanSafeIncidentReceipt, + BanSafeIncidentsEnvelope, + BanSafeSignalDefinition, + BanSafeNumberDetail, + BanSafeTelemetryDetail, + BanSafeTelemetryHistoryEnvelope, + DataEnvelope, + ListBanSafeClaimsParams, + ListBanSafeCollectionParams, + ListBanSafeEnforcementParams, + ListBanSafeFindingsParams, + ListBanSafeHealthActionsParams, + ListBanSafeHealthHistoryParams, + ListBanSafeHealthParams, + ListBanSafeIncidentsParams, + ListBanSafeTelemetryHistoryParams, + ReportBanSafeIncidentRequest, +} from "./types.js"; + +export class BanSafeResource { + constructor(private readonly transport: HttpTransport) {} + + listHealth( + params: ListBanSafeHealthParams = {}, + options: RequestOptions = {}, + ): Promise> { + return this.get("/v1/bansafe/health", params, options); + } + + getHealth( + session: string, + options: RequestOptions = {}, + ): Promise>> { + return this.get( + `/v1/bansafe/health/${encodeURIComponent(session)}`, + {}, + options, + ); + } + + listHealthHistory( + session: string, + params: ListBanSafeHealthHistoryParams = {}, + options: RequestOptions = {}, + ): Promise>> { + return this.get( + `/v1/bansafe/health/${encodeURIComponent(session)}/history`, + params, + options, + ); + } + + listSignals( + options: RequestOptions = {}, + ): Promise>> { + return this.get("/v1/bansafe/signals", {}, options); + } + + getTelemetry( + session: string, + options: RequestOptions = {}, + ): Promise>> { + return this.get( + `/v1/bansafe/telemetry/${encodeURIComponent(session)}`, + {}, + options, + ); + } + + listTelemetryHistory( + session: string, + params: ListBanSafeTelemetryHistoryParams = {}, + options: RequestOptions = {}, + ): Promise> { + return this.get( + `/v1/bansafe/telemetry/${encodeURIComponent(session)}/history`, + params, + options, + ); + } + + listCollection( + params: ListBanSafeCollectionParams = {}, + options: RequestOptions = {}, + ): Promise> { + return this.get("/v1/bansafe/collection", params, options); + } + + listHealthActions( + params: ListBanSafeHealthActionsParams = {}, + options: RequestOptions = {}, + ): Promise> { + return this.get("/v1/bansafe/health-actions", params, options); + } + + listFindings( + params: ListBanSafeFindingsParams = {}, + options: RequestOptions = {}, + ): Promise> { + return this.get("/v1/bansafe/findings", params, options); + } + + listEnforcement( + params: ListBanSafeEnforcementParams = {}, + options: RequestOptions = {}, + ): Promise> { + return this.get("/v1/bansafe/enforcement", params, options); + } + + listIncidents( + params: ListBanSafeIncidentsParams = {}, + options: RequestOptions = {}, + ): Promise> { + return this.get("/v1/bansafe/incidents", params, options); + } + + createIncident( + body: ReportBanSafeIncidentRequest, + options: RequestOptions, + ): Promise>> { + return this.transport.request({ + method: "POST", + path: "/v1/bansafe/incidents", + body, + ...options, + }); + } + + retractIncident( + incidentId: string, + options: RequestOptions = {}, + ): Promise>> { + return this.transport.request({ + method: "POST", + path: `/v1/bansafe/incidents/${encodeURIComponent(incidentId)}/retract`, + ...options, + }); + } + + listClaims( + params: ListBanSafeClaimsParams = {}, + options: RequestOptions = {}, + ): Promise> { + return this.get("/v1/bansafe/claims", params, options); + } + + getClaim( + claimId: string, + options: RequestOptions = {}, + ): Promise>> { + return this.get( + `/v1/bansafe/claims/${encodeURIComponent(claimId)}`, + {}, + options, + ); + } + + private get( + path: string, + params: object, + options: RequestOptions, + ): Promise> { + return this.transport.request({ + method: "GET", + path, + query: params as Readonly>, + ...options, + }); + } +} diff --git a/packages/typescript/src/platform/client.ts b/packages/typescript/src/platform/client.ts index ce8a02e..1f1c442 100644 --- a/packages/typescript/src/platform/client.ts +++ b/packages/typescript/src/platform/client.ts @@ -9,6 +9,7 @@ import { AudiencesResource } from "./audiences.js"; import { ApiKeysResource } from "./api-keys.js"; import { AuditLogsResource } from "./audit-logs.js"; import { BillingResource } from "./billing.js"; +import { BanSafeResource } from "./bansafe.js"; import { CampaignsResource } from "./campaigns.js"; import { CustomersResource } from "./customers.js"; import { MediaResource } from "./media.js"; @@ -28,6 +29,7 @@ export class PlatformClient { readonly audiences: AudiencesResource; readonly auditLogs: AuditLogsResource; readonly billing: BillingResource; + readonly banSafe: BanSafeResource; readonly campaigns: CampaignsResource; readonly customers: CustomersResource; readonly members: MembersResource; @@ -60,6 +62,7 @@ export class PlatformClient { this.audiences = new AudiencesResource(transport); this.auditLogs = new AuditLogsResource(transport); this.billing = new BillingResource(transport); + this.banSafe = new BanSafeResource(transport); this.campaigns = new CampaignsResource(transport); this.customers = new CustomersResource(transport); this.members = new MembersResource(transport); diff --git a/packages/typescript/src/platform/projects.ts b/packages/typescript/src/platform/projects.ts index 5b83b83..f656ba8 100644 --- a/packages/typescript/src/platform/projects.ts +++ b/packages/typescript/src/platform/projects.ts @@ -8,6 +8,14 @@ import type { ProductionEnrollmentResult, Project, ProjectWithStats, + ProjectHealthPolicy, + ProjectInsuranceEvidence, + ProjectSafeMode, + ProjectWarmupPlan, + UpdateProjectHealthPolicyRequest, + UpdateProjectInsuranceEvidenceRequest, + UpdateProjectSafeModeRequest, + UpdateProjectWarmupPlanRequest, } from "./types.js"; export class ProjectsResource { @@ -35,6 +43,98 @@ export class ProjectsResource { }); } + getSafeMode( + projectId: string, + options: RequestOptions = {}, + ): Promise>> { + return this.getSetting(projectId, "safe-mode", options); + } + + updateSafeMode( + projectId: string, + body: UpdateProjectSafeModeRequest, + options: RequestOptions = {}, + ): Promise>> { + return this.updateSetting( + projectId, + "safe-mode", + body, + options, + ); + } + + getWarmupPlan( + projectId: string, + options: RequestOptions = {}, + ): Promise>> { + return this.getSetting( + projectId, + "warmup-plan", + options, + ); + } + + updateWarmupPlan( + projectId: string, + body: UpdateProjectWarmupPlanRequest, + options: RequestOptions = {}, + ): Promise>> { + return this.updateSetting( + projectId, + "warmup-plan", + body, + options, + ); + } + + getInsuranceEvidence( + projectId: string, + options: RequestOptions = {}, + ): Promise>> { + return this.getSetting( + projectId, + "insurance-evidence", + options, + ); + } + + updateInsuranceEvidence( + projectId: string, + body: UpdateProjectInsuranceEvidenceRequest, + options: RequestOptions = {}, + ): Promise>> { + return this.updateSetting( + projectId, + "insurance-evidence", + body, + options, + ); + } + + getHealthPolicy( + projectId: string, + options: RequestOptions = {}, + ): Promise>> { + return this.getSetting( + projectId, + "health-policy", + options, + ); + } + + updateHealthPolicy( + projectId: string, + body: UpdateProjectHealthPolicyRequest, + options: RequestOptions = {}, + ): Promise>> { + return this.updateSetting( + projectId, + "health-policy", + body, + options, + ); + } + requestProductionEnrollment( projectId: string, body: ProductionEnrollmentRequest, @@ -76,4 +176,32 @@ export class ProjectsResource { ...options, }); } + + private getSetting( + projectId: string, + setting: + "safe-mode" | "warmup-plan" | "insurance-evidence" | "health-policy", + options: RequestOptions, + ): Promise>> { + return this.transport.request({ + method: "GET", + path: `/v1/projects/${encodeURIComponent(projectId)}/${setting}`, + ...options, + }); + } + + private updateSetting( + projectId: string, + setting: + "safe-mode" | "warmup-plan" | "insurance-evidence" | "health-policy", + body: unknown, + options: RequestOptions, + ): Promise>> { + return this.transport.request({ + method: "PUT", + path: `/v1/projects/${encodeURIComponent(projectId)}/${setting}`, + body, + ...options, + }); + } } diff --git a/packages/typescript/src/platform/sessions.ts b/packages/typescript/src/platform/sessions.ts index 35c0b4a..8ff8d2d 100644 --- a/packages/typescript/src/platform/sessions.ts +++ b/packages/typescript/src/platform/sessions.ts @@ -13,6 +13,8 @@ import type { SessionRemoveResult, SessionStopResult, SessionTierOverrideRequest, + SessionSafeMode, + UpdateSessionSafeModeRequest, } from "./types.js"; export class PlatformSessionsResource { @@ -106,6 +108,30 @@ export class PlatformSessionsResource { ...options, }); } + + getSafeMode( + sessionId: string, + options: RequestOptions = {}, + ): Promise>> { + return this.transport.request({ + method: "GET", + path: `${sessionPath(sessionId)}/safe-mode`, + ...options, + }); + } + + updateSafeMode( + sessionId: string, + body: UpdateSessionSafeModeRequest, + options: RequestOptions = {}, + ): Promise>> { + return this.transport.request({ + method: "PUT", + path: `${sessionPath(sessionId)}/safe-mode`, + body, + ...options, + }); + } } function sessionPath(sessionId: string): string { diff --git a/packages/typescript/src/platform/types.ts b/packages/typescript/src/platform/types.ts index 3c57d10..dd7b0c8 100644 --- a/packages/typescript/src/platform/types.ts +++ b/packages/typescript/src/platform/types.ts @@ -587,3 +587,547 @@ export interface UpdateWidgetSettingsRequest { readonly historySync?: WidgetHistorySync; readonly methods?: readonly WidgetMethod[] | null; } + +export interface CursorPageMetadata { + readonly nextCursor: string | null; + readonly hasMore: boolean; +} + +export interface CursorEnvelope { + readonly data: readonly T[]; + readonly page: CursorPageMetadata; +} + +export type BanSafeHealthBand = + "good" | "fair" | "poor" | "failing" | "unknown"; +export type BanSafeHealthState = + "healthy" | "limited" | "restricted" | "banned"; +export type BanSafeHealthSource = "rules_v1" | "ml_model" | "unavailable"; +export type BanSafeHealthReliability = + "rules_based" | "validated" | "unavailable"; +export type BanSafeHealthUnavailableReason = + "no_active_model" | "invalid_active_model" | "insufficient_fresh_features"; +export type BanSafeEnforcementRung = + "none" | "notify" | "throttle" | "block_cold" | "suspend"; +export type BanSafeAppealState = "none" | "requested" | "granted" | "denied"; + +export interface BanSafeHealthProbabilities { + readonly healthy: number; + readonly limited: number; + readonly restricted: number; + readonly banned: number; +} + +export type BanSafeHealthExplanationGroup = + "direct_condition" | "delivery" | "connection" | "conduct" | "cadence"; + +export interface BanSafeHealthExplanationFactor { + readonly group: BanSafeHealthExplanationGroup; + readonly key: string; + readonly penalty: number; + readonly observedValue: number; + readonly sampleSize: number; +} + +export interface BanSafeHealthExplanation { + readonly penalties: { + readonly conduct: number; + readonly delivery: number; + readonly connection: number; + readonly restriction: number; + readonly total: number; + }; + readonly factors: readonly BanSafeHealthExplanationFactor[]; + readonly measuredGroups: readonly BanSafeHealthExplanationGroup[]; + readonly missingGroups: readonly BanSafeHealthExplanationGroup[]; +} + +export interface BanSafeObservedAccountState { + readonly state: BanSafeHealthState; + readonly observedAt: string; + readonly source: "account_check" | "restriction_event"; +} + +export interface BanSafeHealthProjection { + readonly health: number | null; + readonly band: BanSafeHealthBand; + readonly healthSource: BanSafeHealthSource; + readonly healthEstimatorVersion: string | null; + readonly healthModelVersion: string | null; + readonly healthEvaluatedAt: string | null; + readonly healthFeatureCoverage: number | null; + readonly healthReliability: BanSafeHealthReliability; + readonly healthUnavailableReason: BanSafeHealthUnavailableReason | null; + readonly healthProbabilities: BanSafeHealthProbabilities | null; + readonly mostLikelyHealthState: BanSafeHealthState | null; + readonly healthExplanation: BanSafeHealthExplanation | null; + readonly observedAccountState: BanSafeObservedAccountState | null; +} + +export interface BanSafeNumberEnforcement { + readonly rung: BanSafeEnforcementRung; + readonly previousRung: BanSafeEnforcementRung; + readonly organizationFloor: BanSafeEnforcementRung; + readonly reason: string; + readonly source: "automatic" | "operator"; + readonly throughputPerMinute: number | null; + readonly blocksUnsolicited: boolean; + readonly suspended: boolean; + readonly startedAt: string; + readonly eligibleLiftAt: string | null; + readonly exitProgress: number; + readonly blockingFindings: readonly string[]; + readonly operatorHold: boolean; + readonly appealState: BanSafeAppealState; + readonly state: "applied" | "applying"; +} + +export interface BanSafeNumber extends BanSafeHealthProjection { + readonly sessionId: string; + readonly session: string; + readonly phoneNumber: string; + readonly projectId: string; + readonly enforcement: BanSafeNumberEnforcement | null; +} + +export interface WarmupCurvePoint { + readonly day: number; + readonly allowance: number; +} + +export interface BanSafeNumberWarmup { + readonly enabled: boolean; + readonly tenureSource: "history" | "link" | "plan" | null; + readonly tenureDay: number; + readonly allowance: number | null; + readonly sentToday: number | null; + readonly resetsAt: string | null; + readonly curve: readonly WarmupCurvePoint[]; +} + +export interface BanSafeNumberDetail extends BanSafeNumber { + readonly warmup: BanSafeNumberWarmup; + readonly findings: readonly BanSafeFinding[]; + readonly liftRequires: string | null; + readonly appealState: BanSafeAppealState; +} + +export interface BanSafeHealthPoint extends Omit< + BanSafeHealthProjection, + "healthEvaluatedAt" +> { + readonly healthEvaluatedAt: string; +} + +export interface BanSafeHealthHistory { + readonly sessionId: string; + readonly session: string; + readonly points: readonly BanSafeHealthPoint[]; +} + +export type BanSafeFindingStatus = + "open" | "acknowledged" | "resolved" | "not_measured"; +export type BanSafeFindingSeverity = "info" | "warning" | "critical"; + +export interface BanSafeFinding { + readonly id: string | null; + readonly key: string; + readonly title: string; + readonly summary: string; + readonly fix: string; + readonly status: BanSafeFindingStatus; + readonly severity: BanSafeFindingSeverity | null; + readonly occurrences: number; + readonly reopenedCount: number; + readonly evidence: Readonly>; + readonly sessionId: string; + readonly session: string; + readonly phoneNumber: string; + readonly firstSeenAt: string | null; + readonly lastSeenAt: string | null; + readonly acknowledgedAt: string | null; + readonly acknowledgedBy: string | null; + readonly acknowledgementNote: string | null; + readonly snoozedUntil: string | null; + readonly resolvedAt: string | null; + readonly resolveReason: + "clean" | "key_retired" | "number_removed" | "stale" | null; +} + +export interface BanSafeEnforcementSummary extends BanSafeHealthProjection { + readonly sessionId: string; + readonly session: string; + readonly phoneNumber: string; + readonly projectId: string; + readonly rung: BanSafeEnforcementRung; + readonly previousRung: BanSafeEnforcementRung; + readonly organizationFloor: BanSafeEnforcementRung; + readonly reason: string; + readonly source: "automatic" | "operator"; + readonly throughputPerMinute: number | null; + readonly blocksUnsolicited: boolean; + readonly suspended: boolean; + readonly blockingFindings: readonly string[]; + readonly startedAt: string; + readonly eligibleLiftAt: string | null; + readonly liftRequires: string; + readonly operatorHold: boolean; + readonly appealState: BanSafeAppealState; + readonly state: "applied" | "applying"; +} + +export type BanSafeIncidentKind = + | "cap_warning" + | "cap_reached" + | "timelock" + | "temporary_ban" + | "permanent_ban" + | "connect_blocked" + | "customer_report"; + +export interface BanSafeIncident { + readonly id: string; + readonly sessionId: string; + readonly session: string; + readonly phoneNumber: string; + readonly projectId: string; + readonly kind: BanSafeIncidentKind; + readonly source: "runtime" | "customer"; + readonly resolution: string; + readonly ambiguous: boolean; + readonly startedAt: string; + readonly endsAt: string | null; + readonly closedAt: string | null; + readonly closedBy: string | null; + readonly claimId: string | null; + readonly note: string | null; + readonly reportedBy: string | null; + readonly createdAt: string; +} + +export interface ReportBanSafeIncidentRequest { + readonly session: string; + readonly occurredAt?: string; + readonly note?: string; +} + +export interface BanSafeIncidentReceipt { + readonly incidentId: string; + readonly created: boolean; + readonly sessionId: string; + readonly session: string; + readonly occurredAt: string; +} + +export type BanSafeClaimStatus = + "filed" | "under_review" | "approved" | "denied" | "paid" | "reversed"; +export type BanSafeClaimVerdict = + | "other_device" + | "customer_conduct" + | "shared_network" + | "ours" + | "inconclusive"; + +export interface BanSafeClaimEvidence { + readonly attributionRuleVersion: number | null; + readonly windowDays: number; + readonly deviceEvidence: boolean; + readonly otherDevices: number; + readonly restrictedInWindow: boolean; + readonly criticalFindingDays: number; + readonly sharedConnection: boolean; + readonly measuredHours: number; +} + +export interface BanSafeClaim { + readonly id: string; + readonly incidentId: string; + readonly sessionId: string; + readonly session: string; + readonly phoneNumber: string; + readonly projectId: string; + readonly status: BanSafeClaimStatus; + readonly verdict: BanSafeClaimVerdict; + readonly windowStart: string; + readonly windowEnd: string; + readonly measuredCents: number; + readonly capCents: number; + readonly amountCents: number; + readonly evidence: BanSafeClaimEvidence; + readonly summary: string; + readonly reason: string; + readonly decidedAt: string | null; + readonly paidAt: string | null; + readonly createdAt: string; +} + +export interface ListBanSafeHealthParams { + readonly projectId?: string; + readonly cursor?: string; + readonly limit?: number; +} + +export interface ListBanSafeHealthHistoryParams { + readonly since?: string; + readonly limit?: number; +} + +export interface ListBanSafeFindingsParams extends ListBanSafeHealthParams { + readonly session?: string; + readonly status?: Exclude; + readonly severity?: BanSafeFindingSeverity; +} + +export interface ListBanSafeEnforcementParams extends ListBanSafeHealthParams { + readonly rung?: BanSafeEnforcementRung; +} + +export interface ListBanSafeIncidentsParams extends ListBanSafeHealthParams { + readonly session?: string; +} + +export interface ListBanSafeClaimsParams extends ListBanSafeHealthParams { + readonly session?: string; + readonly status?: BanSafeClaimStatus; +} + +export type BanSafeSignalKind = + "number" | "boolean" | "enum" | "histogram" | "code_counts"; +export type BanSafeSignalUnit = + "count" | "milliseconds" | "unix_milliseconds" | "ratio" | "none"; + +export interface BanSafeSignalDefinition { + readonly key: string; + readonly label: string; + readonly group: string; + readonly kind: BanSafeSignalKind; + readonly unit: BanSafeSignalUnit; + readonly description: string; +} + +export interface BanSafeSignal extends BanSafeSignalDefinition { + readonly measured: boolean; + readonly value: number | boolean | string | readonly number[] | null; + readonly sampleSize: number | null; + readonly codes: + readonly { readonly code: number; readonly count: number }[] | null; +} + +export type BanSafeCollectionState = + "fresh" | "stale" | "not_collected" | "unsupported"; + +export interface BanSafeCollectionStatus { + readonly state: BanSafeCollectionState; + readonly latestFlushedAt: string | null; + readonly latestReceivedAt: string | null; + readonly freshUntil: string | null; + readonly recordVersion: number | null; + readonly collectorVersion: number | null; + readonly partial: boolean | null; + readonly droppedRecords: number | null; +} + +export interface BanSafeTelemetrySnapshot { + readonly bucketStart: string; + readonly flushedAt: string; + readonly receivedAt: string; + readonly partial: boolean; + readonly recordVersion: number | null; + readonly signals: readonly BanSafeSignal[]; +} + +export interface BanSafeCollectionSession { + readonly sessionId: string; + readonly session: string; + readonly projectId: string; + readonly collection: BanSafeCollectionStatus; +} + +export interface BanSafeTelemetryDetail extends BanSafeCollectionSession { + readonly snapshot: BanSafeTelemetrySnapshot | null; +} + +export interface ListBanSafeTelemetryHistoryParams { + readonly since?: string; + readonly until?: string; + readonly cursor?: string; + readonly limit?: number; +} + +export type ListBanSafeCollectionParams = ListBanSafeHealthParams; + +export type BanSafeHealthActionMode = "apply" | "clear"; +export type BanSafeHealthActionKind = + "stop" | "slow_down" | "log_out" | "email" | "webhook"; +export type BanSafeHealthActionStatus = + "pending" | "running" | "succeeded" | "failed" | "cancelled"; +export type BanSafeHealthActionOutcome = + | "applied" + | "cleared" + | "notification_queued" + | "superseded" + | "expired" + | "not_applied" + | "delivery_failed"; + +export interface BanSafeHealthAction { + readonly id: string; + readonly sessionId: string; + readonly session: string; + readonly projectId: string; + readonly mode: BanSafeHealthActionMode; + readonly action: BanSafeHealthActionKind; + readonly status: BanSafeHealthActionStatus; + readonly health: number; + readonly threshold: number; + readonly healthSource: Exclude; + readonly estimatorVersion: string; + readonly modelVersion: string | null; + readonly slowDownMps: number | null; + readonly evaluatedAt: string; + readonly createdAt: string; + readonly completedAt: string | null; + readonly outcome: BanSafeHealthActionOutcome | null; +} + +export interface ListBanSafeHealthActionsParams extends ListBanSafeHealthParams { + readonly session?: string; + readonly status?: BanSafeHealthActionStatus; +} + +export type BanSafeHealthEnvelope = CursorEnvelope; +export type BanSafeFindingsEnvelope = CursorEnvelope; +export type BanSafeEnforcementEnvelope = + CursorEnvelope; +export type BanSafeIncidentsEnvelope = CursorEnvelope; +export type BanSafeClaimsEnvelope = CursorEnvelope; +export type BanSafeTelemetryHistoryEnvelope = + CursorEnvelope; +export type BanSafeCollectionEnvelope = + CursorEnvelope; +export type BanSafeHealthActionsEnvelope = CursorEnvelope; + +export type SafeModePresence = "dark" | "online_while_sending" | "online_hours"; +export type SafeModeTyping = "off" | "before_text" | "before_all"; +export type SafeModeReads = "off" | "replied_chats" | "all_inbound"; +export type SafeModePacing = "off" | "jittered" | "conversation"; + +export interface SafeModeSettings { + readonly presence: SafeModePresence; + readonly typing: SafeModeTyping; + readonly reads: SafeModeReads; + readonly pacing: SafeModePacing; + readonly onlineStart: number; + readonly onlineEnd: number; +} + +export interface UpdateProjectSafeModeRequest { + readonly presence?: SafeModePresence; + readonly typing?: SafeModeTyping; + readonly reads?: SafeModeReads; + readonly pacing?: SafeModePacing; + readonly onlineStart?: number; + readonly onlineEnd?: number; +} + +export interface ProjectSafeMode { + readonly projectId: string; + readonly ceiling: SafeModeSettings; + readonly entitled: boolean; + readonly entitlementReason: string | null; +} + +export interface SafeModeOverride { + readonly presence: SafeModePresence | "inherit"; + readonly typing: SafeModeTyping | "inherit"; + readonly reads: SafeModeReads | "inherit"; + readonly pacing: SafeModePacing | "inherit"; +} + +export interface SafeModeApplied { + readonly observedAt: string; + readonly presence: string | null; + readonly typing: string | null; + readonly reads: string | null; + readonly pacing: string | null; +} + +export interface SessionSafeMode { + readonly session: string; + readonly projectId: string; + readonly project: SafeModeSettings; + readonly override: SafeModeOverride; + readonly effective: SafeModeSettings; + readonly applied: SafeModeApplied | null; + readonly mismatch: boolean; + readonly entitled: boolean; + readonly entitlementReason: string | null; +} + +export interface UpdateSessionSafeModeRequest { + readonly presence?: SafeModePresence | "inherit"; + readonly typing?: SafeModeTyping | "inherit"; + readonly reads?: SafeModeReads | "inherit"; + readonly pacing?: SafeModePacing | "inherit"; +} + +export interface WarmupPlanSettings { + readonly enabled: boolean; + readonly warmupDays: number; + readonly dailyStart: number; +} + +export interface ProjectWarmupPlan { + readonly projectId: string; + readonly plan: WarmupPlanSettings; + readonly ceiling: number; + readonly curve: readonly WarmupCurvePoint[]; + readonly entitled: boolean; + readonly entitlementReason: string | null; +} + +export interface UpdateProjectWarmupPlanRequest { + readonly enabled?: boolean; + readonly warmupDays?: number; + readonly dailyStart?: number; +} + +export interface ProjectInsuranceEvidence { + readonly projectId: string; + readonly enabled: boolean; + readonly banInsuranceIncluded: boolean; +} + +export interface UpdateProjectInsuranceEvidenceRequest { + readonly enabled: boolean; +} + +export type ProjectHealthSessionAction = + "none" | "stop" | "slow_down" | "log_out"; + +export interface ProjectHealthPolicyIntegrations { + readonly emailConfigured: boolean; + readonly webhookConfigured: boolean; +} + +export interface ProjectHealthPolicy { + readonly projectId: string; + readonly version: number; + readonly enabled: boolean; + readonly threshold: number; + readonly sessionAction: ProjectHealthSessionAction; + readonly slowDownMps: number | null; + readonly emailNotification: boolean; + readonly webhookNotification: boolean; + readonly integrations: ProjectHealthPolicyIntegrations; +} + +export interface UpdateProjectHealthPolicyRequest { + readonly version: number; + readonly enabled: boolean; + readonly threshold: number; + readonly sessionAction: ProjectHealthSessionAction; + readonly slowDownMps: number | null; + readonly emailNotification: boolean; + readonly webhookNotification: boolean; +} diff --git a/packages/typescript/test/bansafe-contract.test.ts b/packages/typescript/test/bansafe-contract.test.ts new file mode 100644 index 0000000..5cb663f --- /dev/null +++ b/packages/typescript/test/bansafe-contract.test.ts @@ -0,0 +1,101 @@ +import { createHash } from "node:crypto"; +import { readFileSync } from "node:fs"; +import { resolve } from "node:path"; +import { describe, expect, it } from "vitest"; + +import { PlatformClient } from "../src/index.js"; + +const root = resolve(import.meta.dirname, "../../.."); +const source = JSON.parse( + readFileSync(resolve(root, "contracts/drafts/bansafe/source.json"), "utf8"), +) as { + sourceState: string; + contracts: Record; +}; +const coverage = JSON.parse( + readFileSync(resolve(root, "contracts/drafts/bansafe/coverage.json"), "utf8"), +) as { + platformSha256: string; + covered: number; + excluded: number; + missing: number; + operations: Array<{ + operationId: string; + method: string; + path: string; + status: "covered" | "excluded"; + sdkPath?: string; + }>; +}; +const platform = JSON.parse( + readFileSync(resolve(root, source.contracts.platform!.snapshotPath), "utf8"), +) as { + paths: Record< + string, + Record< + string, + { operationId?: string; tags?: string[]; description?: string } + > + >; +}; + +describe("BanSafe draft contract coverage", () => { + it("pins the generated draft by content hash without claiming a merged source", () => { + expect(source.sourceState).toBe("uncommitted-bansafe-draft"); + for (const contract of Object.values(source.contracts)) { + const hash = createHash("sha256") + .update(readFileSync(resolve(root, contract.snapshotPath))) + .digest("hex"); + expect(hash).toBe(contract.sha256); + } + expect(coverage.platformSha256).toBe(source.contracts.platform!.sha256); + }); + + it("accounts for every generated BanSafe operation", () => { + const generated = Object.entries(platform.paths).flatMap(([path, item]) => + Object.entries(item) + .filter( + ([method, operation]) => + ["get", "post", "put", "patch", "delete"].includes(method) && + operation.tags?.includes("bansafe"), + ) + .map(([method, operation]) => ({ + operationId: operation.operationId, + method: method.toUpperCase(), + path, + })), + ); + expect( + coverage.operations.map(({ operationId, method, path }) => ({ + operationId, + method, + path, + })), + ).toEqual(generated); + expect(coverage).toMatchObject({ covered: 25, excluded: 2, missing: 0 }); + }); + + it("maps covered operations to methods and excludes dashboard-only actions", () => { + const client = new PlatformClient({ + apiKey: "pmfa_contract", + baseUrl: "https://example.invalid", + }); + for (const operation of coverage.operations) { + if (operation.status === "excluded") continue; + const path = operation + .sdkPath!.replace(/^PlatformClient\./, "") + .split("."); + let value: unknown = client; + for (const part of path) value = (value as Record)[part]; + expect(typeof value, operation.sdkPath).toBe("function"); + } + + expect( + coverage.operations + .filter(({ status }) => status === "excluded") + .map(({ operationId }) => operationId), + ).toEqual(["acknowledgeBanSafeFinding", "appealBanSafeEnforcement"]); + expect(client.banSafe).not.toHaveProperty("acknowledgeFinding"); + expect(client.banSafe).not.toHaveProperty("appealEnforcement"); + }); +}); diff --git a/packages/typescript/test/bansafe.test.ts b/packages/typescript/test/bansafe.test.ts new file mode 100644 index 0000000..04aabc3 --- /dev/null +++ b/packages/typescript/test/bansafe.test.ts @@ -0,0 +1,214 @@ +import { afterEach, describe, expect, expectTypeOf, it } from "vitest"; + +import { + BanSafeResource, + PlatformClient, + type ApiResponse, + type BanSafeCollectionEnvelope, + type BanSafeHealthActionsEnvelope, + type BanSafeHealthEnvelope, + type BanSafeHealthHistory, + type BanSafeSignalDefinition, + type BanSafeTelemetryDetail, + type BanSafeTelemetryHistoryEnvelope, + type DataEnvelope, + type ProjectHealthPolicy, +} from "../src/index.js"; +import { + startTestServer, + type RecordedRequest, + type TestServer, +} from "./support/http-server.js"; + +const servers: TestServer[] = []; + +afterEach(async () => { + await Promise.all(servers.splice(0).map((server) => server.close())); +}); + +async function testClient(): Promise<{ + client: PlatformClient; + requests: RecordedRequest[]; +}> { + const server = await startTestServer(() => ({ + headers: { "content-type": "application/json" }, + body: '{"data":[],"page":{"nextCursor":null,"hasMore":false}}', + })); + servers.push(server); + return { + client: new PlatformClient({ + apiKey: "pmfa_bansafe", + baseUrl: server.url, + maxNetworkRetries: 0, + }), + requests: server.requests, + }; +} + +describe("PlatformClient BanSafe resources", () => { + it("exposes typed Health and telemetry reads without dashboard-only mutations", async () => { + const { client, requests } = await testClient(); + expectTypeOf(client.banSafe).toEqualTypeOf(); + expect(client.banSafe).not.toHaveProperty("acknowledgeFinding"); + expect(client.banSafe).not.toHaveProperty("appealEnforcement"); + + const health = await client.banSafe.listHealth({ + projectId: "project/a", + cursor: "cursor/a", + limit: 25, + }); + const detail = await client.banSafe.getHealth("session/a"); + const history = await client.banSafe.listHealthHistory("session/a", { + since: "2026-09-07T00:00:00.000Z", + limit: 12, + }); + const signals = await client.banSafe.listSignals(); + const telemetry = await client.banSafe.getTelemetry("session/a"); + const telemetryHistory = await client.banSafe.listTelemetryHistory( + "session/a", + { + since: "2026-09-07T00:00:00.000Z", + until: "2026-09-08T00:00:00.000Z", + cursor: "cursor/b", + limit: 10, + }, + ); + const collection = await client.banSafe.listCollection({ + projectId: "project/a", + cursor: "cursor/c", + limit: 25, + }); + const actions = await client.banSafe.listHealthActions({ + projectId: "project/a", + session: "session/a", + status: "succeeded", + cursor: "cursor/d", + limit: 25, + }); + + expectTypeOf(health).toEqualTypeOf>(); + expectTypeOf(detail.data.data).toHaveProperty("healthEstimatorVersion"); + expectTypeOf(history).toEqualTypeOf< + ApiResponse> + >(); + expectTypeOf(signals).toEqualTypeOf< + ApiResponse> + >(); + expectTypeOf(telemetry).toEqualTypeOf< + ApiResponse> + >(); + expectTypeOf(telemetryHistory).toEqualTypeOf< + ApiResponse + >(); + expectTypeOf(collection).toEqualTypeOf< + ApiResponse + >(); + expectTypeOf(actions).toEqualTypeOf< + ApiResponse + >(); + expect(requests.map(({ method, path }) => `${method} ${path}`)).toEqual([ + "GET /v1/bansafe/health?projectId=project%2Fa&cursor=cursor%2Fa&limit=25", + "GET /v1/bansafe/health/session%2Fa", + "GET /v1/bansafe/health/session%2Fa/history?since=2026-09-07T00%3A00%3A00.000Z&limit=12", + "GET /v1/bansafe/signals", + "GET /v1/bansafe/telemetry/session%2Fa", + "GET /v1/bansafe/telemetry/session%2Fa/history?since=2026-09-07T00%3A00%3A00.000Z&until=2026-09-08T00%3A00%3A00.000Z&cursor=cursor%2Fb&limit=10", + "GET /v1/bansafe/collection?projectId=project%2Fa&cursor=cursor%2Fc&limit=25", + "GET /v1/bansafe/health-actions?projectId=project%2Fa&session=session%2Fa&status=succeeded&cursor=cursor%2Fd&limit=25", + ]); + }); + + it("maps API-key-authorized findings, enforcement, incidents, and claims", async () => { + const { client, requests } = await testClient(); + await client.banSafe.listFindings({ + projectId: "project/a", + session: "session/a", + status: "open", + severity: "critical", + limit: 5, + }); + await client.banSafe.listEnforcement({ + projectId: "project/a", + rung: "throttle", + }); + await client.banSafe.listIncidents({ + projectId: "project/a", + session: "session/a", + }); + await client.banSafe.createIncident( + { + session: "session/a", + occurredAt: "2026-09-08T00:00:00.000Z", + note: "WhatsApp restricted sending", + }, + { idempotencyKey: "incident/a" }, + ); + await client.banSafe.retractIncident("incident/a"); + await client.banSafe.listClaims({ + projectId: "project/a", + session: "session/a", + status: "under_review", + }); + await client.banSafe.getClaim("claim/a"); + + expect(requests.map(({ method, path }) => `${method} ${path}`)).toEqual([ + "GET /v1/bansafe/findings?projectId=project%2Fa&session=session%2Fa&status=open&severity=critical&limit=5", + "GET /v1/bansafe/enforcement?projectId=project%2Fa&rung=throttle", + "GET /v1/bansafe/incidents?projectId=project%2Fa&session=session%2Fa", + "POST /v1/bansafe/incidents", + "POST /v1/bansafe/incidents/incident%2Fa/retract", + "GET /v1/bansafe/claims?projectId=project%2Fa&session=session%2Fa&status=under_review", + "GET /v1/bansafe/claims/claim%2Fa", + ]); + expect(requests[3]?.headers["idempotency-key"]).toBe("incident/a"); + expect(JSON.parse(requests[3]!.body)).toEqual({ + session: "session/a", + occurredAt: "2026-09-08T00:00:00.000Z", + note: "WhatsApp restricted sending", + }); + }); + + it("maps project and session safety settings to their typed owners", async () => { + const { client, requests } = await testClient(); + await client.projects.getSafeMode("project/a"); + await client.projects.updateSafeMode("project/a", { pacing: "jittered" }); + await client.projects.getWarmupPlan("project/a"); + await client.projects.updateWarmupPlan("project/a", { + enabled: true, + warmupDays: 30, + dailyStart: 20, + }); + await client.projects.getInsuranceEvidence("project/a"); + await client.projects.updateInsuranceEvidence("project/a", { + enabled: true, + }); + const policy = await client.projects.getHealthPolicy("project/a"); + await client.projects.updateHealthPolicy("project/a", { + version: 4, + enabled: true, + threshold: 50, + sessionAction: "slow_down", + slowDownMps: 0.5, + emailNotification: true, + webhookNotification: true, + }); + await client.sessions.getSafeMode("session/a"); + await client.sessions.updateSafeMode("session/a", { typing: "inherit" }); + + expectTypeOf(policy).toEqualTypeOf< + ApiResponse> + >(); + expect(requests.map(({ method, path }) => `${method} ${path}`)).toEqual([ + "GET /v1/projects/project%2Fa/safe-mode", + "PUT /v1/projects/project%2Fa/safe-mode", + "GET /v1/projects/project%2Fa/warmup-plan", + "PUT /v1/projects/project%2Fa/warmup-plan", + "GET /v1/projects/project%2Fa/insurance-evidence", + "PUT /v1/projects/project%2Fa/insurance-evidence", + "GET /v1/projects/project%2Fa/health-policy", + "PUT /v1/projects/project%2Fa/health-policy", + "GET /v1/sessions/session%2Fa/safe-mode", + "PUT /v1/sessions/session%2Fa/safe-mode", + ]); + }); +}); From 43237c22c7224eae2b9841b3c44821d3e525993c Mon Sep 17 00:00:00 2001 From: Rajeh Taher Date: Tue, 8 Sep 2026 04:14:48 +0300 Subject: [PATCH 2/8] chore: preserve draft contract snapshots --- .prettierignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.prettierignore b/.prettierignore index b2e3804..e0c7b7f 100644 --- a/.prettierignore +++ b/.prettierignore @@ -3,4 +3,6 @@ packages/*/dist/ coverage/ contracts/openapi.messaging.json contracts/openapi.platform.json +contracts/drafts/bansafe/openapi.messaging.json +contracts/drafts/bansafe/openapi.platform.json package-lock.json From 35fe3d62bde13478b22b42a1c014555de09f1d42 Mon Sep 17 00:00:00 2001 From: Rajeh Taher Date: Tue, 8 Sep 2026 04:19:06 +0300 Subject: [PATCH 3/8] chore: refresh integrated BanSafe contracts --- contracts/drafts/bansafe/coverage.json | 2 +- .../drafts/bansafe/openapi.messaging.json | 5376 ++++++++++++++--- .../drafts/bansafe/openapi.platform.json | 647 +- contracts/drafts/bansafe/source.json | 6 +- 4 files changed, 4907 insertions(+), 1124 deletions(-) diff --git a/contracts/drafts/bansafe/coverage.json b/contracts/drafts/bansafe/coverage.json index c807812..7bc6aee 100644 --- a/contracts/drafts/bansafe/coverage.json +++ b/contracts/drafts/bansafe/coverage.json @@ -1,6 +1,6 @@ { "schemaVersion": 1, - "platformSha256": "9b37273ee85a1ce07d456060d46ce18a70832895f03e20ad83319d053232e0c5", + "platformSha256": "d529a62ddcc8e5b661b90db7ca9a36dddc30ca48a6a016c4f6b46e0fd471b9df", "scope": "OpenAPI operations tagged bansafe", "covered": 25, "excluded": 2, diff --git a/contracts/drafts/bansafe/openapi.messaging.json b/contracts/drafts/bansafe/openapi.messaging.json index 4310d96..781745f 100644 --- a/contracts/drafts/bansafe/openapi.messaging.json +++ b/contracts/drafts/bansafe/openapi.messaging.json @@ -3,7 +3,7 @@ "info": { "title": "Polymorfa WhatsApp API", "version": "1.0.0", - "description": "Public Polymorfa REST API for sessions, messaging, media, webhooks, campaigns, templates, client tokens, widgets, and bridge routing.", + "description": "Public Polymorfa REST API for sessions, messaging, media, webhooks, campaigns, templates, client tokens, QuickLinks, and bridge routing.", "contact": { "name": "Polymorfa API", "url": "https://docs.polymorfa.com" @@ -244,9 +244,7 @@ }, "interactive": { "type": "object", - "additionalProperties": { - "nullable": true - } + "additionalProperties": {} } }, "required": [ @@ -283,6 +281,9 @@ }, "event": { "type": "string", + "enum": [ + "message.received" + ], "description": "Event type" }, "payload": { @@ -341,6 +342,9 @@ }, "event": { "type": "string", + "enum": [ + "message.sent" + ], "description": "Event type" }, "payload": { @@ -403,6 +407,9 @@ }, "event": { "type": "string", + "enum": [ + "message.ack" + ], "description": "Event type" }, "payload": { @@ -434,6 +441,9 @@ }, "event": { "type": "string", + "enum": [ + "message.revoked" + ], "description": "Event type" }, "payload": { @@ -465,6 +475,9 @@ }, "event": { "type": "string", + "enum": [ + "message.reaction" + ], "description": "Event type" }, "payload": { @@ -496,6 +509,9 @@ }, "event": { "type": "string", + "enum": [ + "message.edited" + ], "description": "Event type" }, "payload": { @@ -527,6 +543,9 @@ }, "event": { "type": "string", + "enum": [ + "message.update" + ], "description": "Event type" }, "payload": { @@ -581,6 +600,9 @@ }, "event": { "type": "string", + "enum": [ + "message.delete" + ], "description": "Event type" }, "payload": { @@ -638,6 +660,9 @@ }, "event": { "type": "string", + "enum": [ + "message.vote" + ], "description": "Event type" }, "payload": { @@ -708,6 +733,9 @@ }, "event": { "type": "string", + "enum": [ + "session.status" + ], "description": "Event type" }, "payload": { @@ -750,6 +778,9 @@ }, "event": { "type": "string", + "enum": [ + "session.qr" + ], "description": "Event type" }, "payload": { @@ -806,6 +837,9 @@ }, "event": { "type": "string", + "enum": [ + "session.connected" + ], "description": "Event type" }, "payload": { @@ -848,6 +882,9 @@ }, "event": { "type": "string", + "enum": [ + "session.logged_out" + ], "description": "Event type" }, "payload": { @@ -910,6 +947,9 @@ }, "event": { "type": "string", + "enum": [ + "session.phone_offline" + ], "description": "Event type" }, "payload": { @@ -961,6 +1001,9 @@ }, "event": { "type": "string", + "enum": [ + "group.update" + ], "description": "Event type" }, "payload": { @@ -1027,6 +1070,9 @@ }, "event": { "type": "string", + "enum": [ + "group.participant" + ], "description": "Event type" }, "payload": { @@ -1087,6 +1133,9 @@ }, "event": { "type": "string", + "enum": [ + "presence.update" + ], "description": "Event type" }, "payload": { @@ -1163,6 +1212,9 @@ }, "event": { "type": "string", + "enum": [ + "contact.update" + ], "description": "Event type" }, "payload": { @@ -1211,6 +1263,9 @@ }, "event": { "type": "string", + "enum": [ + "chat.archive" + ], "description": "Event type" }, "payload": { @@ -1260,6 +1315,9 @@ }, "event": { "type": "string", + "enum": [ + "chat.mute" + ], "description": "Event type" }, "payload": { @@ -1306,6 +1364,9 @@ }, "event": { "type": "string", + "enum": [ + "chat.read" + ], "description": "Event type" }, "payload": { @@ -1348,6 +1409,9 @@ }, "event": { "type": "string", + "enum": [ + "chat.clear" + ], "description": "Event type" }, "payload": { @@ -1390,6 +1454,9 @@ }, "event": { "type": "string", + "enum": [ + "chat.delete" + ], "description": "Event type" }, "payload": { @@ -1412,11 +1479,17 @@ }, "callId": { "type": "string" + }, + "hasVideo": { + "type": "boolean", + "description": "Whether the offered call advertised video.", + "example": false } }, "required": [ "from", - "callId" + "callId", + "hasVideo" ] }, "CallReceivedEvent": { @@ -1436,6 +1509,9 @@ }, "event": { "type": "string", + "enum": [ + "call.received" + ], "description": "Event type" }, "payload": { @@ -1486,6 +1562,9 @@ }, "event": { "type": "string", + "enum": [ + "call.missed" + ], "description": "Event type" }, "payload": { @@ -1532,6 +1611,9 @@ }, "event": { "type": "string", + "enum": [ + "call.accepted" + ], "description": "Event type" }, "payload": { @@ -1578,6 +1660,9 @@ }, "event": { "type": "string", + "enum": [ + "call.rejected" + ], "description": "Event type" }, "payload": { @@ -1592,6 +1677,391 @@ "payload" ] }, + "CallEndedPayload": { + "type": "object", + "properties": { + "from": { + "type": "object", + "nullable": true, + "properties": { + "id": { + "type": "string" + }, + "phoneNumber": { + "type": "string" + }, + "username": { + "type": "string" + }, + "lid": { + "type": "string", + "deprecated": true + }, + "mode": { + "type": "string", + "enum": [ + "pn", + "lid" + ], + "deprecated": true + } + }, + "required": [ + "id" + ] + }, + "callId": { + "type": "string" + }, + "durationSeconds": { + "type": "integer", + "description": "Total connected duration in seconds (0 if never answered).", + "example": 42 + }, + "reason": { + "type": "string", + "description": "Termination reason: user_hangup | timeout | lost_connection | rejected | capacity | pod_lost.", + "example": "user_hangup" + }, + "direction": { + "type": "string", + "enum": [ + "inbound", + "outbound" + ], + "description": "Call direction.", + "example": "inbound" + }, + "hadVideo": { + "type": "boolean", + "description": "Whether the call carried video.", + "example": false + } + }, + "required": [ + "from", + "callId", + "durationSeconds", + "reason", + "direction", + "hadVideo" + ] + }, + "CallEndedEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "enum": [ + "call.ended" + ], + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/CallEndedPayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ] + }, + "CallTelemetryPayload": { + "type": "object", + "properties": { + "callId": { + "type": "string" + }, + "setupMs": { + "type": "integer", + "description": "Time from offer to media_ready, in milliseconds.", + "example": 850 + }, + "ringMs": { + "type": "integer", + "description": "Time spent ringing before accept, in milliseconds.", + "example": 3200 + }, + "durationSeconds": { + "type": "integer", + "description": "Total connected duration in seconds.", + "example": 42 + }, + "terminateReason": { + "type": "string", + "description": "Termination reason: user_hangup | timeout | lost_connection | rejected | capacity.", + "example": "user_hangup" + }, + "codec": { + "type": "string", + "description": "Negotiated audio codec's bare subtype; empty when no codec stats.", + "example": "opus" + }, + "jitterMs": { + "type": "number", + "description": "Inbound RTP jitter for the audio stream, in milliseconds.", + "example": 12.5 + }, + "packetsLost": { + "type": "integer", + "description": "Cumulative inbound RTP packets lost for the audio stream.", + "example": 3 + }, + "rttMs": { + "type": "number", + "description": "Estimated round-trip time from the remote-inbound report, in milliseconds.", + "example": 48.2 + }, + "recvKbps": { + "type": "number", + "description": "Total inbound volume across all RTP streams, in kilobits (cumulative).", + "example": 2048 + }, + "sendKbps": { + "type": "number", + "description": "Total outbound volume across all RTP streams, in kilobits (cumulative).", + "example": 2011 + } + }, + "required": [ + "callId", + "setupMs", + "ringMs", + "durationSeconds", + "terminateReason", + "codec", + "jitterMs", + "packetsLost", + "rttMs", + "recvKbps", + "sendKbps" + ] + }, + "CallTelemetryEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "enum": [ + "call.telemetry" + ], + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/CallTelemetryPayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ] + }, + "CallParticipant": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "handle": { + "type": "string" + }, + "audioMuted": { + "type": "boolean", + "enum": [ + false + ], + "description": "Reserved; false until WhatsApp exposes authoritative participant mute state." + }, + "video": { + "type": "boolean", + "enum": [ + false + ], + "description": "Reserved; false until WhatsApp exposes authoritative participant video state." + }, + "state": { + "type": "string", + "enum": [ + "invited", + "ringing", + "connected", + "left" + ] + } + }, + "required": [ + "id", + "handle", + "audioMuted", + "video", + "state" + ] + }, + "CallParticipantPayload": { + "type": "object", + "properties": { + "callId": { + "type": "string" + }, + "participant": { + "$ref": "#/components/schemas/CallParticipant" + } + }, + "required": [ + "callId", + "participant" + ] + }, + "CallParticipantJoinedEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "enum": [ + "call.participant_joined" + ], + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/CallParticipantPayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ] + }, + "CallParticipantStateEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "enum": [ + "call.participant_state" + ], + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/CallParticipantPayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ] + }, + "CallParticipantLeftPayload": { + "type": "object", + "properties": { + "callId": { + "type": "string" + }, + "participantId": { + "type": "string" + }, + "reason": { + "type": "string" + } + }, + "required": [ + "callId", + "participantId" + ] + }, + "CallParticipantLeftEvent": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique event identifier" + }, + "session": { + "type": "string", + "description": "Session that produced this event" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp" + }, + "event": { + "type": "string", + "enum": [ + "call.participant_left" + ], + "description": "Event type" + }, + "payload": { + "$ref": "#/components/schemas/CallParticipantLeftPayload" + } + }, + "required": [ + "id", + "session", + "timestamp", + "event", + "payload" + ] + }, "NewsletterUpdatePayload": { "type": "object", "properties": { @@ -1627,6 +2097,9 @@ }, "event": { "type": "string", + "enum": [ + "newsletter.update" + ], "description": "Event type" }, "payload": { @@ -1701,6 +2174,9 @@ }, "event": { "type": "string", + "enum": [ + "blocklist.update" + ], "description": "Event type" }, "payload": { @@ -1798,6 +2274,9 @@ }, "event": { "type": "string", + "enum": [ + "labels.update" + ], "description": "Event type" }, "payload": { @@ -1879,6 +2358,9 @@ }, "event": { "type": "string", + "enum": [ + "business.quick_reply.update" + ], "description": "Event type" }, "payload": { @@ -1974,6 +2456,9 @@ }, "event": { "type": "string", + "enum": [ + "history.sync" + ], "description": "Event type" }, "payload": { @@ -2002,9 +2487,7 @@ }, "data": { "type": "object", - "additionalProperties": { - "nullable": true - } + "additionalProperties": {} }, "error": { "type": "string" @@ -2033,6 +2516,9 @@ }, "event": { "type": "string", + "enum": [ + "command.result" + ], "description": "Event type" }, "payload": { @@ -2113,6 +2599,9 @@ }, "event": { "type": "string", + "enum": [ + "customer.enabled" + ], "description": "Event type" }, "payload": { @@ -2189,6 +2678,9 @@ }, "event": { "type": "string", + "enum": [ + "customer.created" + ], "description": "Event type" }, "payload": { @@ -2279,6 +2771,9 @@ }, "event": { "type": "string", + "enum": [ + "customer.updated" + ], "description": "Event type" }, "payload": { @@ -2365,6 +2860,9 @@ }, "event": { "type": "string", + "enum": [ + "customer.archiving" + ], "description": "Event type" }, "payload": { @@ -2441,6 +2939,9 @@ }, "event": { "type": "string", + "enum": [ + "customer.archived" + ], "description": "Event type" }, "payload": { @@ -2517,6 +3018,9 @@ }, "event": { "type": "string", + "enum": [ + "customer.restored" + ], "description": "Event type" }, "payload": { @@ -2598,6 +3102,9 @@ }, "event": { "type": "string", + "enum": [ + "customer.pairing_link.created" + ], "description": "Event type" }, "payload": { @@ -2679,6 +3186,9 @@ }, "event": { "type": "string", + "enum": [ + "customer.pairing_link.opened" + ], "description": "Event type" }, "payload": { @@ -2765,6 +3275,9 @@ }, "event": { "type": "string", + "enum": [ + "customer.pairing_link.connected" + ], "description": "Event type" }, "payload": { @@ -2851,6 +3364,9 @@ }, "event": { "type": "string", + "enum": [ + "customer.pairing_link.failed" + ], "description": "Event type" }, "payload": { @@ -2932,6 +3448,9 @@ }, "event": { "type": "string", + "enum": [ + "customer.pairing_link.expired" + ], "description": "Event type" }, "payload": { @@ -3022,6 +3541,9 @@ }, "event": { "type": "string", + "enum": [ + "customer.pairing_link.revoked" + ], "description": "Event type" }, "payload": { @@ -3107,6 +3629,9 @@ }, "event": { "type": "string", + "enum": [ + "customer.number.attached" + ], "description": "Event type" }, "payload": { @@ -3193,6 +3718,9 @@ }, "event": { "type": "string", + "enum": [ + "customer.number.transferred" + ], "description": "Event type" }, "payload": { @@ -3279,6 +3807,9 @@ }, "event": { "type": "string", + "enum": [ + "customer.number.disconnected" + ], "description": "Event type" }, "payload": { @@ -3385,6 +3916,9 @@ }, "event": { "type": "string", + "enum": [ + "bansafe.enforcement" + ], "description": "Event type" }, "payload": { @@ -3478,7 +4012,8 @@ "notify", "throttle", "block_cold", - "suspend" + "suspend", + null ], "description": "Restriction previously in force, or null when none was." }, @@ -3602,6 +4137,9 @@ }, "event": { "type": "string", + "enum": [ + "bansafe.action" + ], "description": "Event type" }, "payload": { @@ -3717,6 +4255,9 @@ }, "event": { "type": "string", + "enum": [ + "bansafe.health_threshold" + ], "description": "Event type" }, "payload": { @@ -3843,6 +4384,9 @@ }, "event": { "type": "string", + "enum": [ + "bansafe.incident" + ], "description": "Event type" }, "payload": { @@ -3988,6 +4532,9 @@ }, "event": { "type": "string", + "enum": [ + "bansafe.claim" + ], "description": "Event type" }, "payload": { @@ -4076,6 +4623,9 @@ }, "event": { "type": "string", + "enum": [ + "message.failed" + ], "description": "Event type" }, "payload": { @@ -4150,6 +4700,9 @@ }, "event": { "type": "string", + "enum": [ + "template.status" + ], "description": "Event type" }, "payload": { @@ -4213,6 +4766,9 @@ }, "event": { "type": "string", + "enum": [ + "campaign.paused" + ], "description": "Event type" }, "payload": { @@ -4300,6 +4856,9 @@ }, "event": { "type": "string", + "enum": [ + "campaign.completed" + ], "description": "Event type" }, "payload": { @@ -4357,6 +4916,9 @@ }, "event": { "type": "string", + "enum": [ + "campaign.failed" + ], "description": "Event type" }, "payload": { @@ -4439,6 +5001,9 @@ }, "event": { "type": "string", + "enum": [ + "campaign.recipient_sent" + ], "description": "Event type" }, "payload": { @@ -4514,6 +5079,9 @@ }, "event": { "type": "string", + "enum": [ + "campaign.recipient_failed" + ], "description": "Event type" }, "payload": { @@ -4583,6 +5151,9 @@ }, "event": { "type": "string", + "enum": [ + "campaign.recipient_skipped" + ], "description": "Event type" }, "payload": { @@ -4652,6 +5223,9 @@ }, "event": { "type": "string", + "enum": [ + "campaign.throttled" + ], "description": "Event type" }, "payload": { @@ -4734,6 +5308,9 @@ }, "event": { "type": "string", + "enum": [ + "campaign.cap_reached" + ], "description": "Event type" }, "payload": { @@ -4809,6 +5386,9 @@ }, "event": { "type": "string", + "enum": [ + "campaign.cold_blocked" + ], "description": "Event type" }, "payload": { @@ -5090,6 +5670,21 @@ }, "enabled": { "type": "boolean" + }, + "maxConcurrency": { + "type": "integer", + "minimum": 0, + "default": 0 + }, + "allowedNumber": { + "type": "string", + "default": "" + }, + "maxSetupsPerMinute": { + "type": "integer", + "minimum": 0, + "maximum": 600, + "default": 0 } }, "required": [ @@ -5206,9 +5801,7 @@ }, "config": { "type": "object", - "additionalProperties": { - "nullable": true - } + "additionalProperties": {} }, "createdAt": { "type": "string" @@ -6470,9 +7063,7 @@ }, "components": { "type": "array", - "items": { - "nullable": true - } + "items": {} } }, "required": [ @@ -6675,6 +7266,510 @@ "from" ] }, + "ICEServer": { + "type": "object", + "properties": { + "urls": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + }, + "username": { + "type": "string" + }, + "credential": { + "type": "string" + } + }, + "required": [ + "urls" + ] + }, + "SDPAnswer": { + "type": "object", + "properties": { + "sdp": { + "type": "string" + }, + "iceServers": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ICEServer" + } + } + }, + "required": [ + "sdp", + "iceServers" + ] + }, + "VoipOfferResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/SDPAnswer" + } + }, + "required": [ + "success", + "data" + ] + }, + "VoipOfferRequest": { + "type": "object", + "properties": { + "sdp": { + "type": "string", + "minLength": 1 + } + }, + "required": [ + "sdp" + ] + }, + "VoipRenegotiateResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/SDPAnswer" + } + }, + "required": [ + "success", + "data" + ] + }, + "VoipRenegotiateRequest": { + "type": "object", + "properties": { + "sdp": { + "type": "string", + "minLength": 1 + } + }, + "required": [ + "sdp" + ] + }, + "VoipSocketTicket": { + "type": "object", + "properties": { + "ticket": { + "type": "string" + }, + "expiresAt": { + "type": "number" + }, + "url": { + "type": "string" + } + }, + "required": [ + "ticket", + "expiresAt", + "url" + ] + }, + "VoipSocketTicketResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/VoipSocketTicket" + } + }, + "required": [ + "success", + "data" + ] + }, + "VoipSocketTicketRequest": { + "type": "object", + "properties": { + "session": { + "type": "string", + "minLength": 1 + } + } + }, + "VoipAgentToken": { + "type": "object", + "properties": { + "token": { + "type": "string" + }, + "expiresAt": { + "type": "number" + } + }, + "required": [ + "token", + "expiresAt" + ] + }, + "VoipAgentTokenResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/VoipAgentToken" + } + }, + "required": [ + "success", + "data" + ] + }, + "VoipAgentTokenRequest": { + "type": "object", + "properties": { + "ttlSeconds": { + "type": "integer", + "minimum": 1, + "maximum": 3600 + } + } + }, + "VoipPlacedCall": { + "type": "object", + "properties": { + "callId": { + "type": "string" + }, + "session": { + "type": "string" + }, + "video": { + "type": "boolean" + } + }, + "required": [ + "callId", + "session", + "video" + ] + }, + "VoipPlacedCallResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/VoipPlacedCall" + } + }, + "required": [ + "success", + "data" + ] + }, + "VoipPlaceCallRequest": { + "type": "object", + "properties": { + "session": { + "type": "string", + "minLength": 1, + "example": "support" + }, + "to": { + "type": "string", + "minLength": 1, + "maxLength": 128, + "example": "+15550100" + }, + "video": { + "type": "boolean" + } + }, + "required": [ + "to" + ] + }, + "VoipAcceptCallRequest": { + "type": "object", + "properties": { + "video": { + "type": "boolean" + } + } + }, + "VoipParticipant": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "handle": { + "type": "string" + }, + "audioMuted": { + "type": "boolean" + }, + "video": { + "type": "boolean" + }, + "state": { + "type": "string", + "enum": [ + "invited", + "ringing", + "connected", + "left" + ] + } + }, + "required": [ + "id", + "handle", + "audioMuted", + "video", + "state" + ] + }, + "VoipAddParticipantResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/VoipParticipant" + } + }, + "required": [ + "success", + "data" + ] + }, + "VoipAddParticipantRequest": { + "type": "object", + "properties": { + "to": { + "type": "string", + "minLength": 1, + "maxLength": 128, + "example": "+15550100" + } + }, + "required": [ + "to" + ] + }, + "VoipModeResponse": { + "type": "object", + "properties": { + "session": { + "type": "string" + }, + "mode": { + "type": "string", + "enum": [ + "browser", + "agent", + "sdk" + ] + } + }, + "required": [ + "session", + "mode" + ] + }, + "VoipModeResult": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/VoipModeResponse" + } + }, + "required": [ + "success", + "data" + ] + }, + "VoipModeRequest": { + "type": "object", + "properties": { + "session": { + "type": "string", + "minLength": 1, + "example": "support" + }, + "mode": { + "type": "string", + "enum": [ + "browser", + "agent", + "sdk" + ] + } + }, + "required": [ + "mode" + ] + }, + "VoipCandidateRequest": { + "type": "object", + "properties": { + "candidate": { + "type": "string" + }, + "sdpMid": { + "type": "string" + }, + "sdpMLineIndex": { + "type": "integer" + } + }, + "required": [ + "candidate" + ] + }, + "TrickleCandidate": { + "type": "object", + "properties": { + "candidate": { + "type": "string" + }, + "sdpMid": { + "type": "string" + }, + "sdpMLineIndex": { + "type": "integer" + } + }, + "required": [ + "candidate" + ] + }, + "VoipCandidatesResponse": { + "type": "object", + "properties": { + "candidates": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TrickleCandidate" + } + } + }, + "required": [ + "candidates" + ] + }, + "VoipCandidatesEnvelope": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/VoipCandidatesResponse" + } + }, + "required": [ + "success", + "data" + ] + }, + "VoipToken": { + "type": "object", + "properties": { + "token": { + "type": "string" + }, + "expiresAt": { + "type": "number" + } + }, + "required": [ + "token", + "expiresAt" + ] + }, + "VoipTokenResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { + "$ref": "#/components/schemas/VoipToken" + } + }, + "required": [ + "success", + "data" + ] + }, + "VoipTokenRequest": { + "type": "object", + "properties": { + "session": { + "type": "string", + "minLength": 1 + }, + "ephemeralId": { + "type": "string", + "minLength": 1 + }, + "ttlSeconds": { + "type": "integer" + } + }, + "required": [ + "session", + "ephemeralId" + ] + }, "Participant": { "type": "object", "properties": { @@ -11640,17 +12735,11 @@ "kind": { "type": "string" }, - "definition": { - "nullable": true - }, - "sampleValues": { - "nullable": true - }, + "definition": {}, + "sampleValues": {}, "cloudLinks": { "type": "array", - "items": { - "nullable": true - } + "items": {} }, "createdAt": { "type": "number" @@ -11738,9 +12827,7 @@ }, "definition": { "type": "object", - "additionalProperties": { - "nullable": true - } + "additionalProperties": {} }, "sampleValues": { "type": "object", @@ -11784,9 +12871,7 @@ }, "definition": { "type": "object", - "additionalProperties": { - "nullable": true - } + "additionalProperties": {} }, "sampleValues": { "type": "object", @@ -11807,9 +12892,7 @@ }, "data": { "type": "object", - "additionalProperties": { - "nullable": true - } + "additionalProperties": {} } }, "required": [ @@ -11847,9 +12930,7 @@ }, "data": { "type": "object", - "additionalProperties": { - "nullable": true - } + "additionalProperties": {} } }, "required": [ @@ -11995,9 +13076,7 @@ }, "data": { "type": "object", - "additionalProperties": { - "nullable": true - } + "additionalProperties": {} } }, "required": [ @@ -12038,9 +13117,7 @@ }, "senderConfig": { "type": "object", - "additionalProperties": { - "nullable": true - } + "additionalProperties": {} }, "scheduledAt": { "type": "number" @@ -12160,9 +13237,7 @@ }, "data": { "type": "object", - "additionalProperties": { - "nullable": true - } + "additionalProperties": {} } }, "required": [ @@ -12178,30 +13253,34 @@ } } }, - "WidgetSessionResponse": { + "QuickLink": { "type": "object", "properties": { - "widgetUrl": { - "type": "string" - }, - "redirectUrl": { - "type": "string" + "id": { + "type": "string", + "description": "Stable QuickLink identifier, prefixed `ql_`." }, - "clientToken": { - "type": "string" + "url": { + "type": "string", + "description": "Hosted connection URL. Share it only with the person holding the phone." }, "session": { - "type": "string" + "type": "string", + "description": "Session name that receives the connected number." + }, + "expiresAt": { + "type": "string", + "description": "ISO-8601 expiry. QuickLinks live 15 minutes unless `expiresInSeconds` was set." } }, "required": [ - "widgetUrl", - "redirectUrl", - "clientToken", - "session" + "id", + "url", + "session", + "expiresAt" ] }, - "WidgetSessionResponseWrapper": { + "QuickLinkResponse": { "type": "object", "properties": { "success": { @@ -12211,7 +13290,7 @@ ] }, "data": { - "$ref": "#/components/schemas/WidgetSessionResponse" + "$ref": "#/components/schemas/QuickLink" } }, "required": [ @@ -12219,23 +13298,18 @@ "data" ] }, - "CreateWidgetSessionRequest": { + "CreateQuickLinkRequest": { "type": "object", "properties": { - "mode": { - "type": "string", - "enum": [ - "embedded", - "redirect" - ] - }, "projectId": { "type": "string", - "format": "uuid" + "format": "uuid", + "description": "Project that receives the connected number. Required for organization keys with more than one project." }, "customerId": { "type": "string", - "format": "uuid" + "format": "uuid", + "description": "Customer that owns the connected number when Customers is enabled for the project." }, "methods": { "type": "array", @@ -12243,44 +13317,33 @@ "type": "string", "enum": [ "qr", - "pairing", - "cloud-api" + "pairing" ] - } + }, + "minItems": 1, + "maxItems": 2, + "description": "Connection methods offered on the hosted page. Defaults to the saved settings, then to both." }, "businessName": { "type": "string", "minLength": 1, - "maxLength": 120 + "maxLength": 120, + "description": "Name shown to the recipient when no saved business name exists." }, "historySync": { "type": "string", "enum": [ + "ask", "force_on", - "force_off", - "ask" + "force_off" ] }, - "sessionName": { - "type": "string" - }, "callbackUrl": { "type": "string", "maxLength": 2048, "format": "uri", "pattern": "^[Hh][Tt][Tt][Pp][Ss]://", - "description": "Exact HTTPS URL without credentials." - }, - "allowedOrigins": { - "type": "array", - "items": { - "type": "string", - "maxLength": 2048, - "format": "uri", - "pattern": "^[Hh][Tt][Tt][Pp][Ss]://[^/?#@,]+/?$", - "description": "Exact HTTPS origin without credentials, path, query, fragment, or comma. A trailing root slash is removed." - }, - "maxItems": 50 + "description": "Exact HTTPS URL without credentials. Must match a saved redirect URL." }, "theme": { "type": "string", @@ -12296,92 +13359,282 @@ }, "prefillPhone": { "type": "string", - "pattern": "^\\+?\\d{6,15}$" - }, - "autoSubmitPhone": { - "type": "boolean" + "pattern": "^\\+?\\d{6,15}$", + "description": "Pre-fills the phone number for the pairing-code method." }, - "analytics": { - "type": "object", - "properties": { - "posthogKey": { - "type": "string" - }, - "posthogHost": { - "type": "string" - } - }, - "required": [ - "posthogKey" - ] - }, - "metaApp": { - "type": "object", - "properties": { - "appId": { - "type": "string", - "minLength": 1 - }, - "appSecret": { - "type": "string", - "minLength": 1 - } - }, - "required": [ - "appId", - "appSecret" - ] + "expiresInSeconds": { + "type": "integer", + "minimum": 300, + "maximum": 3600, + "description": "Link lifetime in seconds, 300–3600. Defaults to 900." } } }, - "WidgetHandoffResponse": { + "QuickLinkStatus": { "type": "object", "properties": { - "handoffUrl": { + "id": { "type": "string" }, - "metaQrSvg": { + "status": { + "type": "string", + "enum": [ + "pending", + "opened", + "linked", + "connected", + "failed", + "cancelled" + ] + }, + "session": { "type": "string" }, "expiresAt": { "type": "string" + }, + "openedAt": { + "type": "string", + "nullable": true + }, + "connectedAt": { + "type": "string", + "nullable": true + }, + "phone": { + "type": "string", + "nullable": true, + "description": "Connected phone in E.164 once the link is connected." + }, + "errorCode": { + "type": "string", + "nullable": true } }, "required": [ - "handoffUrl", - "metaQrSvg", - "expiresAt" + "id", + "status", + "session", + "expiresAt", + "openedAt", + "connectedAt", + "phone", + "errorCode" ] }, - "WidgetHandoffState": { + "QuickLinkStatusResponse": { "type": "object", "properties": { - "qr": { - "type": "string", - "nullable": true + "success": { + "type": "boolean", + "enum": [ + true + ] }, - "status": { + "data": { + "$ref": "#/components/schemas/QuickLinkStatus" + } + }, + "required": [ + "success", + "data" + ] + }, + "QuickLinkState": { + "type": "object", + "properties": { + "id": { "type": "string" }, - "sessionName": { + "status": { + "type": "string", + "enum": [ + "pending", + "opened", + "linked", + "connected", + "failed", + "cancelled" + ] + }, + "expiresAt": { "type": "string" }, + "methods": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "qr", + "pairing" + ] + } + }, + "defaultMethod": { + "type": "string", + "nullable": true, + "enum": [ + "qr", + "pairing", + null + ] + }, "businessName": { "type": "string" + }, + "headline": { + "type": "string", + "nullable": true + }, + "description": { + "type": "string", + "nullable": true + }, + "successMessage": { + "type": "string", + "nullable": true + }, + "supportUrl": { + "type": "string", + "nullable": true + }, + "privacyUrl": { + "type": "string", + "nullable": true + }, + "termsUrl": { + "type": "string", + "nullable": true + }, + "theme": { + "type": "string", + "enum": [ + "light", + "dark", + "system" + ] + }, + "accent": { + "type": "string", + "nullable": true + }, + "shape": { + "type": "string", + "nullable": true, + "enum": [ + "square", + "rounded", + "pill", + null + ] + }, + "radiusPx": { + "type": "number", + "nullable": true + }, + "logoUrl": { + "type": "string", + "nullable": true + }, + "hideWatermark": { + "type": "boolean" + }, + "historySync": { + "type": "string", + "enum": [ + "ask", + "force_on", + "force_off" + ] + }, + "prefillPhone": { + "type": "string", + "nullable": true + }, + "customer": { + "type": "boolean", + "description": "True when the link assigns the number to a Customer." + }, + "session": { + "type": "object", + "properties": { + "status": { + "type": "string" + }, + "phone": { + "type": "string", + "nullable": true + } + }, + "required": [ + "status", + "phone" + ] + }, + "qrSvg": { + "type": "string", + "nullable": true, + "description": "Inline SVG of the current WhatsApp QR code, when the QR method is offered and the number is not linked yet." + }, + "errorCode": { + "type": "string", + "nullable": true } }, "required": [ - "qr", + "id", "status", - "sessionName" + "expiresAt", + "methods", + "defaultMethod", + "businessName", + "headline", + "description", + "successMessage", + "supportUrl", + "privacyUrl", + "termsUrl", + "theme", + "accent", + "shape", + "radiusPx", + "logoUrl", + "hideWatermark", + "historySync", + "prefillPhone", + "customer", + "session", + "qrSvg", + "errorCode" + ] + }, + "QuickLinkCodeRequest": { + "type": "object", + "properties": { + "phone": { + "type": "string", + "minLength": 6, + "maxLength": 20 + } + }, + "required": [ + "phone" ] + }, + "QuickLinkConfirmRequest": { + "type": "object", + "properties": { + "historySync": { + "type": "boolean" + } + } } }, "securitySchemes": { "BearerAuth": { "type": "http", "scheme": "bearer", - "description": "Polymorfa API key (pmfa_ prefix) or client token (pmfa_ct_ prefix)." + "description": "Polymorfa organization key (pmfa_ prefix), project token (pmfa_pt_ prefix) where supported, or short-lived client token (pmfa_ct_ prefix). Organization and project keys may be personal or service-account owned and enforce selected action scopes. Organization keys cover the team and its projects; project tokens stay inside one project. Client tokens stay inside their live project and session and enforce their client rules." } } }, @@ -12613,7 +13866,15 @@ "BearerAuth": [] } ], - "x-required-scope": "sessions:manage", + "x-required-scopes": [ + "sessions:manage", + "messages:write", + "contacts:read", + "presence:read", + "presence:observe", + "mcp" + ], + "x-required-scope-mode": "all", "requestBody": { "content": { "application/json": { @@ -12686,9 +13947,9 @@ } }, "x-mint": { - "content": "sessions:manage" + "content": "sessions:manage messages:write contacts:read presence:read presence:observe mcp" }, - "description": "**Required scope:** `sessions:manage`" + "description": "**Required scopes (all):** `sessions:manage` · `messages:write` · `contacts:read` · `presence:read` · `presence:observe` · `mcp`" } }, "/api/sessions/{session}/client-rules": { @@ -12792,7 +14053,15 @@ "BearerAuth": [] } ], - "x-required-scope": "sessions:manage", + "x-required-scopes": [ + "sessions:manage", + "messages:write", + "contacts:read", + "presence:read", + "presence:observe", + "mcp" + ], + "x-required-scope-mode": "all", "parameters": [ { "schema": { @@ -12875,9 +14144,9 @@ } }, "x-mint": { - "content": "sessions:manage" + "content": "sessions:manage messages:write contacts:read presence:read presence:observe mcp" }, - "description": "**Required scope:** `sessions:manage`" + "description": "**Required scopes (all):** `sessions:manage` · `messages:write` · `contacts:read` · `presence:read` · `presence:observe` · `mcp`" }, "delete": { "operationId": "deleteClientRules", @@ -15796,6 +17065,1605 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `chats:manage`" } }, + "/api/voip/calls/{id}/offer": { + "post": { + "operationId": "voipOffer", + "tags": [ + "VoIP" + ], + "summary": "Submit an SDP offer and receive the pod's answer + ICE servers", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "sessions:manage", + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "example": "call-123" + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoipOfferRequest" + } + } + } + }, + "responses": { + "200": { + "description": "SDP answer with STUN/TURN ICE servers", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoipOfferResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "409": { + "description": "Call not ready — no media session on the owning pod yet", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "410": { + "description": "Call ended — the pod that owned its media is gone (pod_lost)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "429": { + "description": "Call setup rate exceeded for this client token, or its concurrency limit is reached", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "503": { + "description": "Call unavailable — the owning pod is at capacity or draining, or call authority cannot be verified", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "sessions:manage" + }, + "description": "**Required scope:** `sessions:manage`" + } + }, + "/api/voip/calls/{id}/renegotiate": { + "post": { + "operationId": "voipRenegotiate", + "tags": [ + "VoIP" + ], + "summary": "Re-offer on an established call (add video, restart ICE) and receive the pod's answer", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "sessions:manage", + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "example": "call-123" + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoipRenegotiateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "SDP answer for the re-offer, on the same peer connection", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoipRenegotiateResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "409": { + "description": "Call not ready — no media session on the owning pod yet", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "410": { + "description": "Call ended — the pod that owned its media is gone (pod_lost)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "503": { + "description": "Call unavailable — the owning pod is at capacity or draining, or call authority cannot be verified", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "sessions:manage" + }, + "description": "**Required scope:** `sessions:manage`" + } + }, + "/api/voip/ws-ticket": { + "post": { + "operationId": "voipSocketTicket", + "tags": [ + "VoIP" + ], + "summary": "Mint a single-use ticket for the calls WebSocket", + "description": "**Required scope:** `sessions:manage`\n\nBrowsers cannot send an Authorization header on a WebSocket upgrade, so the calls socket (`GET /voip/ws?ticket=…`) is opened with a ticket obtained here. Tickets are single-use and expire after 60 seconds. Client tokens are bound to their session; server keys must name one.", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "sessions:manage", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoipSocketTicketRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Ticket minted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoipSocketTicketResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "sessions:manage" + } + } + }, + "/api/voip/calls/{id}/agent-token": { + "post": { + "operationId": "voipAgentToken", + "tags": [ + "VoIP" + ], + "summary": "Mint a per-call ticket for a voice agent's media WebSocket", + "description": "**Required scope:** `sessions:manage`\n\nServer keys only. The ticket is bound to this call, expires after `ttlSeconds` (default 300, max 3600) and is presented by the agent to the voip pod as `Authorization: Bearer `. It grants nothing else.", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "sessions:manage", + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "example": "call-123" + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoipAgentTokenRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Agent ticket minted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoipAgentTokenResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "409": { + "description": "Call not ready — no media session on the owning pod yet", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "410": { + "description": "Call ended — the pod that owned its media is gone (pod_lost)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "503": { + "description": "Call unavailable — the owning pod is at capacity or draining, or call authority cannot be verified", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "sessions:manage" + } + } + }, + "/api/voip/calls": { + "post": { + "operationId": "voipPlaceCall", + "tags": [ + "VoIP" + ], + "summary": "Place an outbound call from a session", + "description": "**Required scope:** `sessions:manage`\n\nOriginates a WhatsApp call to `to` (an E.164 phone number or a WhatsApp JID) from the named session. The call rings on the callee's device: `call.accepted` follows when they pick up and `call.ended` when either side hangs up. Attach media like any other call — `/offer` for a browser, the SDK media socket for programmatic audio/video. Client tokens place from their bound session; server keys must name one. Outbound starts share a rate limit per organization and source session across server keys and client tokens; client-token rules also apply.", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "sessions:manage", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoipPlaceCallRequest" + } + } + } + }, + "responses": { + "201": { + "description": "Call placed and ringing", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoipPlacedCallResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "409": { + "description": "Session not ready — the named session cannot place an outbound call yet", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "410": { + "description": "Call ended — the pod that owned its media is gone (pod_lost)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "429": { + "description": "Outbound call rate exceeded for this organization and source session, or a client-token setup or concurrency limit was reached", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "501": { + "description": "Outbound calls are not available on this deployment", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "503": { + "description": "Call unavailable — the owning pod is at capacity or draining, or call authority cannot be verified", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "sessions:manage" + } + } + }, + "/api/voip/calls/{id}/accept": { + "post": { + "operationId": "voipAcceptCall", + "tags": [ + "VoIP" + ], + "summary": "Answer a ringing inbound call", + "description": "**Required scope:** `sessions:manage`\n\nAnswers a call the pod is holding for the SDK (sessions in `sdk` client mode ring instead of auto-answering). 409 when the call is not ringing — already answered, ended, or hosted by a session that auto-answers.", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "sessions:manage", + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "example": "call-123" + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoipAcceptCallRequest" + } + } + } + }, + "responses": { + "202": { + "description": "Call answered", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "409": { + "description": "Call not ready — no media session on the owning pod yet", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "410": { + "description": "Call ended — the pod that owned its media is gone (pod_lost)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "503": { + "description": "Call unavailable — the owning pod is at capacity or draining, or call authority cannot be verified", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "sessions:manage" + } + } + }, + "/api/voip/calls/{id}/reject": { + "post": { + "operationId": "voipRejectCall", + "tags": [ + "VoIP" + ], + "summary": "Decline a ringing inbound call", + "description": "**Required scope:** `sessions:manage`\n\nDeclines a call the pod is holding for the SDK and releases it. 409 when the call is not ringing.", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "sessions:manage", + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "example": "call-123" + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "responses": { + "202": { + "description": "Call declined", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "409": { + "description": "Call not ready — no media session on the owning pod yet", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "410": { + "description": "Call ended — the pod that owned its media is gone (pod_lost)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "503": { + "description": "Call unavailable — the owning pod is at capacity or draining, or call authority cannot be verified", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "sessions:manage" + } + } + }, + "/api/voip/calls/{id}/participants": { + "post": { + "operationId": "voipAddParticipant", + "tags": [ + "VoIP" + ], + "summary": "Invite another party into a live call", + "description": "**Required scope:** `sessions:manage`\n\nRings `to` (an E.164 phone number or a WhatsApp JID) into the call, turning a 1:1 call into a group call. The invitee enters the roster as `invited`; roster changes reach the SDK media socket as `participant_joined` / `participant_state` / `participant_left` frames. 409 until the call has a live leg.", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "sessions:manage", + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "example": "call-123" + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoipAddParticipantRequest" + } + } + } + }, + "responses": { + "201": { + "description": "Participant invited", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoipAddParticipantResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "409": { + "description": "Call not ready — no media session on the owning pod yet", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "410": { + "description": "Call ended — the pod that owned its media is gone (pod_lost)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "429": { + "description": "Call setup rate exceeded for this client token, or its concurrency limit is reached", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "503": { + "description": "Call unavailable — the owning pod is at capacity or draining, or call authority cannot be verified", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "sessions:manage" + } + } + }, + "/api/voip/mode": { + "post": { + "operationId": "voipSetMode", + "tags": [ + "VoIP" + ], + "summary": "Choose how a session answers inbound calls", + "description": "**Required scope:** `sessions:manage`\n\n`browser` (default) answers each inbound call and bridges it to a browser through `/offer`; `agent` answers and bridges to the raw-audio socket; `sdk` lets the call ring and waits for your `/accept` or `/reject`. The claim persists until changed and applies to calls that arrive after it. Client tokens configure their bound session; server keys must name one.", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "sessions:manage", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoipModeRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Mode recorded", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoipModeResult" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "sessions:manage" + } + } + }, + "/api/voip/calls/{id}/candidate": { + "post": { + "operationId": "voipCandidate", + "tags": [ + "VoIP" + ], + "summary": "Trickle a local ICE candidate to the owning pod", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "sessions:manage", + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "example": "call-123" + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoipCandidateRequest" + } + } + } + }, + "responses": { + "202": { + "description": "Candidate accepted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "409": { + "description": "Call not ready — no media session on the owning pod yet", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "410": { + "description": "Call ended — the pod that owned its media is gone (pod_lost)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "503": { + "description": "Call unavailable — the owning pod is at capacity or draining, or call authority cannot be verified", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "sessions:manage" + }, + "description": "**Required scope:** `sessions:manage`" + } + }, + "/api/voip/calls/{id}/candidates": { + "get": { + "operationId": "voipCandidates", + "tags": [ + "VoIP" + ], + "summary": "Poll remote ICE candidates queued for the browser", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "sessions:manage", + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "example": "call-123" + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Queued remote candidates (drained on read)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoipCandidatesEnvelope" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "409": { + "description": "Call not ready — no media session on the owning pod yet", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "410": { + "description": "Call ended — the pod that owned its media is gone (pod_lost)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "503": { + "description": "Call unavailable — the owning pod is at capacity or draining, or call authority cannot be verified", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "sessions:manage" + }, + "description": "**Required scope:** `sessions:manage`" + } + }, + "/api/voip/calls/{id}": { + "delete": { + "operationId": "voipTeardown", + "tags": [ + "VoIP" + ], + "summary": "Tear down a call's browser media session", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "sessions:manage", + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "example": "call-123" + }, + "required": true, + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Call torn down", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "409": { + "description": "Call not ready — no media session on the owning pod yet", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "410": { + "description": "Call ended — the pod that owned its media is gone (pod_lost)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "503": { + "description": "Call unavailable — the owning pod is at capacity or draining, or call authority cannot be verified", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "sessions:manage" + }, + "description": "**Required scope:** `sessions:manage`" + } + }, + "/api/voip/token": { + "post": { + "operationId": "voipToken", + "tags": [ + "VoIP" + ], + "summary": "Mint a short-lived browser client token for the VoIP SDK", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scopes": [ + "sessions:manage", + "messages:write", + "contacts:read", + "presence:read", + "presence:observe", + "mcp" + ], + "x-required-scope-mode": "all", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoipTokenRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Client token minted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoipTokenResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "sessions:manage messages:write contacts:read presence:read presence:observe mcp" + }, + "description": "**Required scopes (all):** `sessions:manage` · `messages:write` · `contacts:read` · `presence:read` · `presence:observe` · `mcp`" + } + }, "/api/{session}/groups": { "get": { "operationId": "listGroups", @@ -26080,27 +28948,428 @@ } }, "x-mint": { - "content": "Linked Device API profile:read" + "content": "Linked Device API profile:read" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:read`" + } + }, + "/api/{session}/profile/name": { + "put": { + "operationId": "setProfileName", + "tags": [ + "Profile" + ], + "summary": "Set profile display name (push name)", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "profile:write", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SetProfileNameRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Name updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API profile:write" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:write`" + } + }, + "/api/{session}/profile/status": { + "put": { + "operationId": "setProfileStatus", + "tags": [ + "Profile" + ], + "summary": "Set profile status (about) text", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "profile:write", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SetProfileStatusRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Status updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API profile:write" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:write`" + } + }, + "/api/{session}/profile/picture": { + "put": { + "operationId": "setProfilePicture", + "tags": [ + "Profile" + ], + "summary": "Set profile picture", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "profile:write", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SetProfilePictureRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Picture updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API profile:write" + }, + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:write`" + }, + "delete": { + "operationId": "deleteProfilePicture", + "tags": [ + "Profile" + ], + "summary": "Remove the profile picture", + "security": [ + { + "BearerAuth": [] + } + ], + "x-required-scope": "profile:write", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "session", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Picture deleted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "Linked Device API profile:write" }, "x-protocols": [ "Linked Device API" ], - "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:read`" + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:write`" } }, - "/api/{session}/profile/name": { - "put": { - "operationId": "setProfileName", + "/api/{session}/privacy": { + "get": { + "operationId": "getPrivacySettings", "tags": [ - "Profile" + "Privacy" ], - "summary": "Set profile display name (push name)", + "summary": "Get privacy settings", "security": [ { "BearerAuth": [] } ], - "x-required-scope": "profile:write", + "x-required-scope": "profile:read", "parameters": [ { "schema": { @@ -26111,22 +29380,13 @@ "in": "path" } ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SetProfileNameRequest" - } - } - } - }, "responses": { "200": { - "description": "Name updated", + "description": "Privacy settings", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SuccessResponse" + "$ref": "#/components/schemas/PrivacySettingsResponse" } } } @@ -26183,21 +29443,21 @@ } }, "x-mint": { - "content": "Linked Device API profile:write" + "content": "Linked Device API profile:read" }, "x-protocols": [ "Linked Device API" ], - "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:write`" + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:read`" } }, - "/api/{session}/profile/status": { + "/api/{session}/privacy/disappearing/default": { "put": { - "operationId": "setProfileStatus", + "operationId": "setDefaultDisappearingTimer", "tags": [ - "Profile" + "Privacy" ], - "summary": "Set profile status (about) text", + "summary": "Set the default disappearing-message timer", "security": [ { "BearerAuth": [] @@ -26218,14 +29478,14 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SetProfileStatusRequest" + "$ref": "#/components/schemas/DefaultDisappearingTimerRequest" } } } }, "responses": { "200": { - "description": "Status updated", + "description": "Default disappearing-message timer updated", "content": { "application/json": { "schema": { @@ -26294,13 +29554,13 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:write`" } }, - "/api/{session}/profile/picture": { + "/api/{session}/privacy/{setting}": { "put": { - "operationId": "setProfilePicture", + "operationId": "setPrivacySetting", "tags": [ - "Profile" + "Privacy" ], - "summary": "Set profile picture", + "summary": "Update a privacy setting", "security": [ { "BearerAuth": [] @@ -26315,24 +29575,44 @@ "required": true, "name": "session", "in": "path" + }, + { + "schema": { + "type": "string", + "enum": [ + "groupadd", + "last", + "status", + "profile", + "readreceipts", + "online", + "calladd", + "messages", + "defense", + "stickers" + ] + }, + "required": true, + "name": "setting", + "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SetProfilePictureRequest" + "$ref": "#/components/schemas/SetPrivacySettingRequest" } } } }, "responses": { "200": { - "description": "Picture updated", + "description": "Updated privacy settings", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SuccessResponse" + "$ref": "#/components/schemas/UpdatedPrivacySettingsResponse" } } } @@ -26395,19 +29675,21 @@ "Linked Device API" ], "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:write`" - }, - "delete": { - "operationId": "deleteProfilePicture", + } + }, + "/api/{session}/labels": { + "get": { + "operationId": "listLabels", "tags": [ - "Profile" + "Labels" ], - "summary": "Remove the profile picture", + "summary": "List labels defined for the session", "security": [ { "BearerAuth": [] } ], - "x-required-scope": "profile:write", + "x-required-scope": "labels:read", "parameters": [ { "schema": { @@ -26416,15 +29698,27 @@ "required": true, "name": "session", "in": "path" + }, + { + "schema": { + "type": "string", + "enum": [ + "true", + "false" + ] + }, + "required": false, + "name": "includeObservation", + "in": "query" } ], "responses": { "200": { - "description": "Picture deleted", + "description": "Label list", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SuccessResponse" + "$ref": "#/components/schemas/ListLabelsResponse" } } } @@ -26481,27 +29775,25 @@ } }, "x-mint": { - "content": "Linked Device API profile:write" + "content": "Linked Device API labels:read" }, "x-protocols": [ "Linked Device API" ], - "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:write`" - } - }, - "/api/{session}/privacy": { - "get": { - "operationId": "getPrivacySettings", + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `labels:read`" + }, + "post": { + "operationId": "createLabel", "tags": [ - "Privacy" + "Labels" ], - "summary": "Get privacy settings", + "summary": "Create a label", "security": [ { "BearerAuth": [] } ], - "x-required-scope": "profile:read", + "x-required-scope": "labels:manage", "parameters": [ { "schema": { @@ -26512,13 +29804,22 @@ "in": "path" } ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateLabelRequest" + } + } + } + }, "responses": { "200": { - "description": "Privacy settings", + "description": "Label created", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/PrivacySettingsResponse" + "$ref": "#/components/schemas/CreateLabelResponse" } } } @@ -26575,27 +29876,27 @@ } }, "x-mint": { - "content": "Linked Device API profile:read" + "content": "Linked Device API labels:manage" }, "x-protocols": [ "Linked Device API" ], - "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:read`" + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `labels:manage`" } }, - "/api/{session}/privacy/disappearing/default": { + "/api/{session}/labels/{labelId}": { "put": { - "operationId": "setDefaultDisappearingTimer", + "operationId": "updateLabel", "tags": [ - "Privacy" + "Labels" ], - "summary": "Set the default disappearing-message timer", + "summary": "Update a label", "security": [ { "BearerAuth": [] } ], - "x-required-scope": "profile:write", + "x-required-scope": "labels:manage", "parameters": [ { "schema": { @@ -26604,20 +29905,28 @@ "required": true, "name": "session", "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "labelId", + "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DefaultDisappearingTimerRequest" + "$ref": "#/components/schemas/UpdateLabelRequest" } } } }, "responses": { "200": { - "description": "Default disappearing-message timer updated", + "description": "Label updated", "content": { "application/json": { "schema": { @@ -26666,6 +29975,16 @@ } } }, + "409": { + "description": "The session has no authoritative view of its labels yet. Retry once a cached or project-retained snapshot is complete.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, "500": { "description": "Internal server error", "content": { @@ -26678,27 +29997,25 @@ } }, "x-mint": { - "content": "Linked Device API profile:write" + "content": "Linked Device API labels:manage" }, "x-protocols": [ "Linked Device API" ], - "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:write`" - } - }, - "/api/{session}/privacy/{setting}": { - "put": { - "operationId": "setPrivacySetting", + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `labels:manage`" + }, + "delete": { + "operationId": "deleteLabel", "tags": [ - "Privacy" + "Labels" ], - "summary": "Update a privacy setting", + "summary": "Delete a label", "security": [ { "BearerAuth": [] } ], - "x-required-scope": "profile:write", + "x-required-scope": "labels:manage", "parameters": [ { "schema": { @@ -26710,41 +30027,20 @@ }, { "schema": { - "type": "string", - "enum": [ - "groupadd", - "last", - "status", - "profile", - "readreceipts", - "online", - "calladd", - "messages", - "defense", - "stickers" - ] + "type": "string" }, "required": true, - "name": "setting", + "name": "labelId", "in": "path" } ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SetPrivacySettingRequest" - } - } - } - }, "responses": { "200": { - "description": "Updated privacy settings", + "description": "Label deleted", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/UpdatedPrivacySettingsResponse" + "$ref": "#/components/schemas/SuccessResponse" } } } @@ -26801,21 +30097,21 @@ } }, "x-mint": { - "content": "Linked Device API profile:write" + "content": "Linked Device API labels:manage" }, "x-protocols": [ "Linked Device API" ], - "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:write`" + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `labels:manage`" } }, - "/api/{session}/labels": { + "/api/{session}/labels/chats/{chatId}": { "get": { - "operationId": "listLabels", + "operationId": "getChatLabels", "tags": [ "Labels" ], - "summary": "List labels defined for the session", + "summary": "Get labels attached to a chat", "security": [ { "BearerAuth": [] @@ -26831,6 +30127,14 @@ "name": "session", "in": "path" }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "chatId", + "in": "path" + }, { "schema": { "type": "string", @@ -26846,11 +30150,11 @@ ], "responses": { "200": { - "description": "Label list", + "description": "Chat labels", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ListLabelsResponse" + "$ref": "#/components/schemas/GetChatLabelsResponse" } } } @@ -26914,12 +30218,12 @@ ], "description": "**Protocols:** Linked Device API\n\n**Required scope:** `labels:read`" }, - "post": { - "operationId": "createLabel", + "put": { + "operationId": "setChatLabels", "tags": [ "Labels" ], - "summary": "Create a label", + "summary": "Replace the set of labels attached to a chat", "security": [ { "BearerAuth": [] @@ -26934,24 +30238,32 @@ "required": true, "name": "session", "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "chatId", + "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/CreateLabelRequest" + "$ref": "#/components/schemas/SetChatLabelsRequest" } } } }, "responses": { "200": { - "description": "Label created", + "description": "Chat labels updated", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/CreateLabelResponse" + "$ref": "#/components/schemas/SuccessResponse" } } } @@ -26996,6 +30308,16 @@ } } }, + "409": { + "description": "The session has no authoritative view of its labels yet. Retry once a cached or project-retained snapshot is complete.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, "500": { "description": "Internal server error", "content": { @@ -27016,53 +30338,26 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `labels:manage`" } }, - "/api/{session}/labels/{labelId}": { - "put": { - "operationId": "updateLabel", + "/api/webhooks": { + "get": { + "operationId": "listWebhooks", "tags": [ - "Labels" + "Webhooks" ], - "summary": "Update a label", + "summary": "List webhooks for the tenant", "security": [ { "BearerAuth": [] } ], - "x-required-scope": "labels:manage", - "parameters": [ - { - "schema": { - "type": "string" - }, - "required": true, - "name": "session", - "in": "path" - }, - { - "schema": { - "type": "string" - }, - "required": true, - "name": "labelId", - "in": "path" - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UpdateLabelRequest" - } - } - } - }, + "x-required-scope": "webhooks:manage", "responses": { "200": { - "description": "Label updated", + "description": "Webhook list", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SuccessResponse" + "$ref": "#/components/schemas/ListWebhooksResponse" } } } @@ -27107,16 +30402,6 @@ } } }, - "409": { - "description": "The session has no authoritative view of its labels yet. Retry once a cached or project-retained snapshot is complete.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, "500": { "description": "Internal server error", "content": { @@ -27129,50 +30414,38 @@ } }, "x-mint": { - "content": "Linked Device API labels:manage" + "content": "webhooks:manage" }, - "x-protocols": [ - "Linked Device API" - ], - "description": "**Protocols:** Linked Device API\n\n**Required scope:** `labels:manage`" + "description": "**Required scope:** `webhooks:manage`" }, - "delete": { - "operationId": "deleteLabel", + "post": { + "operationId": "createWebhook", "tags": [ - "Labels" + "Webhooks" ], - "summary": "Delete a label", + "summary": "Register a new webhook", "security": [ { "BearerAuth": [] } ], - "x-required-scope": "labels:manage", - "parameters": [ - { - "schema": { - "type": "string" - }, - "required": true, - "name": "session", - "in": "path" - }, - { - "schema": { - "type": "string" - }, - "required": true, - "name": "labelId", - "in": "path" + "x-required-scope": "webhooks:manage", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateWebhookRequest" + } + } } - ], + }, "responses": { - "200": { - "description": "Label deleted", + "201": { + "description": "Webhook created", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SuccessResponse" + "$ref": "#/components/schemas/CreateWebhookResponse" } } } @@ -27229,64 +30502,41 @@ } }, "x-mint": { - "content": "Linked Device API labels:manage" + "content": "webhooks:manage" }, - "x-protocols": [ - "Linked Device API" - ], - "description": "**Protocols:** Linked Device API\n\n**Required scope:** `labels:manage`" + "description": "**Required scope:** `webhooks:manage`" } }, - "/api/{session}/labels/chats/{chatId}": { + "/api/webhooks/{id}": { "get": { - "operationId": "getChatLabels", + "operationId": "getWebhook", "tags": [ - "Labels" + "Webhooks" ], - "summary": "Get labels attached to a chat", + "summary": "Get a webhook by id", "security": [ { "BearerAuth": [] } ], - "x-required-scope": "labels:read", + "x-required-scope": "webhooks:manage", "parameters": [ { "schema": { "type": "string" }, "required": true, - "name": "session", - "in": "path" - }, - { - "schema": { - "type": "string" - }, - "required": true, - "name": "chatId", + "name": "id", "in": "path" - }, - { - "schema": { - "type": "string", - "enum": [ - "true", - "false" - ] - }, - "required": false, - "name": "includeObservation", - "in": "query" } ], "responses": { "200": { - "description": "Chat labels", + "description": "Webhook details", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/GetChatLabelsResponse" + "$ref": "#/components/schemas/GetWebhookResponse" } } } @@ -27343,40 +30593,29 @@ } }, "x-mint": { - "content": "Linked Device API labels:read" + "content": "webhooks:manage" }, - "x-protocols": [ - "Linked Device API" - ], - "description": "**Protocols:** Linked Device API\n\n**Required scope:** `labels:read`" + "description": "**Required scope:** `webhooks:manage`" }, "put": { - "operationId": "setChatLabels", + "operationId": "updateWebhook", "tags": [ - "Labels" + "Webhooks" ], - "summary": "Replace the set of labels attached to a chat", + "summary": "Update a webhook", "security": [ { "BearerAuth": [] } ], - "x-required-scope": "labels:manage", + "x-required-scope": "webhooks:manage", "parameters": [ { "schema": { "type": "string" }, "required": true, - "name": "session", - "in": "path" - }, - { - "schema": { - "type": "string" - }, - "required": true, - "name": "chatId", + "name": "id", "in": "path" } ], @@ -27384,18 +30623,18 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SetChatLabelsRequest" + "$ref": "#/components/schemas/UpdateWebhookRequest" } } } }, "responses": { "200": { - "description": "Chat labels updated", + "description": "Webhook updated", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SuccessResponse" + "$ref": "#/components/schemas/UpdateWebhookResponse" } } } @@ -27440,16 +30679,6 @@ } } }, - "409": { - "description": "The session has no authoritative view of its labels yet. Retry once a cached or project-retained snapshot is complete.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, "500": { "description": "Internal server error", "content": { @@ -27462,34 +30691,39 @@ } }, "x-mint": { - "content": "Linked Device API labels:manage" + "content": "webhooks:manage" }, - "x-protocols": [ - "Linked Device API" - ], - "description": "**Protocols:** Linked Device API\n\n**Required scope:** `labels:manage`" - } - }, - "/api/webhooks": { - "get": { - "operationId": "listWebhooks", + "description": "**Required scope:** `webhooks:manage`" + }, + "delete": { + "operationId": "deleteWebhook", "tags": [ "Webhooks" ], - "summary": "List webhooks for the tenant", + "summary": "Delete a webhook", "security": [ { "BearerAuth": [] } ], "x-required-scope": "webhooks:manage", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "id", + "in": "path" + } + ], "responses": { "200": { - "description": "Webhook list", + "description": "Webhook deleted", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ListWebhooksResponse" + "$ref": "#/components/schemas/SuccessResponse" } } } @@ -27549,38 +30783,37 @@ "content": "webhooks:manage" }, "description": "**Required scope:** `webhooks:manage`" - }, - "post": { - "operationId": "createWebhook", + } + }, + "/api/media/{id}": { + "get": { + "operationId": "downloadMedia", "tags": [ - "Webhooks" + "Media" ], - "summary": "Register a new webhook", + "summary": "Download media (binary stream or redirect to S3)", "security": [ { "BearerAuth": [] } ], - "x-required-scope": "webhooks:manage", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateWebhookRequest" - } - } + "x-required-scope": "media:read", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "id", + "in": "path" } - }, + ], "responses": { - "201": { - "description": "Webhook created", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateWebhookResponse" - } - } - } + "200": { + "description": "Media binary stream" + }, + "302": { + "description": "Redirect to S3" }, "400": { "description": "Bad request — request body or params failed validation", @@ -27634,24 +30867,27 @@ } }, "x-mint": { - "content": "webhooks:manage" + "content": "Linked Device API media:read" }, - "description": "**Required scope:** `webhooks:manage`" + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `media:read`" } }, - "/api/webhooks/{id}": { + "/api/media/{id}/info": { "get": { - "operationId": "getWebhook", + "operationId": "getMediaInfo", "tags": [ - "Webhooks" + "Media" ], - "summary": "Get a webhook by id", + "summary": "Get media metadata", "security": [ { "BearerAuth": [] } ], - "x-required-scope": "webhooks:manage", + "x-required-scope": "media:read", "parameters": [ { "schema": { @@ -27664,11 +30900,11 @@ ], "responses": { "200": { - "description": "Webhook details", + "description": "Media info", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/GetWebhookResponse" + "$ref": "#/components/schemas/GetMediaInfoResponse" } } } @@ -27725,22 +30961,27 @@ } }, "x-mint": { - "content": "webhooks:manage" + "content": "Linked Device API media:read" }, - "description": "**Required scope:** `webhooks:manage`" - }, - "put": { - "operationId": "updateWebhook", + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `media:read`" + } + }, + "/api/media/{id}/download-and-save": { + "post": { + "operationId": "downloadAndSaveMedia", "tags": [ - "Webhooks" + "Media" ], - "summary": "Update a webhook", + "summary": "Download media and persist it to the tenant's S3 bucket", "security": [ { "BearerAuth": [] } ], - "x-required-scope": "webhooks:manage", + "x-required-scope": "media:manage", "parameters": [ { "schema": { @@ -27751,22 +30992,13 @@ "in": "path" } ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UpdateWebhookRequest" - } - } - } - }, "responses": { "200": { - "description": "Webhook updated", + "description": "Persistence queued or already persisted", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/UpdateWebhookResponse" + "$ref": "#/components/schemas/SuccessResponse" } } } @@ -27823,39 +31055,44 @@ } }, "x-mint": { - "content": "webhooks:manage" + "content": "Linked Device API media:manage" }, - "description": "**Required scope:** `webhooks:manage`" - }, - "delete": { - "operationId": "deleteWebhook", + "x-protocols": [ + "Linked Device API" + ], + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `media:manage`" + } + }, + "/api/projects/{projectSlug}/templates": { + "get": { + "operationId": "listProjectTemplates", "tags": [ - "Webhooks" + "Templates" ], - "summary": "Delete a webhook", + "summary": "List project message templates", "security": [ { "BearerAuth": [] } ], - "x-required-scope": "webhooks:manage", + "x-required-scope": "templates:read", "parameters": [ { "schema": { "type": "string" }, "required": true, - "name": "id", + "name": "projectSlug", "in": "path" } ], "responses": { "200": { - "description": "Webhook deleted", + "description": "Templates", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SuccessResponse" + "$ref": "#/components/schemas/ListProjectTemplatesResponse" } } } @@ -27912,131 +31149,48 @@ } }, "x-mint": { - "content": "webhooks:manage" + "content": "templates:read" }, - "description": "**Required scope:** `webhooks:manage`" - } - }, - "/api/media/{id}": { - "get": { - "operationId": "downloadMedia", + "description": "**Required scope:** `templates:read`" + }, + "post": { + "operationId": "createProjectTemplate", "tags": [ - "Media" + "Templates" ], - "summary": "Download media (binary stream or redirect to S3)", + "summary": "Create a project message template", "security": [ { "BearerAuth": [] } ], - "x-required-scope": "media:read", + "x-required-scope": "templates:manage", "parameters": [ { "schema": { "type": "string" }, "required": true, - "name": "id", + "name": "projectSlug", "in": "path" } ], - "responses": { - "200": { - "description": "Media binary stream" - }, - "302": { - "description": "Redirect to S3" - }, - "400": { - "description": "Bad request — request body or params failed validation", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "401": { - "description": "Missing or invalid authentication token", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "403": { - "description": "Authenticated but not permitted (missing scope or rule violation)", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "404": { - "description": "Resource not found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "500": { - "description": "Internal server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateMessageTemplateRequest" } } } }, - "x-mint": { - "content": "Linked Device API media:read" - }, - "x-protocols": [ - "Linked Device API" - ], - "description": "**Protocols:** Linked Device API\n\n**Required scope:** `media:read`" - } - }, - "/api/media/{id}/info": { - "get": { - "operationId": "getMediaInfo", - "tags": [ - "Media" - ], - "summary": "Get media metadata", - "security": [ - { - "BearerAuth": [] - } - ], - "x-required-scope": "media:read", - "parameters": [ - { - "schema": { - "type": "string" - }, - "required": true, - "name": "id", - "in": "path" - } - ], "responses": { - "200": { - "description": "Media info", + "201": { + "description": "Created", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/GetMediaInfoResponse" + "$ref": "#/components/schemas/CreateProjectTemplateResponse" } } } @@ -28093,28 +31247,33 @@ } }, "x-mint": { - "content": "Linked Device API media:read" + "content": "templates:manage" }, - "x-protocols": [ - "Linked Device API" - ], - "description": "**Protocols:** Linked Device API\n\n**Required scope:** `media:read`" + "description": "**Required scope:** `templates:manage`" } }, - "/api/media/{id}/download-and-save": { - "post": { - "operationId": "downloadAndSaveMedia", + "/api/projects/{projectSlug}/templates/{id}": { + "get": { + "operationId": "getProjectTemplate", "tags": [ - "Media" + "Templates" ], - "summary": "Download media and persist it to the tenant's S3 bucket", + "summary": "Get a project message template", "security": [ { "BearerAuth": [] } ], - "x-required-scope": "media:manage", + "x-required-scope": "templates:read", "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "projectSlug", + "in": "path" + }, { "schema": { "type": "string" @@ -28126,11 +31285,11 @@ ], "responses": { "200": { - "description": "Persistence queued or already persisted", + "description": "Template", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SuccessResponse" + "$ref": "#/components/schemas/GetProjectTemplateResponse" } } } @@ -28187,27 +31346,22 @@ } }, "x-mint": { - "content": "Linked Device API media:manage" + "content": "templates:read" }, - "x-protocols": [ - "Linked Device API" - ], - "description": "**Protocols:** Linked Device API\n\n**Required scope:** `media:manage`" - } - }, - "/api/projects/{projectSlug}/templates": { - "get": { - "operationId": "listProjectTemplates", + "description": "**Required scope:** `templates:read`" + }, + "patch": { + "operationId": "updateProjectTemplate", "tags": [ "Templates" ], - "summary": "List project message templates", + "summary": "Update a project message template", "security": [ { "BearerAuth": [] } ], - "x-required-scope": "templates:read", + "x-required-scope": "templates:manage", "parameters": [ { "schema": { @@ -28216,15 +31370,32 @@ "required": true, "name": "projectSlug", "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "id", + "in": "path" } ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateMessageTemplateRequest" + } + } + } + }, "responses": { "200": { - "description": "Templates", + "description": "Updated", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ListProjectTemplatesResponse" + "$ref": "#/components/schemas/UpdateProjectTemplateResponse" } } } @@ -28281,16 +31452,16 @@ } }, "x-mint": { - "content": "templates:read" + "content": "templates:manage" }, - "description": "**Required scope:** `templates:read`" + "description": "**Required scope:** `templates:manage`" }, - "post": { - "operationId": "createProjectTemplate", + "delete": { + "operationId": "deleteProjectTemplate", "tags": [ "Templates" ], - "summary": "Create a project message template", + "summary": "Delete a project message template", "security": [ { "BearerAuth": [] @@ -28305,24 +31476,23 @@ "required": true, "name": "projectSlug", "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "id", + "in": "path" } ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateMessageTemplateRequest" - } - } - } - }, "responses": { - "201": { - "description": "Created", + "200": { + "description": "Deleted", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/CreateProjectTemplateResponse" + "$ref": "#/components/schemas/SuccessResponse" } } } @@ -28384,13 +31554,13 @@ "description": "**Required scope:** `templates:manage`" } }, - "/api/projects/{projectSlug}/templates/{id}": { - "get": { - "operationId": "getProjectTemplate", + "/api/projects/{projectSlug}/templates/{id}/preview": { + "post": { + "operationId": "previewProjectTemplate", "tags": [ "Templates" ], - "summary": "Get a project message template", + "summary": "Render a template preview (idealized) or surface-specific output", "security": [ { "BearerAuth": [] @@ -28415,13 +31585,22 @@ "in": "path" } ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PreviewMessageTemplateRequest" + } + } + } + }, "responses": { "200": { - "description": "Template", + "description": "Rendered", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/GetProjectTemplateResponse" + "$ref": "#/components/schemas/PreviewProjectTemplateResponse" } } } @@ -28481,13 +31660,16 @@ "content": "templates:read" }, "description": "**Required scope:** `templates:read`" - }, - "patch": { - "operationId": "updateProjectTemplate", + } + }, + "/api/projects/{projectSlug}/templates/{id}/submit": { + "post": { + "operationId": "submitProjectTemplateToMeta", "tags": [ "Templates" ], - "summary": "Update a project message template", + "summary": "Submit a project template to Meta for approval on a Cloud-API session", + "description": "**Required scope:** `templates:manage`\n\nRenders the canonical template into a Meta create-template payload and submits it through the given cloud_api session. Records a per-session approval pointer (cloudLinks) and returns the updated template. The Meta review verdict arrives later via webhook.", "security": [ { "BearerAuth": [] @@ -28516,18 +31698,18 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/UpdateMessageTemplateRequest" + "$ref": "#/components/schemas/SubmitMessageTemplateRequest" } } } }, "responses": { "200": { - "description": "Updated", + "description": "Submitted", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/UpdateProjectTemplateResponse" + "$ref": "#/components/schemas/SubmitProjectTemplateResponse" } } } @@ -28585,21 +31767,22 @@ }, "x-mint": { "content": "templates:manage" - }, - "description": "**Required scope:** `templates:manage`" - }, - "delete": { - "operationId": "deleteProjectTemplate", + } + } + }, + "/api/projects/{projectSlug}/campaigns": { + "get": { + "operationId": "listCampaigns", "tags": [ - "Templates" + "Campaigns" ], - "summary": "Delete a project message template", + "summary": "List campaigns", "security": [ { "BearerAuth": [] } ], - "x-required-scope": "templates:manage", + "x-required-scope": "campaigns:read", "parameters": [ { "schema": { @@ -28608,23 +31791,15 @@ "required": true, "name": "projectSlug", "in": "path" - }, - { - "schema": { - "type": "string" - }, - "required": true, - "name": "id", - "in": "path" } ], "responses": { "200": { - "description": "Deleted", + "description": "OK", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SuccessResponse" + "$ref": "#/components/schemas/ListCampaignsResponse" } } } @@ -28681,24 +31856,22 @@ } }, "x-mint": { - "content": "templates:manage" + "content": "campaigns:read" }, - "description": "**Required scope:** `templates:manage`" - } - }, - "/api/projects/{projectSlug}/templates/{id}/preview": { + "description": "**Required scope:** `campaigns:read`" + }, "post": { - "operationId": "previewProjectTemplate", + "operationId": "createCampaign", "tags": [ - "Templates" + "Campaigns" ], - "summary": "Render a template preview (idealized) or surface-specific output", + "summary": "Create a campaign", "security": [ { "BearerAuth": [] } ], - "x-required-scope": "templates:read", + "x-required-scope": "campaigns:manage", "parameters": [ { "schema": { @@ -28707,32 +31880,24 @@ "required": true, "name": "projectSlug", "in": "path" - }, - { - "schema": { - "type": "string" - }, - "required": true, - "name": "id", - "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/PreviewMessageTemplateRequest" + "$ref": "#/components/schemas/CreateCampaignRequest" } } } }, "responses": { "200": { - "description": "Rendered", + "description": "OK", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/PreviewProjectTemplateResponse" + "$ref": "#/components/schemas/CreateCampaignResponse" } } } @@ -28757,6 +31922,16 @@ } } }, + "402": { + "description": "This project has no number on a plan that includes Campaigns (`campaigns_not_entitled`)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, "403": { "description": "Authenticated but not permitted (missing scope or rule violation)", "content": { @@ -28789,25 +31964,24 @@ } }, "x-mint": { - "content": "templates:read" + "content": "campaigns:manage" }, - "description": "**Required scope:** `templates:read`" + "description": "**Required scope:** `campaigns:manage`" } }, - "/api/projects/{projectSlug}/templates/{id}/submit": { - "post": { - "operationId": "submitProjectTemplateToMeta", + "/api/projects/{projectSlug}/campaigns/{id}": { + "get": { + "operationId": "getCampaign", "tags": [ - "Templates" + "Campaigns" ], - "summary": "Submit a project template to Meta for approval on a Cloud-API session", - "description": "**Required scope:** `templates:manage`\n\nRenders the canonical template into a Meta create-template payload and submits it through the given cloud_api session. Records a per-session approval pointer (cloudLinks) and returns the updated template. The Meta review verdict arrives later via webhook.", + "summary": "Get a campaign", "security": [ { "BearerAuth": [] } ], - "x-required-scope": "templates:manage", + "x-required-scope": "campaigns:read", "parameters": [ { "schema": { @@ -28826,22 +32000,13 @@ "in": "path" } ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubmitMessageTemplateRequest" - } - } - } - }, "responses": { "200": { - "description": "Submitted", + "description": "OK", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SubmitProjectTemplateResponse" + "$ref": "#/components/schemas/GetCampaignResponse" } } } @@ -28866,6 +32031,16 @@ } } }, + "402": { + "description": "This project has no number on a plan that includes Campaigns (`campaigns_not_entitled`)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, "403": { "description": "Authenticated but not permitted (missing scope or rule violation)", "content": { @@ -28898,17 +32073,18 @@ } }, "x-mint": { - "content": "templates:manage" - } + "content": "campaigns:read" + }, + "description": "**Required scope:** `campaigns:read`" } }, - "/api/projects/{projectSlug}/campaigns": { + "/api/projects/{projectSlug}/campaigns/{id}/analytics": { "get": { - "operationId": "listCampaigns", + "operationId": "getCampaignAnalytics", "tags": [ "Campaigns" ], - "summary": "List campaigns", + "summary": "Campaign analytics (funnel, response timing, retries)", "security": [ { "BearerAuth": [] @@ -28923,6 +32099,14 @@ "required": true, "name": "projectSlug", "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "id", + "in": "path" } ], "responses": { @@ -28931,7 +32115,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ListCampaignsResponse" + "$ref": "#/components/schemas/CampaignAnalyticsResponse" } } } @@ -28956,6 +32140,16 @@ } } }, + "402": { + "description": "This project has no number on a plan that includes Campaigns (`campaigns_not_entitled`)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, "403": { "description": "Authenticated but not permitted (missing scope or rule violation)", "content": { @@ -28991,13 +32185,15 @@ "content": "campaigns:read" }, "description": "**Required scope:** `campaigns:read`" - }, + } + }, + "/api/projects/{projectSlug}/campaigns/{id}/launch": { "post": { - "operationId": "createCampaign", + "operationId": "launchCampaign", "tags": [ "Campaigns" ], - "summary": "Create a campaign", + "summary": "Launch a campaign", "security": [ { "BearerAuth": [] @@ -29012,13 +32208,21 @@ "required": true, "name": "projectSlug", "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "id", + "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/CreateCampaignRequest" + "$ref": "#/components/schemas/LaunchCampaignRequest" } } } @@ -29029,7 +32233,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/CreateCampaignResponse" + "$ref": "#/components/schemas/LaunchCampaignResponse" } } } @@ -29101,19 +32305,19 @@ "description": "**Required scope:** `campaigns:manage`" } }, - "/api/projects/{projectSlug}/campaigns/{id}": { - "get": { - "operationId": "getCampaign", + "/api/projects/{projectSlug}/campaigns/{id}/pause": { + "post": { + "operationId": "pauseCampaign", "tags": [ "Campaigns" ], - "summary": "Get a campaign", + "summary": "Pause a campaign", "security": [ { "BearerAuth": [] } ], - "x-required-scope": "campaigns:read", + "x-required-scope": "campaigns:manage", "parameters": [ { "schema": { @@ -29138,7 +32342,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/GetCampaignResponse" + "$ref": "#/components/schemas/PauseCampaignResponse" } } } @@ -29205,24 +32409,24 @@ } }, "x-mint": { - "content": "campaigns:read" + "content": "campaigns:manage" }, - "description": "**Required scope:** `campaigns:read`" + "description": "**Required scope:** `campaigns:manage`" } }, - "/api/projects/{projectSlug}/campaigns/{id}/analytics": { - "get": { - "operationId": "getCampaignAnalytics", + "/api/projects/{projectSlug}/campaigns/{id}/resume": { + "post": { + "operationId": "resumeCampaign", "tags": [ "Campaigns" ], - "summary": "Campaign analytics (funnel, response timing, retries)", + "summary": "Resume a campaign", "security": [ { "BearerAuth": [] } ], - "x-required-scope": "campaigns:read", + "x-required-scope": "campaigns:manage", "parameters": [ { "schema": { @@ -29247,7 +32451,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/CampaignAnalyticsResponse" + "$ref": "#/components/schemas/ResumeCampaignResponse" } } } @@ -29314,18 +32518,18 @@ } }, "x-mint": { - "content": "campaigns:read" + "content": "campaigns:manage" }, - "description": "**Required scope:** `campaigns:read`" + "description": "**Required scope:** `campaigns:manage`" } }, - "/api/projects/{projectSlug}/campaigns/{id}/launch": { + "/api/projects/{projectSlug}/campaigns/{id}/stop": { "post": { - "operationId": "launchCampaign", + "operationId": "stopCampaign", "tags": [ "Campaigns" ], - "summary": "Launch a campaign", + "summary": "Stop a campaign", "security": [ { "BearerAuth": [] @@ -29350,22 +32554,13 @@ "in": "path" } ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/LaunchCampaignRequest" - } - } - } - }, "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/LaunchCampaignResponse" + "$ref": "#/components/schemas/StopCampaignResponse" } } } @@ -29437,13 +32632,13 @@ "description": "**Required scope:** `campaigns:manage`" } }, - "/api/projects/{projectSlug}/campaigns/{id}/pause": { + "/api/projects/{projectSlug}/campaigns/{id}/requeue": { "post": { - "operationId": "pauseCampaign", + "operationId": "requeueCampaign", "tags": [ "Campaigns" ], - "summary": "Pause a campaign", + "summary": "Re-queue failed recipients", "security": [ { "BearerAuth": [] @@ -29468,13 +32663,22 @@ "in": "path" } ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RequeueCampaignRequest" + } + } + } + }, "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/PauseCampaignResponse" + "$ref": "#/components/schemas/RequeueCampaignResponse" } } } @@ -29546,44 +32750,36 @@ "description": "**Required scope:** `campaigns:manage`" } }, - "/api/projects/{projectSlug}/campaigns/{id}/resume": { + "/api/quicklinks": { "post": { - "operationId": "resumeCampaign", + "operationId": "createQuickLink", "tags": [ - "Campaigns" + "QuickLink" ], - "summary": "Resume a campaign", + "summary": "Create a QuickLink", + "description": "**Required scope:** `quicklink:manage`\n\nCreates a 15-minute hosted link that connects one WhatsApp number to a new session in the project.", "security": [ { "BearerAuth": [] } ], - "x-required-scope": "campaigns:manage", - "parameters": [ - { - "schema": { - "type": "string" - }, - "required": true, - "name": "projectSlug", - "in": "path" - }, - { - "schema": { - "type": "string" - }, - "required": true, - "name": "id", - "in": "path" + "x-required-scope": "quicklink:manage", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateQuickLinkRequest" + } + } } - ], + }, "responses": { - "200": { - "description": "OK", + "201": { + "description": "QuickLink created", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ResumeCampaignResponse" + "$ref": "#/components/schemas/QuickLinkResponse" } } } @@ -29608,16 +32804,6 @@ } } }, - "402": { - "description": "This project has no number on a plan that includes Campaigns (`campaigns_not_entitled`)", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, "403": { "description": "Authenticated but not permitted (missing scope or rule violation)", "content": { @@ -29650,33 +32836,24 @@ } }, "x-mint": { - "content": "campaigns:manage" - }, - "description": "**Required scope:** `campaigns:manage`" + "content": "quicklink:manage" + } } }, - "/api/projects/{projectSlug}/campaigns/{id}/stop": { - "post": { - "operationId": "stopCampaign", + "/api/quicklinks/{id}": { + "get": { + "operationId": "getQuickLink", "tags": [ - "Campaigns" + "QuickLink" ], - "summary": "Stop a campaign", + "summary": "Read QuickLink status", "security": [ { "BearerAuth": [] } ], - "x-required-scope": "campaigns:manage", + "x-required-scope": "quicklink:manage", "parameters": [ - { - "schema": { - "type": "string" - }, - "required": true, - "name": "projectSlug", - "in": "path" - }, { "schema": { "type": "string" @@ -29688,11 +32865,11 @@ ], "responses": { "200": { - "description": "OK", + "description": "Current QuickLink status", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/StopCampaignResponse" + "$ref": "#/components/schemas/QuickLinkStatusResponse" } } } @@ -29717,16 +32894,6 @@ } } }, - "402": { - "description": "This project has no number on a plan that includes Campaigns (`campaigns_not_entitled`)", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, "403": { "description": "Authenticated but not permitted (missing scope or rule violation)", "content": { @@ -29759,33 +32926,24 @@ } }, "x-mint": { - "content": "campaigns:manage" + "content": "quicklink:manage" }, - "description": "**Required scope:** `campaigns:manage`" - } - }, - "/api/projects/{projectSlug}/campaigns/{id}/requeue": { - "post": { - "operationId": "requeueCampaign", + "description": "**Required scope:** `quicklink:manage`" + }, + "delete": { + "operationId": "cancelQuickLink", "tags": [ - "Campaigns" + "QuickLink" ], - "summary": "Re-queue failed recipients", + "summary": "Cancel a QuickLink", + "description": "**Required scope:** `quicklink:manage`\n\nInvalidates the link and removes its pending session. Connected links cannot be cancelled.", "security": [ { "BearerAuth": [] } ], - "x-required-scope": "campaigns:manage", + "x-required-scope": "quicklink:manage", "parameters": [ - { - "schema": { - "type": "string" - }, - "required": true, - "name": "projectSlug", - "in": "path" - }, { "schema": { "type": "string" @@ -29795,22 +32953,28 @@ "in": "path" } ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RequeueCampaignRequest" - } - } - } - }, "responses": { "200": { - "description": "OK", + "description": "Cancelled", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/RequeueCampaignResponse" + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "message": { + "type": "string" + } + }, + "required": [ + "success", + "message" + ] } } } @@ -29835,8 +32999,93 @@ } } }, - "402": { - "description": "This project has no number on a plan that includes Campaigns (`campaigns_not_entitled`)", + "403": { + "description": "Authenticated but not permitted (missing scope or rule violation)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-mint": { + "content": "quicklink:manage" + } + } + }, + "/quicklink/{token}": { + "get": { + "operationId": "getQuickLinkState", + "tags": [ + "QuickLink" + ], + "security": [], + "summary": "Read QuickLink state", + "description": "Returns the hosted page state for a QuickLink. Public; the token in the URL is the credential. Starts the session on first read.", + "parameters": [ + { + "schema": { + "type": "string", + "description": "Opaque QuickLink token from the hosted URL." + }, + "required": true, + "name": "token", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Current QuickLink state", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/QuickLinkState" + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "description": "Bad request — request body or params failed validation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication token", "content": { "application/json": { "schema": { @@ -29875,42 +33124,37 @@ } } } - }, - "x-mint": { - "content": "campaigns:manage" - }, - "description": "**Required scope:** `campaigns:manage`" + } } }, - "/api/widget/sessions": { - "post": { - "operationId": "createWidgetSession", + "/quicklink/{token}/logo": { + "get": { + "operationId": "getQuickLinkLogo", "tags": [ - "Widget" + "QuickLink" ], - "summary": "Create a widget session for embedding the connect flow", - "security": [ + "security": [], + "summary": "Read the QuickLink page logo", + "description": "Returns the saved logo image for the page. Public; the token in the URL is the credential.", + "parameters": [ { - "BearerAuth": [] + "schema": { + "type": "string", + "description": "Opaque QuickLink token from the hosted URL." + }, + "required": true, + "name": "token", + "in": "path" } ], - "x-required-scope": "widget:create", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateWidgetSessionRequest" - } - } - } - }, "responses": { - "201": { - "description": "Widget session created", + "200": { + "description": "Logo image", "content": { - "application/json": { + "image/png": { "schema": { - "$ref": "#/components/schemas/WidgetSessionResponseWrapper" + "type": "string", + "format": "binary" } } } @@ -29965,57 +33209,63 @@ } } } - }, - "x-mint": { - "content": "widget:create" - }, - "description": "**Required scope:** `widget:create`" + } } }, - "/api/widget/sessions/{id}": { - "delete": { - "operationId": "cancelWidgetSession", + "/quicklink/{token}/code": { + "post": { + "operationId": "requestQuickLinkCode", "tags": [ - "Widget" - ], - "summary": "Cancel a pending widget session and revoke its CST", - "security": [ - { - "BearerAuth": [] - } + "QuickLink" ], - "x-required-scope": "widget:create", + "security": [], + "summary": "Request a QuickLink pairing code", "parameters": [ { "schema": { - "type": "string" + "type": "string", + "description": "Opaque QuickLink token from the hosted URL." }, "required": true, - "name": "id", + "name": "token", "in": "path" } ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/QuickLinkCodeRequest" + } + } + } + }, "responses": { "200": { - "description": "Cancelled", + "description": "Pairing code issued", "content": { "application/json": { "schema": { "type": "object", "properties": { - "success": { - "type": "boolean", - "enum": [ - true + "data": { + "type": "object", + "properties": { + "code": { + "type": "string" + }, + "phone": { + "type": "string" + } + }, + "required": [ + "code", + "phone" ] - }, - "message": { - "type": "string" } }, "required": [ - "success", - "message" + "data" ] } } @@ -30071,56 +33321,76 @@ } } } - }, - "x-mint": { - "content": "widget:create" - }, - "description": "**Required scope:** `widget:create`" + } } }, - "/api/widget/sessions/{id}/handoff": { + "/quicklink/{token}/confirm": { "post": { - "operationId": "createWidgetHandoff", + "operationId": "confirmQuickLink", "tags": [ - "Widget" + "QuickLink" ], - "summary": "Mint a TV-style handoff token + meta-QR so the user can finish the connect flow on another device.", - "security": [ - { - "BearerAuth": [] - } - ], - "x-required-scope": "widget:create", + "security": [], + "summary": "Confirm a linked QuickLink", + "description": "Records consent, applies the chat-history choice, assigns Customer ownership when applicable, and returns the redirect target.", "parameters": [ { "schema": { - "type": "string" + "type": "string", + "description": "Opaque QuickLink token from the hosted URL." }, "required": true, - "name": "id", + "name": "token", "in": "path" } ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/QuickLinkConfirmRequest" + } + } + } + }, "responses": { - "201": { - "description": "Handoff minted", + "200": { + "description": "Connected", "content": { "application/json": { "schema": { "type": "object", "properties": { - "success": { - "type": "boolean", - "enum": [ - true - ] - }, "data": { - "$ref": "#/components/schemas/WidgetHandoffResponse" + "type": "object", + "properties": { + "status": { + "type": "string", + "enum": [ + "connected" + ] + }, + "phone": { + "type": "string", + "nullable": true + }, + "historySync": { + "type": "boolean" + }, + "redirectUrl": { + "type": "string", + "nullable": true + } + }, + "required": [ + "status", + "phone", + "historySync", + "redirectUrl" + ] } }, "required": [ - "success", "data" ] } @@ -30177,25 +33447,22 @@ } } } - }, - "x-mint": { - "content": "widget:create" - }, - "description": "**Required scope:** `widget:create`" + } } }, - "/widget/handoff/{token}/state": { - "get": { - "operationId": "getWidgetHandoffState", + "/quicklink/{token}/cancel": { + "post": { + "operationId": "cancelQuickLinkByToken", "tags": [ - "Widget" + "QuickLink" ], "security": [], - "summary": "Resolve a handoff token to the current QR + session status. Public — the token in the URL is the bearer.", + "summary": "Cancel a QuickLink from the hosted page", "parameters": [ { "schema": { - "type": "string" + "type": "string", + "description": "Opaque QuickLink token from the hosted URL." }, "required": true, "name": "token", @@ -30204,24 +33471,33 @@ ], "responses": { "200": { - "description": "Current QR + status", + "description": "Cancelled", "content": { "application/json": { "schema": { "type": "object", "properties": { - "success": { - "type": "boolean", - "enum": [ - true - ] - }, "data": { - "$ref": "#/components/schemas/WidgetHandoffState" + "type": "object", + "properties": { + "status": { + "type": "string", + "enum": [ + "cancelled" + ] + }, + "redirectUrl": { + "type": "string", + "nullable": true + } + }, + "required": [ + "status", + "redirectUrl" + ] } }, "required": [ - "success", "data" ] } @@ -30301,7 +33577,7 @@ } }, "responses": { - "200": { + "2XX": { "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." } } @@ -30325,7 +33601,7 @@ } }, "responses": { - "200": { + "2XX": { "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." } } @@ -30349,7 +33625,7 @@ } }, "responses": { - "200": { + "2XX": { "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." } } @@ -30373,7 +33649,7 @@ } }, "responses": { - "200": { + "2XX": { "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." } } @@ -30397,7 +33673,7 @@ } }, "responses": { - "200": { + "2XX": { "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." } } @@ -30421,7 +33697,7 @@ } }, "responses": { - "200": { + "2XX": { "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." } } @@ -30445,7 +33721,7 @@ } }, "responses": { - "200": { + "2XX": { "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." } } @@ -30469,7 +33745,7 @@ } }, "responses": { - "200": { + "2XX": { "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." } } @@ -30493,7 +33769,7 @@ } }, "responses": { - "200": { + "2XX": { "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." } } @@ -30517,7 +33793,7 @@ } }, "responses": { - "200": { + "2XX": { "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." } } @@ -30541,7 +33817,7 @@ } }, "responses": { - "200": { + "2XX": { "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." } } @@ -30565,7 +33841,7 @@ } }, "responses": { - "200": { + "2XX": { "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." } } @@ -30589,7 +33865,7 @@ } }, "responses": { - "200": { + "2XX": { "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." } } @@ -30613,7 +33889,7 @@ } }, "responses": { - "200": { + "2XX": { "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." } } @@ -30637,7 +33913,7 @@ } }, "responses": { - "200": { + "2XX": { "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." } } @@ -30661,7 +33937,7 @@ } }, "responses": { - "200": { + "2XX": { "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." } } @@ -30685,7 +33961,7 @@ } }, "responses": { - "200": { + "2XX": { "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." } } @@ -30709,7 +33985,7 @@ } }, "responses": { - "200": { + "2XX": { "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." } } @@ -30733,7 +34009,7 @@ } }, "responses": { - "200": { + "2XX": { "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." } } @@ -30757,7 +34033,7 @@ } }, "responses": { - "200": { + "2XX": { "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." } } @@ -30781,7 +34057,7 @@ } }, "responses": { - "200": { + "2XX": { "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." } } @@ -30805,7 +34081,7 @@ } }, "responses": { - "200": { + "2XX": { "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." } } @@ -30829,7 +34105,7 @@ } }, "responses": { - "200": { + "2XX": { "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." } } @@ -30853,7 +34129,7 @@ } }, "responses": { - "200": { + "2XX": { "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." } } @@ -30877,7 +34153,7 @@ } }, "responses": { - "200": { + "2XX": { "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." } } @@ -30901,7 +34177,7 @@ } }, "responses": { - "200": { + "2XX": { "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." } } @@ -30925,7 +34201,127 @@ } }, "responses": { - "200": { + "2XX": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "call.ended": { + "post": { + "operationId": "onCallEnded", + "summary": "Call ended", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CallEndedEvent" + } + } + } + }, + "responses": { + "2XX": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "call.telemetry": { + "post": { + "operationId": "onCallTelemetry", + "summary": "Call telemetry", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CallTelemetryEvent" + } + } + } + }, + "responses": { + "2XX": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "call.participant_joined": { + "post": { + "operationId": "onCallParticipantJoined", + "summary": "Participant joined a call", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CallParticipantJoinedEvent" + } + } + } + }, + "responses": { + "2XX": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "call.participant_state": { + "post": { + "operationId": "onCallParticipantState", + "summary": "Participant call state changed", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CallParticipantStateEvent" + } + } + } + }, + "responses": { + "2XX": { + "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." + } + } + } + }, + "call.participant_left": { + "post": { + "operationId": "onCallParticipantLeft", + "summary": "Participant left a call", + "tags": [ + "Webhooks" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CallParticipantLeftEvent" + } + } + } + }, + "responses": { + "2XX": { "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." } } @@ -30949,7 +34345,7 @@ } }, "responses": { - "200": { + "2XX": { "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." } } @@ -30973,7 +34369,7 @@ } }, "responses": { - "200": { + "2XX": { "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." } } @@ -30997,7 +34393,7 @@ } }, "responses": { - "200": { + "2XX": { "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." } } @@ -31021,7 +34417,7 @@ } }, "responses": { - "200": { + "2XX": { "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." } } @@ -31045,7 +34441,7 @@ } }, "responses": { - "200": { + "2XX": { "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." } } @@ -31069,7 +34465,7 @@ } }, "responses": { - "200": { + "2XX": { "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." } } @@ -31093,7 +34489,7 @@ } }, "responses": { - "200": { + "2XX": { "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." } } @@ -31117,7 +34513,7 @@ } }, "responses": { - "200": { + "2XX": { "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." } } @@ -31141,7 +34537,7 @@ } }, "responses": { - "200": { + "2XX": { "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." } } @@ -31165,7 +34561,7 @@ } }, "responses": { - "200": { + "2XX": { "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." } } @@ -31189,7 +34585,7 @@ } }, "responses": { - "200": { + "2XX": { "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." } } @@ -31213,7 +34609,7 @@ } }, "responses": { - "200": { + "2XX": { "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." } } @@ -31237,7 +34633,7 @@ } }, "responses": { - "200": { + "2XX": { "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." } } @@ -31261,7 +34657,7 @@ } }, "responses": { - "200": { + "2XX": { "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." } } @@ -31285,7 +34681,7 @@ } }, "responses": { - "200": { + "2XX": { "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." } } @@ -31309,7 +34705,7 @@ } }, "responses": { - "200": { + "2XX": { "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." } } @@ -31333,7 +34729,7 @@ } }, "responses": { - "200": { + "2XX": { "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." } } @@ -31357,7 +34753,7 @@ } }, "responses": { - "200": { + "2XX": { "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." } } @@ -31381,7 +34777,7 @@ } }, "responses": { - "200": { + "2XX": { "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." } } @@ -31405,7 +34801,7 @@ } }, "responses": { - "200": { + "2XX": { "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." } } @@ -31429,7 +34825,7 @@ } }, "responses": { - "200": { + "2XX": { "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." } } @@ -31453,7 +34849,7 @@ } }, "responses": { - "200": { + "2XX": { "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." } } @@ -31477,7 +34873,7 @@ } }, "responses": { - "200": { + "2XX": { "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." } } @@ -31501,7 +34897,7 @@ } }, "responses": { - "200": { + "2XX": { "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." } } @@ -31525,7 +34921,7 @@ } }, "responses": { - "200": { + "2XX": { "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." } } @@ -31549,7 +34945,7 @@ } }, "responses": { - "200": { + "2XX": { "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." } } @@ -31573,7 +34969,7 @@ } }, "responses": { - "200": { + "2XX": { "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." } } @@ -31597,7 +34993,7 @@ } }, "responses": { - "200": { + "2XX": { "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." } } @@ -31621,7 +35017,7 @@ } }, "responses": { - "200": { + "2XX": { "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." } } @@ -31645,7 +35041,7 @@ } }, "responses": { - "200": { + "2XX": { "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." } } @@ -31669,7 +35065,7 @@ } }, "responses": { - "200": { + "2XX": { "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." } } @@ -31693,7 +35089,7 @@ } }, "responses": { - "200": { + "2XX": { "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." } } @@ -31717,7 +35113,7 @@ } }, "responses": { - "200": { + "2XX": { "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." } } @@ -31741,7 +35137,7 @@ } }, "responses": { - "200": { + "2XX": { "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." } } @@ -31765,7 +35161,7 @@ } }, "responses": { - "200": { + "2XX": { "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." } } @@ -31789,7 +35185,7 @@ } }, "responses": { - "200": { + "2XX": { "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." } } @@ -31813,7 +35209,7 @@ } }, "responses": { - "200": { + "2XX": { "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." } } diff --git a/contracts/drafts/bansafe/openapi.platform.json b/contracts/drafts/bansafe/openapi.platform.json index 79272f6..33cd06c 100644 --- a/contracts/drafts/bansafe/openapi.platform.json +++ b/contracts/drafts/bansafe/openapi.platform.json @@ -3,7 +3,7 @@ "info": { "title": "Polymorfa Console & Management API", "version": "1.0.0", - "description": "Complete console/management surface. Resource-oriented REST: `{param}` path variables, single-word action sub-resources.\n\nNamespaces decide inclusion:\n- `/v1/…` — **public registry** (150 endpoints): each endpoint declares either a scoped `pmfa_` organization key or a verified live dashboard JWT, or dashboard-only authorization when a specific user's authority is required. Only implemented handlers are published to customers and SDKs.\n- `/console/…` — **console-only** (50 endpoints): verified dashboard identity. EXCLUDED from the published spec; reason per endpoint.\n- `/admin/…` — **staff-only** (53 endpoints): Polymorfa internal staff. EXCLUDED.\n\nThe published customer spec = this document filtered to `x-audience: public` endpoints with an implemented runtime handler.\nMost transitional body/response schemas remain loose (`additionalProperties: true`); session-control operations use explicit strict schemas." + "description": "Complete console/management surface. Resource-oriented REST: `{param}` path variables, single-word action sub-resources.\n\nNamespaces decide inclusion:\n- `/v1/…` — **public registry** (150 endpoints): each endpoint declares either a scoped `pmfa_` organization key or a verified live dashboard JWT, or dashboard-only authorization when a specific user's authority is required. Only implemented handlers are published to customers and SDKs.\n- `/console/…` — **console-only** (52 endpoints): verified dashboard identity. EXCLUDED from the published spec; reason per endpoint.\n- `/admin/…` — **staff-only** (53 endpoints): Polymorfa internal staff. EXCLUDED.\n\nThe published customer spec = this document filtered to `x-audience: public` endpoints with an implemented runtime handler.\nMost transitional body/response schemas remain loose (`additionalProperties: true`); session-control operations use explicit strict schemas." }, "servers": [ { @@ -6458,6 +6458,154 @@ } } }, + "/console/projects/{projectId}": { + "patch": { + "operationId": "updateProject", + "tags": [ + "projects" + ], + "summary": "Update project settings", + "description": "Updates the display name, icon, or default number plan without changing the project ID, URL, stage, or individual number overrides.\n\nRequires a verified dashboard bearer and current organization authorization. The signed-in member must be an organization owner or admin. Organization keys and project tokens are not accepted.", + "x-audience": "console", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Dashboard project name, icon, and default number plan settings. Requires a current owner or admin.", + "x-required-organization-role": "owner_or_admin", + "security": [ + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "projectId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "minProperties": 1, + "properties": { + "name": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "defaultTier": { + "type": "string", + "enum": [ + "free", + "standard", + "pro" + ] + }, + "icon": { + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "value" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "emoji", + "icon", + "image" + ] + }, + "value": { + "type": "string", + "minLength": 1, + "maxLength": 512 + }, + "color": { + "type": "string", + "maxLength": 64 + }, + "storageId": { + "type": "string", + "maxLength": 256 + } + } + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "type": "object", + "additionalProperties": false, + "required": [ + "saved" + ], + "properties": { + "saved": { + "type": "boolean", + "enum": [ + true + ] + } + } + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, "/v1/projects/{projectId}/promote": { "post": { "operationId": "requestProductionEnrollment", @@ -13110,18 +13258,18 @@ } } }, - "/v1/widget": { + "/v1/quicklink": { "get": { - "operationId": "getWidgetSettings", + "operationId": "getQuickLinkSettings", "tags": [ - "widget" + "quicklink" ], - "summary": "Get widget settings", - "description": "Public Management API. Organization API-key callers require `widget:create`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "summary": "Read QuickLink settings", + "description": "Returns the saved QuickLink settings for the authenticated organization or one project, or null when nothing has been saved for that scope. There is no separate read permission: reading and updating both require `quicklink:manage`, because the settings include the redirect allowlist and branding that only a QuickLink manager should see.\n\nOrganization API-key callers require `quicklink:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, - "x-required-scope": "widget:create", + "x-required-scope": "quicklink:manage", "security": [ { "ApiKeyAuth": [] @@ -13160,7 +13308,21 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DataEnvelope" + "type": "object", + "additionalProperties": false, + "properties": { + "data": { + "nullable": true, + "allOf": [ + { + "$ref": "#/components/schemas/QuickLinkSettings" + } + ] + } + }, + "required": [ + "data" + ] } } } @@ -13170,23 +13332,20 @@ }, "403": { "$ref": "#/components/responses/Forbidden" - }, - "501": { - "$ref": "#/components/responses/NotImplemented" } } }, "put": { - "operationId": "updateWidgetSettings", + "operationId": "updateQuickLinkSettings", "tags": [ - "widget" + "quicklink" ], - "summary": "Update widget settings", - "description": "Updates the widget settings for the authenticated organization and project.\n\nOrganization API-key callers require `widget:create`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "summary": "Update QuickLink settings", + "description": "Updates the saved QuickLink settings for the authenticated organization or project and returns the saved record.\n\nOrganization API-key callers require `quicklink:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, - "x-required-scope": "widget:create", + "x-required-scope": "quicklink:manage", "security": [ { "ApiKeyAuth": [] @@ -13200,7 +13359,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/UpdateWidgetSettingsRequest" + "$ref": "#/components/schemas/UpdateQuickLinkSettingsRequest" } } } @@ -13229,8 +13388,7 @@ "additionalProperties": false, "properties": { "data": { - "type": "object", - "additionalProperties": true + "$ref": "#/components/schemas/QuickLinkSettings" } }, "required": [ @@ -15317,13 +15475,13 @@ } } }, - "/console/widget/logo/uploads": { + "/console/quicklink/logo/uploads": { "post": { - "operationId": "generateWidgetSettingsLogoUploadUrl", + "operationId": "generateQuickLinkSettingsLogoUploadUrl", "tags": [ - "widget" + "quicklink" ], - "summary": "Generate widget settings logo upload url", + "summary": "Generate quick link settings logo upload url", "description": "**EXCLUDED from the public API** (`console`). Browser logo-upload flow.", "x-audience": "console", "x-polymorfa-resource-boundary": "human_only", @@ -15382,13 +15540,13 @@ } } }, - "/console/widget/logo": { + "/console/quicklink/logo": { "put": { - "operationId": "attachLogoWidgetSettings", + "operationId": "attachLogoQuickLinkSettings", "tags": [ - "widget" + "quicklink" ], - "summary": "Attach logo widget settings", + "summary": "Attach logo quick link settings", "description": "**EXCLUDED from the public API** (`console`). Browser logo-upload flow.", "x-audience": "console", "x-polymorfa-resource-boundary": "human_only", @@ -15447,11 +15605,11 @@ } }, "delete": { - "operationId": "removeLogoWidgetSettings", + "operationId": "removeLogoQuickLinkSettings", "tags": [ - "widget" + "quicklink" ], - "summary": "Remove logo widget settings", + "summary": "Remove logo quick link settings", "description": "**EXCLUDED from the public API** (`console`). Browser logo-upload flow.", "x-audience": "console", "x-polymorfa-resource-boundary": "human_only", @@ -15499,13 +15657,13 @@ } } }, - "/console/widget/logo/org": { + "/console/quicklink/logo/org": { "post": { - "operationId": "useOrgLogoWidgetSettings", + "operationId": "useOrgLogoQuickLinkSettings", "tags": [ - "widget" + "quicklink" ], - "summary": "Use org logo widget settings", + "summary": "Use org logo quick link settings", "description": "**EXCLUDED from the public API** (`console`). Console snapshot flow (copies org logo).", "x-audience": "console", "x-polymorfa-resource-boundary": "human_only", @@ -15564,13 +15722,13 @@ } } }, - "/console/widget/logo/project": { + "/console/quicklink/logo/project": { "post": { - "operationId": "useProjectIconWidgetSettings", + "operationId": "useProjectIconQuickLinkSettings", "tags": [ - "widget" + "quicklink" ], - "summary": "Use project icon widget settings", + "summary": "Use project icon quick link settings", "description": "**EXCLUDED from the public API** (`console`). Console snapshot flow (copies project icon).", "x-audience": "console", "x-polymorfa-resource-boundary": "human_only", @@ -16036,6 +16194,89 @@ } } }, + "/console/calls": { + "get": { + "operationId": "listCalls", + "tags": [ + "calls" + ], + "summary": "List calls", + "description": "**EXCLUDED from the public API** (`console`). Customer console view of the organization's own call records.", + "x-audience": "console", + "x-polymorfa-resource-boundary": "human_only", + "x-excluded-from-public": true, + "x-exclusion-reason": "Customer console view of the organization's own call records.", + "security": [ + { + "ConsoleSession": [] + } + ], + "parameters": [ + { + "name": "projectId", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "sessionId", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "limit", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 25 + } + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "X-Request-Id": { + "schema": { + "type": "string" + }, + "description": "Stable request correlation identifier." + }, + "Polymorfa-Version": { + "schema": { + "type": "string" + }, + "description": "API version applied to this response." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataEnvelope" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "501": { + "$ref": "#/components/responses/NotImplemented" + } + } + } + }, "/console/insights/logs": { "get": { "operationId": "logsInsight", @@ -19947,7 +20188,7 @@ "ApiKeyAuth": { "type": "http", "scheme": "bearer", - "description": "Polymorfa server credential: a scoped pmfa_ organization key, or a pmfa_pt_ project token on project- and session-bound operations inside its exact authenticated project. Listener and browser client credentials are rejected." + "description": "Polymorfa server credential: a scoped pmfa_ organization key, or a pmfa_pt_ project token on project- and session-bound operations inside its exact authenticated project. Keys may be personal or service-account owned. Both enforce selected action scopes; organization keys can address team resources and every project in the organization. Listener and browser client credentials are rejected." }, "ConsoleSession": { "type": "http", @@ -20445,7 +20686,8 @@ "type": "string", "enum": [ "en", - "pt-BR" + "pt-BR", + null ], "nullable": true }, @@ -20454,7 +20696,8 @@ "enum": [ "light", "dark", - "system" + "system", + null ], "nullable": true }, @@ -20618,7 +20861,8 @@ "type": "string", "enum": [ "en", - "pt-BR" + "pt-BR", + null ], "nullable": true }, @@ -20627,7 +20871,8 @@ "enum": [ "light", "dark", - "system" + "system", + null ], "nullable": true }, @@ -20794,7 +21039,8 @@ "type": "string", "enum": [ "en", - "pt-BR" + "pt-BR", + null ], "nullable": true }, @@ -20803,7 +21049,8 @@ "enum": [ "light", "dark", - "system" + "system", + null ], "nullable": true } @@ -21032,82 +21279,181 @@ "removed" ] }, - "WidgetColorPalette": { + "QuickLinkSettings": { "type": "object", "additionalProperties": false, + "description": "Saved QuickLink settings for one scope. `logoUrl` is a short-lived read URL for the saved logo.", "properties": { - "background": { + "id": { "type": "string", - "pattern": "^#[0-9A-Fa-f]{6}$" + "format": "uuid" }, - "foreground": { + "projectId": { "type": "string", - "pattern": "^#[0-9A-Fa-f]{6}$" + "format": "uuid", + "nullable": true }, - "card": { + "enabled": { + "type": "boolean" + }, + "allowedRedirectUris": { + "type": "array", + "items": { + "type": "string" + } + }, + "businessName": { "type": "string", - "pattern": "^#[0-9A-Fa-f]{6}$" + "nullable": true }, - "cardForeground": { + "headline": { "type": "string", - "pattern": "^#[0-9A-Fa-f]{6}$" + "nullable": true }, - "primary": { + "description": { "type": "string", - "pattern": "^#[0-9A-Fa-f]{6}$" + "nullable": true }, - "primaryForeground": { + "successMessage": { "type": "string", - "pattern": "^#[0-9A-Fa-f]{6}$" + "nullable": true }, - "muted": { + "supportUrl": { "type": "string", - "pattern": "^#[0-9A-Fa-f]{6}$" + "nullable": true }, - "mutedForeground": { + "privacyUrl": { "type": "string", - "pattern": "^#[0-9A-Fa-f]{6}$" + "nullable": true }, - "border": { + "termsUrl": { "type": "string", - "pattern": "^#[0-9A-Fa-f]{6}$" + "nullable": true }, "accent": { "type": "string", - "pattern": "^#[0-9A-Fa-f]{6}$" + "nullable": true }, - "destructive": { + "theme": { "type": "string", - "pattern": "^#[0-9A-Fa-f]{6}$" + "enum": [ + "light", + "dark", + "system" + ] + }, + "hideWatermark": { + "type": "boolean" }, - "ring": { + "shape": { "type": "string", - "pattern": "^#[0-9A-Fa-f]{6}$" + "enum": [ + "square", + "rounded", + "pill", + null + ], + "nullable": true + }, + "radiusPx": { + "type": "number", + "nullable": true + }, + "logoMode": { + "type": "string", + "enum": [ + "none", + "custom", + "organization", + "project" + ] + }, + "logoStorageId": { + "type": "string", + "nullable": true + }, + "logoSourceStorageId": { + "type": "string", + "nullable": true + }, + "logoUrl": { + "type": "string", + "nullable": true + }, + "historySync": { + "type": "string", + "enum": [ + "ask", + "force_on", + "force_off" + ] + }, + "methods": { + "type": "array", + "nullable": true, + "items": { + "type": "string", + "enum": [ + "qr", + "pairing" + ] + } + }, + "defaultMethod": { + "type": "string", + "enum": [ + "qr", + "pairing", + null + ], + "nullable": true + }, + "createdAt": { + "type": "integer" + }, + "updatedAt": { + "type": "integer" } - } + }, + "required": [ + "id", + "projectId", + "enabled", + "allowedRedirectUris", + "businessName", + "headline", + "description", + "successMessage", + "supportUrl", + "privacyUrl", + "termsUrl", + "accent", + "theme", + "hideWatermark", + "shape", + "radiusPx", + "logoMode", + "logoStorageId", + "logoSourceStorageId", + "logoUrl", + "historySync", + "methods", + "defaultMethod", + "createdAt", + "updatedAt" + ] }, - "UpdateWidgetSettingsRequest": { + "UpdateQuickLinkSettingsRequest": { "type": "object", "additionalProperties": false, + "description": "QuickLink settings for the organization or one project. Omitted fields keep their saved value; `null` clears an optional field.", "properties": { "projectId": { "$ref": "#/components/schemas/ProjectId" }, "enabled": { - "type": "boolean" - }, - "modesAllowed": { - "type": "array", - "minItems": 1, - "maxItems": 50, - "uniqueItems": true, - "items": { - "type": "string", - "enum": [ - "embedded", - "redirect" - ] - } + "type": "boolean", + "description": "Allows QuickLinks to be created for the scope." }, "allowedRedirectUris": { "type": "array", @@ -21118,24 +21464,55 @@ "pattern": "^[Hh][Tt][Tt][Pp][Ss]://", "maxLength": 2048 }, - "description": "Up to 50 exact HTTPS callback URLs without credentials." - }, - "allowedOrigins": { - "type": "array", - "maxItems": 50, - "items": { - "type": "string", - "format": "uri", - "pattern": "^[Hh][Tt][Tt][Pp][Ss]://[^/?#@,]+/?$", - "maxLength": 2048 - }, - "description": "Up to 50 exact HTTPS origins without credentials, paths, queries, fragments, or commas. A trailing root slash is accepted and removed." + "description": "Up to 50 exact HTTPS callback URLs without credentials. A QuickLink callbackUrl must match one of them." }, "businessName": { "type": "string", "maxLength": 120, "nullable": true }, + "headline": { + "type": "string", + "maxLength": 80, + "nullable": true, + "description": "Page title shown above the pairing flow. Defaults to “Connect WhatsApp”." + }, + "description": { + "type": "string", + "maxLength": 280, + "nullable": true, + "description": "Intro sentence shown under the headline." + }, + "successMessage": { + "type": "string", + "maxLength": 280, + "nullable": true, + "description": "Message shown after the number connects." + }, + "supportUrl": { + "type": "string", + "format": "uri", + "pattern": "^[Hh][Tt][Tt][Pp][Ss]://", + "maxLength": 2048, + "nullable": true, + "description": "Help link shown on the page." + }, + "privacyUrl": { + "type": "string", + "format": "uri", + "pattern": "^[Hh][Tt][Tt][Pp][Ss]://", + "maxLength": 2048, + "nullable": true, + "description": "Privacy policy link shown on the consent step." + }, + "termsUrl": { + "type": "string", + "format": "uri", + "pattern": "^[Hh][Tt][Tt][Pp][Ss]://", + "maxLength": 2048, + "nullable": true, + "description": "Terms link shown on the consent step." + }, "accent": { "type": "string", "pattern": "^#[0-9A-Fa-f]{6}$", @@ -21152,25 +21529,13 @@ "hideWatermark": { "type": "boolean" }, - "colors": { - "type": "object", - "additionalProperties": false, - "nullable": true, - "properties": { - "light": { - "$ref": "#/components/schemas/WidgetColorPalette" - }, - "dark": { - "$ref": "#/components/schemas/WidgetColorPalette" - } - } - }, "shape": { "type": "string", "enum": [ "square", "rounded", - "pill" + "pill", + null ], "nullable": true }, @@ -21180,7 +21545,7 @@ "maximum": 999, "nullable": true }, - "qrLogoMode": { + "logoMode": { "type": "string", "enum": [ "none", @@ -21189,11 +21554,11 @@ "project" ] }, - "qrLogoStorageId": { + "logoStorageId": { "type": "string", "nullable": true }, - "qrLogoSourceStorageId": { + "logoSourceStorageId": { "type": "string", "nullable": true }, @@ -21209,16 +21574,26 @@ "type": "array", "nullable": true, "minItems": 1, - "maxItems": 50, + "maxItems": 2, "uniqueItems": true, "items": { "type": "string", "enum": [ "qr", - "pairing", - "cloud-api" + "pairing" ] - } + }, + "description": "Connection methods offered on hosted QuickLink pages." + }, + "defaultMethod": { + "type": "string", + "enum": [ + "qr", + "pairing", + null + ], + "nullable": true, + "description": "Method the page opens first. Unset lets the page choose by device." } } }, @@ -21553,7 +21928,8 @@ "enum": [ "free", "standard", - "pro" + "pro", + null ], "nullable": true } @@ -21896,7 +22272,8 @@ "enum": [ "free", "standard", - "pro" + "pro", + null ], "nullable": true } @@ -21950,7 +22327,8 @@ "free", "standard", "pro", - "scale" + "scale", + null ], "nullable": true }, @@ -22903,7 +23281,8 @@ "superseded", "expired", "not_applied", - "delivery_failed" + "delivery_failed", + null ] } }, @@ -23142,7 +23521,8 @@ "healthy", "limited", "restricted", - "banned" + "banned", + null ], "nullable": true }, @@ -23232,7 +23612,8 @@ "enum": [ "info", "warning", - "critical" + "critical", + null ], "nullable": true }, @@ -23413,7 +23794,8 @@ "healthy", "limited", "restricted", - "banned" + "banned", + null ], "nullable": true }, @@ -23494,7 +23876,8 @@ "enum": [ "history", "link", - "plan" + "plan", + null ], "nullable": true, "description": "Retained evidence anchoring the ramp; null when legacy evidence cannot be classified." @@ -23588,7 +23971,8 @@ "fair", "poor", "failing", - "unknown" + "unknown", + null ], "nullable": true }, @@ -23650,7 +24034,8 @@ "healthy", "limited", "restricted", - "banned" + "banned", + null ], "nullable": true }, @@ -23876,7 +24261,8 @@ "healthy", "limited", "restricted", - "banned" + "banned", + null ], "nullable": true }, @@ -26735,7 +27121,8 @@ "cancelling", "succeeded", "failed", - "cancelled" + "cancelled", + null ], "nullable": true }, diff --git a/contracts/drafts/bansafe/source.json b/contracts/drafts/bansafe/source.json index 2a86a3a..240da1c 100644 --- a/contracts/drafts/bansafe/source.json +++ b/contracts/drafts/bansafe/source.json @@ -1,17 +1,17 @@ { "repository": "polymorfa/polymorfa", - "sourceBaseCommit": "9dded587b159a97038b1e4536e3b6d26d002f434", + "sourceBaseCommit": "77e157729d5f3d630d08c1e13f3aa93449e6065e", "sourceState": "uncommitted-bansafe-draft", "contracts": { "messaging": { "sourcePath": "apps/api/docs/openapi.json", "snapshotPath": "contracts/drafts/bansafe/openapi.messaging.json", - "sha256": "b412ca4506e5920c5b6b61548dfb19c42b9168d5b067558bb55ac1cca64905d5" + "sha256": "1018fc4b096d79ad5bcfa45e7d1c0d46248decdb79348775c6f2b14d346da9c5" }, "platform": { "sourcePath": "apps/api/docs/openapi.management.json", "snapshotPath": "contracts/drafts/bansafe/openapi.platform.json", - "sha256": "9b37273ee85a1ce07d456060d46ce18a70832895f03e20ad83319d053232e0c5" + "sha256": "d529a62ddcc8e5b661b90db7ca9a36dddc30ca48a6a016c4f6b46e0fd471b9df" } } } From 9e175fd3c977528478359da3530ce36134e9fd4f Mon Sep 17 00:00:00 2001 From: Rajeh Taher Date: Tue, 8 Sep 2026 04:30:39 +0300 Subject: [PATCH 4/8] fix(sdk): allow null historical health bands --- packages/typescript/src/platform/types.ts | 3 ++- packages/typescript/test/bansafe.test.ts | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/typescript/src/platform/types.ts b/packages/typescript/src/platform/types.ts index dd7b0c8..bc59824 100644 --- a/packages/typescript/src/platform/types.ts +++ b/packages/typescript/src/platform/types.ts @@ -714,8 +714,9 @@ export interface BanSafeNumberDetail extends BanSafeNumber { export interface BanSafeHealthPoint extends Omit< BanSafeHealthProjection, - "healthEvaluatedAt" + "band" | "healthEvaluatedAt" > { + readonly band: BanSafeHealthBand | null; readonly healthEvaluatedAt: string; } diff --git a/packages/typescript/test/bansafe.test.ts b/packages/typescript/test/bansafe.test.ts index 04aabc3..6ca9d1a 100644 --- a/packages/typescript/test/bansafe.test.ts +++ b/packages/typescript/test/bansafe.test.ts @@ -6,8 +6,10 @@ import { type ApiResponse, type BanSafeCollectionEnvelope, type BanSafeHealthActionsEnvelope, + type BanSafeHealthBand, type BanSafeHealthEnvelope, type BanSafeHealthHistory, + type BanSafeHealthPoint, type BanSafeSignalDefinition, type BanSafeTelemetryDetail, type BanSafeTelemetryHistoryEnvelope, @@ -91,6 +93,9 @@ describe("PlatformClient BanSafe resources", () => { expectTypeOf(history).toEqualTypeOf< ApiResponse> >(); + expectTypeOf< + BanSafeHealthPoint["band"] + >().toEqualTypeOf(); expectTypeOf(signals).toEqualTypeOf< ApiResponse> >(); From 2b8867090f47d69445a22e21ecbb5a17e512d28b Mon Sep 17 00:00:00 2001 From: Rajeh Taher Date: Tue, 8 Sep 2026 08:33:31 +0300 Subject: [PATCH 5/8] fix(sdk): allow incident reports without options --- packages/typescript/src/platform/bansafe.ts | 2 +- packages/typescript/test/bansafe.test.ts | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/packages/typescript/src/platform/bansafe.ts b/packages/typescript/src/platform/bansafe.ts index 951a3fe..87d7918 100644 --- a/packages/typescript/src/platform/bansafe.ts +++ b/packages/typescript/src/platform/bansafe.ts @@ -132,7 +132,7 @@ export class BanSafeResource { createIncident( body: ReportBanSafeIncidentRequest, - options: RequestOptions, + options: RequestOptions = {}, ): Promise>> { return this.transport.request({ method: "POST", diff --git a/packages/typescript/test/bansafe.test.ts b/packages/typescript/test/bansafe.test.ts index 6ca9d1a..4390507 100644 --- a/packages/typescript/test/bansafe.test.ts +++ b/packages/typescript/test/bansafe.test.ts @@ -173,6 +173,19 @@ describe("PlatformClient BanSafe resources", () => { }); }); + it("reports an incident without requiring request options", async () => { + const { client, requests } = await testClient(); + + await client.banSafe.createIncident({ session: "session/a" }); + + expect(requests).toMatchObject([ + { + method: "POST", + path: "/v1/bansafe/incidents", + }, + ]); + }); + it("maps project and session safety settings to their typed owners", async () => { const { client, requests } = await testClient(); await client.projects.getSafeMode("project/a"); From 85435f1160da7cae9b3562f4bc603fc1eed0f45a Mon Sep 17 00:00:00 2001 From: Rajeh Taher Date: Tue, 8 Sep 2026 08:34:52 +0300 Subject: [PATCH 6/8] fix(sdk): preserve incident idempotency requirement --- packages/typescript/src/platform/bansafe.ts | 2 +- packages/typescript/test/bansafe.test.ts | 13 ------------- 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/packages/typescript/src/platform/bansafe.ts b/packages/typescript/src/platform/bansafe.ts index 87d7918..951a3fe 100644 --- a/packages/typescript/src/platform/bansafe.ts +++ b/packages/typescript/src/platform/bansafe.ts @@ -132,7 +132,7 @@ export class BanSafeResource { createIncident( body: ReportBanSafeIncidentRequest, - options: RequestOptions = {}, + options: RequestOptions, ): Promise>> { return this.transport.request({ method: "POST", diff --git a/packages/typescript/test/bansafe.test.ts b/packages/typescript/test/bansafe.test.ts index 4390507..6ca9d1a 100644 --- a/packages/typescript/test/bansafe.test.ts +++ b/packages/typescript/test/bansafe.test.ts @@ -173,19 +173,6 @@ describe("PlatformClient BanSafe resources", () => { }); }); - it("reports an incident without requiring request options", async () => { - const { client, requests } = await testClient(); - - await client.banSafe.createIncident({ session: "session/a" }); - - expect(requests).toMatchObject([ - { - method: "POST", - path: "/v1/bansafe/incidents", - }, - ]); - }); - it("maps project and session safety settings to their typed owners", async () => { const { client, requests } = await testClient(); await client.projects.getSafeMode("project/a"); From f81e7a3e63449637a2c282fd269063dcf521b334 Mon Sep 17 00:00:00 2001 From: Rajeh Taher Date: Wed, 9 Sep 2026 09:16:37 +0300 Subject: [PATCH 7/8] fix(sdk): align BanSafe with platform contracts --- CHANGELOG.md | 5 +- README.md | 8 +- contracts/drafts/bansafe/README.md | 7 +- contracts/drafts/bansafe/coverage.json | 56 +- .../drafts/bansafe/openapi.messaging.json | 14672 +++++++++++++--- .../drafts/bansafe/openapi.platform.json | 691 +- contracts/drafts/bansafe/source.json | 8 +- packages/typescript/README.md | 4 +- packages/typescript/src/platform/bansafe.ts | 30 +- packages/typescript/src/platform/projects.ts | 4 +- packages/typescript/src/transport/http.ts | 11 +- .../typescript/test/bansafe-contract.test.ts | 2 +- packages/typescript/test/bansafe.test.ts | 50 +- packages/typescript/test/business.test.ts | 6 +- .../typescript/test/coverage-issues.test.ts | 7 +- packages/typescript/test/system.test.ts | 7 +- packages/typescript/test/transport.test.ts | 19 +- 17 files changed, 12862 insertions(+), 2725 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b1805f0..859000f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,9 @@ evidence, and Health policy settings. Dashboard-only finding acknowledgement and appeals remain outside the server-key client. +- Aligned public requests with the `/messaging` and `/platform` namespaces. + Typed HTTP errors now preserve the canonical nested error code and message. + - Export typed terminal Calls webhooks. `call.ended` preserves a nullable caller identity for `pod_lost`; `call.telemetry` preserves cumulative traffic values. @@ -109,7 +112,7 @@ and localized through new `calls.*` messages; `pmfa-call` follows the same controller contract. - Refreshed the Messaging and Platform contracts and the coverage ledger for - the `/api/voip/*` signaling routes and the `call.ended` / `call.telemetry` + the `/messaging/voip/*` signaling routes and the `call.ended` / `call.telemetry` webhook events. ## 0.1.0-dev.0 - 2026-08-19 diff --git a/README.md b/README.md index 12ec4a2..c84a65c 100644 --- a/README.md +++ b/README.md @@ -329,14 +329,14 @@ Every client exposes `raw.request()` for deliberate API escape hatches: ```ts const response = await client.raw.request<{ data: unknown }>({ method: "GET", - path: "/v1/operations/operation_123", + path: "/platform/operations/operation_123", query: { projectId: "project_123" }, }); ``` Organization raw paths remain relative API paths. Project raw paths are relative to the bound project and receive the encoded -`/v1/projects/{projectId}` prefix automatically. Project raw requests reject +`/platform/projects/{projectId}` prefix automatically. Project raw requests reject absolute URLs, traversal, explicit project prefixes, backslashes, and `Authorization` overrides before transport. Raw requests retain typed errors, metadata, cancellation, API versions, retry rules, and idempotency. @@ -392,7 +392,7 @@ helpers. ## QuickLink lifecycle and settings `MessagingClient.quickLinks.create()`, `retrieve()`, and `cancel()` map the -authenticated hosted lifecycle at `/api/quicklinks`. They accept organization +authenticated hosted lifecycle at `/messaging/quicklinks`. They accept organization API keys or project tokens with `quicklink:manage`; browser client tokens fail before transport. Organization keys can set `projectId` on creation, while a project token remains bound by the server. @@ -401,7 +401,7 @@ These methods expose the short-lived connection URL and status record. They do not add list, recovery, or history operations that the API does not provide. `client.quickLinkSettings.retrieve()` and `update()` map only the management -`GET /v1/quicklink` and `PUT /v1/quicklink` settings contract. The same methods +`GET /platform/quicklink` and `PUT /platform/quicklink` settings contract. The same methods on `client.project(projectId)` use the immutable project ownership context. ## Browser controllers and UI diff --git a/contracts/drafts/bansafe/README.md b/contracts/drafts/bansafe/README.md index 6101625..7b1d043 100644 --- a/contracts/drafts/bansafe/README.md +++ b/contracts/drafts/bansafe/README.md @@ -1,9 +1,8 @@ # BanSafe draft contracts -These files are byte-identical copies of the BanSafe implementation worktree -specs at the hashes recorded in `source.json`. The source tree contains -uncommitted API work on top of `sourceBaseCommit`, so these snapshots do not -claim a merged Polymorfa source revision or published SDK parity. +These files are byte-identical copies of the BanSafe API pull request specs at +the commit and hashes recorded in `source.json`. These snapshots do not claim a +merged Polymorfa source revision or published SDK parity. The canonical files under `contracts/` and their coverage ledger stay pinned to the last merged source revision. Replace that pin only after the API changes diff --git a/contracts/drafts/bansafe/coverage.json b/contracts/drafts/bansafe/coverage.json index 370a294..d3aa787 100644 --- a/contracts/drafts/bansafe/coverage.json +++ b/contracts/drafts/bansafe/coverage.json @@ -1,6 +1,6 @@ { "schemaVersion": 1, - "platformSha256": "d529a62ddcc8e5b661b90db7ca9a36dddc30ca48a6a016c4f6b46e0fd471b9df", + "platformSha256": "a7f9d3b449aa93ebdf1e52c5c04519dd405d963a2da59db85d43748f671c95bf", "scope": "OpenAPI operations tagged bansafe", "covered": 25, "excluded": 2, @@ -9,189 +9,189 @@ { "operationId": "listBanSafeHealth", "method": "GET", - "path": "/v1/bansafe/health", + "path": "/platform/bansafe/health", "status": "covered", "sdkPath": "Client.banSafe.listHealth" }, { "operationId": "getBanSafeHealth", "method": "GET", - "path": "/v1/bansafe/health/{session}", + "path": "/platform/bansafe/health/{session}", "status": "covered", "sdkPath": "Client.banSafe.getHealth" }, { "operationId": "listBanSafeHealthHistory", "method": "GET", - "path": "/v1/bansafe/health/{session}/history", + "path": "/platform/bansafe/health/{session}/history", "status": "covered", "sdkPath": "Client.banSafe.listHealthHistory" }, { "operationId": "listBanSafeSignals", "method": "GET", - "path": "/v1/bansafe/signals", + "path": "/platform/bansafe/signals", "status": "covered", "sdkPath": "Client.banSafe.listSignals" }, { "operationId": "getBanSafeTelemetry", "method": "GET", - "path": "/v1/bansafe/telemetry/{session}", + "path": "/platform/bansafe/telemetry/{session}", "status": "covered", "sdkPath": "Client.banSafe.getTelemetry" }, { "operationId": "listBanSafeTelemetryHistory", "method": "GET", - "path": "/v1/bansafe/telemetry/{session}/history", + "path": "/platform/bansafe/telemetry/{session}/history", "status": "covered", "sdkPath": "Client.banSafe.listTelemetryHistory" }, { "operationId": "listBanSafeCollection", "method": "GET", - "path": "/v1/bansafe/collection", + "path": "/platform/bansafe/collection", "status": "covered", "sdkPath": "Client.banSafe.listCollection" }, { "operationId": "listBanSafeHealthActions", "method": "GET", - "path": "/v1/bansafe/health-actions", + "path": "/platform/bansafe/health-actions", "status": "covered", "sdkPath": "Client.banSafe.listHealthActions" }, { "operationId": "listBanSafeFindings", "method": "GET", - "path": "/v1/bansafe/findings", + "path": "/platform/bansafe/findings", "status": "covered", "sdkPath": "Client.banSafe.listFindings" }, { "operationId": "acknowledgeBanSafeFinding", "method": "POST", - "path": "/v1/bansafe/findings/{findingId}/acknowledge", + "path": "/platform/bansafe/findings/{findingId}/acknowledge", "status": "excluded", "reason": "Requires signed-in dashboard identity; server API keys and project tokens are refused." }, { "operationId": "listBanSafeEnforcement", "method": "GET", - "path": "/v1/bansafe/enforcement", + "path": "/platform/bansafe/enforcement", "status": "covered", "sdkPath": "Client.banSafe.listEnforcement" }, { "operationId": "appealBanSafeEnforcement", "method": "POST", - "path": "/v1/bansafe/enforcement/{session}/appeal", + "path": "/platform/bansafe/enforcement/{session}/appeal", "status": "excluded", "reason": "Requires signed-in dashboard identity; server API keys and project tokens are refused." }, { "operationId": "listBanSafeIncidents", "method": "GET", - "path": "/v1/bansafe/incidents", + "path": "/platform/bansafe/incidents", "status": "covered", "sdkPath": "Client.banSafe.listIncidents" }, { "operationId": "createBanSafeIncident", "method": "POST", - "path": "/v1/bansafe/incidents", + "path": "/platform/bansafe/incidents", "status": "covered", "sdkPath": "Client.banSafe.createIncident" }, { "operationId": "retractBanSafeIncident", "method": "POST", - "path": "/v1/bansafe/incidents/{incidentId}/retract", + "path": "/platform/bansafe/incidents/{incidentId}/retract", "status": "covered", "sdkPath": "Client.banSafe.retractIncident" }, { "operationId": "listBanSafeClaims", "method": "GET", - "path": "/v1/bansafe/claims", + "path": "/platform/bansafe/claims", "status": "covered", "sdkPath": "Client.banSafe.listClaims" }, { "operationId": "getBanSafeClaim", "method": "GET", - "path": "/v1/bansafe/claims/{claimId}", + "path": "/platform/bansafe/claims/{claimId}", "status": "covered", "sdkPath": "Client.banSafe.getClaim" }, { "operationId": "getProjectSafeModeCeiling", "method": "GET", - "path": "/v1/projects/{projectId}/safe-mode", + "path": "/platform/projects/{projectId}/safe-mode", "status": "covered", "sdkPath": "Client.projects.getSafeMode" }, { "operationId": "updateProjectSafeModeCeiling", "method": "PUT", - "path": "/v1/projects/{projectId}/safe-mode", + "path": "/platform/projects/{projectId}/safe-mode", "status": "covered", "sdkPath": "Client.projects.updateSafeMode" }, { "operationId": "getNumberSafeMode", "method": "GET", - "path": "/v1/sessions/{sessionId}/safe-mode", + "path": "/platform/sessions/{sessionId}/safe-mode", "status": "covered", "sdkPath": "Client.sessions.getSafeMode" }, { "operationId": "updateNumberSafeMode", "method": "PUT", - "path": "/v1/sessions/{sessionId}/safe-mode", + "path": "/platform/sessions/{sessionId}/safe-mode", "status": "covered", "sdkPath": "Client.sessions.updateSafeMode" }, { "operationId": "getProjectWarmupPlanSettings", "method": "GET", - "path": "/v1/projects/{projectId}/warmup-plan", + "path": "/platform/projects/{projectId}/warmup-plan", "status": "covered", "sdkPath": "Client.projects.getWarmupPlan" }, { "operationId": "updateProjectWarmupPlanSettings", "method": "PUT", - "path": "/v1/projects/{projectId}/warmup-plan", + "path": "/platform/projects/{projectId}/warmup-plan", "status": "covered", "sdkPath": "Client.projects.updateWarmupPlan" }, { "operationId": "getProjectHealthPolicySettings", "method": "GET", - "path": "/v1/projects/{projectId}/health-policy", + "path": "/platform/projects/{projectId}/health-policy", "status": "covered", "sdkPath": "Client.projects.getHealthPolicy" }, { "operationId": "updateProjectHealthPolicySettings", "method": "PUT", - "path": "/v1/projects/{projectId}/health-policy", + "path": "/platform/projects/{projectId}/health-policy", "status": "covered", "sdkPath": "Client.projects.updateHealthPolicy" }, { "operationId": "getInsuranceEvidenceSettings", "method": "GET", - "path": "/v1/projects/{projectId}/insurance-evidence", + "path": "/platform/projects/{projectId}/insurance-evidence", "status": "covered", "sdkPath": "Client.projects.getInsuranceEvidence" }, { "operationId": "updateInsuranceEvidenceSettings", "method": "PUT", - "path": "/v1/projects/{projectId}/insurance-evidence", + "path": "/platform/projects/{projectId}/insurance-evidence", "status": "covered", "sdkPath": "Client.projects.updateInsuranceEvidence" } diff --git a/contracts/drafts/bansafe/openapi.messaging.json b/contracts/drafts/bansafe/openapi.messaging.json index 781745f..c953c56 100644 --- a/contracts/drafts/bansafe/openapi.messaging.json +++ b/contracts/drafts/bansafe/openapi.messaging.json @@ -21,7 +21,7 @@ ], "components": { "schemas": { - "JIDRef": { + "ConversationRef": { "type": "object", "properties": { "id": { @@ -33,22 +33,21 @@ "username": { "type": "string" }, - "lid": { - "type": "string", - "deprecated": true - }, - "mode": { - "type": "string", - "enum": [ - "pn", - "lid" - ], - "deprecated": true + "sender": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "phoneNumber": { + "type": "string" + }, + "username": { + "type": "string" + } + } } - }, - "required": [ - "id" - ] + } }, "PollOption": { "type": "object", @@ -71,11 +70,8 @@ "id": { "type": "string" }, - "from": { - "$ref": "#/components/schemas/JIDRef" - }, - "sender": { - "$ref": "#/components/schemas/JIDRef" + "conversation": { + "$ref": "#/components/schemas/ConversationRef" }, "fromMe": { "type": "boolean" @@ -191,8 +187,7 @@ }, "required": [ "id", - "from", - "sender", + "conversation", "fromMe", "timestamp", "pushName", @@ -206,9 +201,8 @@ "messageId": { "type": "string" }, - "from": { - "type": "string", - "description": "Meta wa_id. This is not a LID-backed user ID." + "conversation": { + "$ref": "#/components/schemas/ConversationRef" }, "timestamp": { "type": "string" @@ -249,7 +243,7 @@ }, "required": [ "messageId", - "from", + "conversation", "timestamp", "type" ] @@ -304,25 +298,21 @@ "id": { "type": "string" }, - "from": { - "$ref": "#/components/schemas/JIDRef" + "conversation": { + "$ref": "#/components/schemas/ConversationRef" }, "type": { "type": "string" }, "timestamp": { "type": "number" - }, - "sender": { - "$ref": "#/components/schemas/JIDRef" } }, "required": [ "id", - "from", + "conversation", "type", - "timestamp", - "sender" + "timestamp" ] }, "MessageSentEvent": { @@ -359,6 +349,23 @@ "payload" ] }, + "IdentityRef": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "phoneNumber": { + "type": "string" + }, + "username": { + "type": "string" + } + }, + "required": [ + "id" + ] + }, "MessageAckPayload": { "type": "object", "properties": { @@ -369,10 +376,10 @@ } }, "from": { - "$ref": "#/components/schemas/JIDRef" + "$ref": "#/components/schemas/IdentityRef" }, "sender": { - "$ref": "#/components/schemas/JIDRef" + "$ref": "#/components/schemas/IdentityRef" }, "type": { "type": "string", @@ -564,10 +571,10 @@ "type": "object", "properties": { "from": { - "$ref": "#/components/schemas/JIDRef" + "$ref": "#/components/schemas/IdentityRef" }, "sender": { - "$ref": "#/components/schemas/JIDRef" + "$ref": "#/components/schemas/IdentityRef" }, "messageId": { "type": "string" @@ -624,7 +631,7 @@ "type": "string" }, "voter": { - "$ref": "#/components/schemas/JIDRef" + "$ref": "#/components/schemas/IdentityRef" }, "selectedHashes": { "type": "array", @@ -750,58 +757,13 @@ "payload" ] }, - "SessionQRPayload": { - "type": "object", - "properties": { - "code": { - "type": "string" - } - }, - "required": [ - "code" - ] - }, - "SessionQREvent": { - "type": "object", - "properties": { - "id": { - "type": "string", - "description": "Unique event identifier" - }, - "session": { - "type": "string", - "description": "Session that produced this event" - }, - "timestamp": { - "type": "string", - "description": "ISO 8601 timestamp" - }, - "event": { - "type": "string", - "enum": [ - "session.qr" - ], - "description": "Event type" - }, - "payload": { - "$ref": "#/components/schemas/SessionQRPayload" - } - }, - "required": [ - "id", - "session", - "timestamp", - "event", - "payload" - ] - }, "SessionConnectedPayload": { "type": "object", "properties": { "phoneNumber": { "type": "string" }, - "lid": { + "id": { "type": "string" }, "pushName": { @@ -1027,25 +989,25 @@ "joined": { "type": "array", "items": { - "$ref": "#/components/schemas/JIDRef" + "$ref": "#/components/schemas/IdentityRef" } }, "left": { "type": "array", "items": { - "$ref": "#/components/schemas/JIDRef" + "$ref": "#/components/schemas/IdentityRef" } }, "promoted": { "type": "array", "items": { - "$ref": "#/components/schemas/JIDRef" + "$ref": "#/components/schemas/IdentityRef" } }, "demoted": { "type": "array", "items": { - "$ref": "#/components/schemas/JIDRef" + "$ref": "#/components/schemas/IdentityRef" } } }, @@ -1094,10 +1056,10 @@ "type": "integer" }, "from": { - "$ref": "#/components/schemas/JIDRef" + "$ref": "#/components/schemas/IdentityRef" }, "sender": { - "$ref": "#/components/schemas/JIDRef" + "$ref": "#/components/schemas/IdentityRef" }, "state": { "type": "string" @@ -1156,10 +1118,6 @@ "id": { "type": "string" }, - "lid": { - "type": "string", - "deprecated": true - }, "phoneNumber": { "type": "string" }, @@ -1233,7 +1191,7 @@ "type": "object", "properties": { "from": { - "$ref": "#/components/schemas/JIDRef" + "$ref": "#/components/schemas/IdentityRef" }, "archive": { "type": "boolean" @@ -1284,7 +1242,7 @@ "type": "object", "properties": { "from": { - "$ref": "#/components/schemas/JIDRef" + "$ref": "#/components/schemas/IdentityRef" }, "muted": { "type": "boolean" @@ -1336,7 +1294,7 @@ "type": "object", "properties": { "from": { - "$ref": "#/components/schemas/JIDRef" + "$ref": "#/components/schemas/IdentityRef" }, "read": { "type": "boolean" @@ -1385,7 +1343,7 @@ "type": "object", "properties": { "from": { - "$ref": "#/components/schemas/JIDRef" + "$ref": "#/components/schemas/IdentityRef" } }, "required": [ @@ -1430,7 +1388,7 @@ "type": "object", "properties": { "from": { - "$ref": "#/components/schemas/JIDRef" + "$ref": "#/components/schemas/IdentityRef" } }, "required": [ @@ -1475,7 +1433,7 @@ "type": "object", "properties": { "from": { - "$ref": "#/components/schemas/JIDRef" + "$ref": "#/components/schemas/IdentityRef" }, "callId": { "type": "string" @@ -1530,7 +1488,7 @@ "type": "object", "properties": { "from": { - "$ref": "#/components/schemas/JIDRef" + "$ref": "#/components/schemas/IdentityRef" }, "callId": { "type": "string" @@ -1583,7 +1541,7 @@ "type": "object", "properties": { "from": { - "$ref": "#/components/schemas/JIDRef" + "$ref": "#/components/schemas/IdentityRef" }, "callId": { "type": "string" @@ -1632,7 +1590,7 @@ "type": "object", "properties": { "from": { - "$ref": "#/components/schemas/JIDRef" + "$ref": "#/components/schemas/IdentityRef" }, "callId": { "type": "string" @@ -1692,18 +1650,6 @@ }, "username": { "type": "string" - }, - "lid": { - "type": "string", - "deprecated": true - }, - "mode": { - "type": "string", - "enum": [ - "pn", - "lid" - ], - "deprecated": true } }, "required": [ @@ -2120,10 +2066,6 @@ "id": { "type": "string" }, - "lid": { - "type": "string", - "deprecated": true - }, "phoneNumber": { "type": "string" }, @@ -2206,7 +2148,7 @@ "from": { "allOf": [ { - "$ref": "#/components/schemas/JIDRef" + "$ref": "#/components/schemas/IdentityRef" }, { "description": "Chat the label action applies to" @@ -4556,7 +4498,7 @@ "to": { "allOf": [ { - "$ref": "#/components/schemas/JIDRef" + "$ref": "#/components/schemas/IdentityRef" }, { "description": "Recipient chat the send was attempted to" @@ -5692,89 +5634,21 @@ "enabled" ] }, - "Operation": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "uuid" - }, - "kind": { - "type": "string" - }, - "resourceType": { - "type": "string" - }, - "resourceId": { - "type": "string" - }, - "projectId": { - "type": "string", - "nullable": true, - "format": "uuid" - }, - "status": { - "type": "string", - "enum": [ - "pending", - "running", - "action_required", - "cancelling", - "succeeded", - "failed", - "cancelled" - ] - }, - "progressCode": { - "type": "string", - "nullable": true - }, - "failureCode": { - "type": "string", - "nullable": true - }, - "createdAt": { - "type": "string", - "format": "date-time" - }, - "updatedAt": { - "type": "string", - "format": "date-time" - }, - "completedAt": { - "type": "string", - "nullable": true, - "format": "date-time" - } - }, - "required": [ - "id", - "kind", - "resourceType", - "resourceId", - "projectId", - "status", - "progressCode", - "failureCode", - "createdAt", - "updatedAt", - "completedAt" - ] - }, "Session": { "type": "object", "properties": { "sessionId": { "type": "string", - "description": "Canonical per-org session identifier. Use this in /api/sessions/{session}/* paths." + "description": "Canonical per-org session identifier. Use this in /messaging/sessions/{session}/* paths." }, "name": { - "type": "string" + "type": "string", + "description": "Display label, or the session identifier when no label is set." }, "tenantId": { "type": "string" }, - "connection": { + "type": { "type": "string", "enum": [ "linked_device", @@ -5793,15 +5667,29 @@ "statusReason": { "type": "string" }, - "runnerId": { - "type": "string" - }, - "proxy": { - "type": "string" - }, "config": { "type": "object", - "additionalProperties": {} + "properties": { + "historySync": { + "type": "object", + "properties": { + "mode": { + "type": "string", + "enum": [ + "metadata_only", + "deliver" + ] + }, + "requestFull": { + "type": "boolean" + } + }, + "required": [ + "mode", + "requestFull" + ] + } + } }, "createdAt": { "type": "string" @@ -5811,9 +5699,10 @@ } }, "required": [ + "sessionId", "name", "tenantId", - "connection", + "type", "testMode", "status", "config", @@ -5849,12 +5738,7 @@ }, { "type": "object", - "properties": { - "operationId": { - "type": "string", - "format": "uuid" - } - } + "properties": {} } ] }, @@ -5915,7 +5799,7 @@ "systemUserToken", "webhookVerifyToken" ], - "description": "Meta credentials. Required when connection='cloud_api'. Encrypted at rest before storage." + "description": "Credentials required when type is cloud_api. Stored encrypted." }, "HistorySyncPolicy": { "type": "object", @@ -5933,64 +5817,53 @@ "default": false } }, + "additionalProperties": false, + "description": "History processing for linked-device sessions. Defaults to metadata-only processing." + }, + "SessionConfig": { + "type": "object", + "properties": { + "historySync": { + "$ref": "#/components/schemas/HistorySyncPolicy" + } + }, "additionalProperties": false }, "CreateSessionRequest": { "type": "object", "properties": { - "projectId": { - "type": "string", - "minLength": 1, - "description": "Project id the session belongs to. Required." - }, - "sessionId": { - "type": "string", - "minLength": 1, - "description": "Canonical per-org session identifier (1-64 alphanumeric chars, dots, hyphens, underscores). Caller-supplied or generated; returned in the response. This is the id used in all /api/sessions/{session}/* paths." - }, "name": { "type": "string", "minLength": 1, - "description": "Optional human-friendly label for the session. Not an id." + "description": "Optional display label. The server generates the session identifier." }, - "start": { - "type": "boolean" + "startOnConnect": { + "type": "boolean", + "default": false, + "description": "Start connecting immediately after creation. Pairing or credentials are still required." }, - "connection": { + "type": { "type": "string", "enum": [ "linked_device", "cloud_api" ], - "description": "How the session connects to WhatsApp. 'linked_device' (default) pairs as a WhatsApp linked device; 'cloud_api' uses the Meta Cloud API and requires the `cloudApi` creds block. Immutable after create." + "default": "linked_device", + "description": "Connection type. Immutable after creation." }, "testMode": { "type": "boolean", - "description": "Create a simulated testing number (behaves like a real session via the simulated universe). Defaults to false." - }, - "bartenderMode": { - "type": "string", - "enum": [ - "magic", - "passthrough", - "passthrough_plus" - ], - "description": "Bartender privacy tier. Defaults to 'magic'. Mutable via the handoff ceremony at POST /api/sessions/{name}/handoff-keys + /handoff-import. 'magic' — Polymorfa holds the Signal session; full message visibility. 'passthrough' — Polymorfa holds noise creds only; neither messages nor app state are decryptable on Polymorfa's side. 'passthrough_plus' — Track P + customer has uploaded AppStateSyncKeys for selected collections (contacts, labels, mute/archive, blocklist), so Polymorfa sees metadata mutations but never message content." + "default": false, + "description": "Create a simulated testing session." }, "cloudApi": { "$ref": "#/components/schemas/CloudApiCredentials" }, "config": { - "type": "object", - "additionalProperties": true - }, - "historySync": { - "$ref": "#/components/schemas/HistorySyncPolicy" + "$ref": "#/components/schemas/SessionConfig" } }, - "required": [ - "projectId" - ] + "additionalProperties": false }, "GetSessionResponse": { "type": "object", @@ -6052,10 +5925,6 @@ "message": { "type": "string" }, - "operationId": { - "type": "string", - "format": "uuid" - }, "immediate": { "type": "boolean" } @@ -6068,8 +5937,9 @@ "WhatsAppAccount": { "type": "object", "properties": { - "lid": { - "type": "string" + "id": { + "type": "string", + "description": "Stable account ID when supplied by the connection." }, "phoneNumber": { "type": "string" @@ -6088,7 +5958,6 @@ } }, "required": [ - "lid", "pushName" ] }, @@ -6353,43 +6222,70 @@ "phone" ] }, - "MessageResponse": { + "ConversationIdentifier": { "type": "object", "properties": { "id": { "type": "string", - "description": "WhatsApp message ID" + "description": "Stable conversation ID. Linked Device users use pmfa_lid_, groups use pmfa_gid_, bots use pmfa_botid_, and Cloud users use their business-scoped ID.", + "example": "pmfa_lid_123456789" + }, + "phoneNumber": { + "type": "string", + "pattern": "^\\+[1-9]\\d{1,14}$", + "description": "E.164 phone number. Supply it alone or alongside id; id selects the conversation when both are present.", + "example": "+15550001111" + } + }, + "additionalProperties": false, + "description": "ConversationIdentifier identified by an ID, an E.164 phone number, or both. At least one is required. When both are supplied, the ID selects the conversation and phoneNumber is an alias. User IDs use pmfa_lid_, group IDs use pmfa_gid_, and bot IDs use pmfa_botid_. Cloud API user IDs are business-scoped.", + "anyOf": [ + { + "required": [ + "id" + ] + }, + { + "required": [ + "phoneNumber" + ] + } + ] + }, + "SentMessage": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "conversation": { + "$ref": "#/components/schemas/ConversationIdentifier" }, "timestamp": { "type": "string", - "description": "ISO 8601 send timestamp" + "format": "date-time" }, "status": { "type": "string", - "description": "Delivery status: pending, sent, delivered, read" + "description": "Upstream acceptance status. Delivery and read receipts arrive separately." }, - "mediaId": { - "type": "string" - }, - "senderLid": { - "type": "string" - }, - "senderPhoneNumber": { + "type": { "type": "string" }, - "fromLid": { - "type": "string" + "content": { + "$ref": "#/components/schemas/MessageContent" }, - "fromPhoneNumber": { + "mediaId": { "type": "string" } }, "required": [ "id", + "conversation", "timestamp", "status", - "senderLid", - "fromLid" + "type", + "content" ] }, "SendMessageResponse": { @@ -6402,7 +6298,7 @@ ] }, "data": { - "$ref": "#/components/schemas/MessageResponse" + "$ref": "#/components/schemas/SentMessage" } }, "required": [ @@ -6410,702 +6306,1105 @@ "data" ] }, - "QuotedMessage": { + "AsyncAcceptedResponse": { "type": "object", "properties": { - "messageId": { - "type": "string" - }, - "participant": { - "type": "string" - }, - "type": { - "type": "string" + "success": { + "type": "boolean", + "enum": [ + true + ] }, - "text": { - "type": "string" + "data": { + "type": "object", + "properties": { + "requestId": { + "type": "string", + "format": "uuid" + } + }, + "required": [ + "requestId" + ] } }, "required": [ - "messageId", - "participant" + "success", + "data" ] }, - "SendMessageRequest": { + "PublicError": { "type": "object", "properties": { - "chatId": { - "type": "string", - "minLength": 1 + "error": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "invalid_request_error", + "authentication_error", + "permission_error", + "conflict_error", + "rate_limit_error", + "api_error", + "upstream_error" + ] + }, + "code": { + "type": "string", + "enum": [ + "invalid_parameter", + "invalid_credential", + "entitlement_required", + "method_not_allowed", + "permission_denied", + "missing_scope", + "resource_not_found", + "media_fetch_failed", + "resource_gone", + "state_conflict", + "rate_limit_exceeded", + "internal_error", + "operation_not_supported", + "upstream_failure", + "service_unavailable", + "credential_verification_unavailable", + "session_not_ready", + "command_dispatch_failed", + "result_unknown" + ] + }, + "message": { + "type": "string" + }, + "param": { + "type": "string", + "nullable": true + } + }, + "required": [ + "type", + "code", + "message", + "param" + ] }, - "type": { + "data": { "type": "string", + "nullable": true, "enum": [ - "text", - "image", - "file", - "voice", - "video", - "poll", - "location", - "contact", - "request_phone_number", - "product", - "product_list", - "order", - "list", - "buttons", - "address_message", - "flow" - ] - }, - "text": { - "type": "string" - }, - "url": { - "type": "string" - }, - "base64": { - "type": "string" + null + ], + "description": "Always null for a failed request." }, - "mimeType": { + "docs": { + "type": "string", + "format": "uri" + } + }, + "required": [ + "error", + "data", + "docs" + ] + }, + "QuotedMessage": { + "type": "object", + "properties": { + "messageId": { "type": "string" }, - "filename": { + "participant": { "type": "string" }, - "caption": { + "type": { "type": "string" }, - "ptt": { - "type": "boolean" - }, - "pollTitle": { + "text": { "type": "string" + } + }, + "required": [ + "messageId", + "participant" + ], + "description": "Message being replied to." + }, + "MessageContent": { + "description": "Exactly one message kind: text, image, location, or another supported content field.", + "oneOf": [ + { + "type": "object", + "properties": { + "text": { + "type": "string", + "minLength": 1, + "description": "Text to send." + } + }, + "required": [ + "text" + ], + "additionalProperties": false }, - "pollOptions": { - "type": "array", - "items": { - "type": "string" - } - }, - "pollMultiSelect": { - "type": "boolean" - }, - "latitude": { - "type": "number" - }, - "longitude": { - "type": "number" + { + "type": "object", + "properties": { + "image": { + "type": "object", + "properties": { + "url": { + "type": "string", + "format": "uri", + "description": "URL of the media to send. Specify this or base64." + }, + "base64": { + "type": "string", + "minLength": 1, + "description": "Base64-encoded media bytes. Specify this or url." + }, + "mimeType": { + "type": "string", + "description": "MIME type of the media." + }, + "caption": { + "type": "string", + "description": "Caption sent with the media." + } + }, + "additionalProperties": false + } + }, + "required": [ + "image" + ], + "additionalProperties": false }, - "address": { - "type": "string" + { + "type": "object", + "properties": { + "video": { + "type": "object", + "properties": { + "url": { + "type": "string", + "format": "uri", + "description": "URL of the media to send. Specify this or base64." + }, + "base64": { + "type": "string", + "minLength": 1, + "description": "Base64-encoded media bytes. Specify this or url." + }, + "mimeType": { + "type": "string", + "description": "MIME type of the media." + }, + "caption": { + "type": "string", + "description": "Caption sent with the media." + } + }, + "additionalProperties": false + } + }, + "required": [ + "video" + ], + "additionalProperties": false }, - "vcard": { - "type": "string" + { + "type": "object", + "properties": { + "file": { + "type": "object", + "properties": { + "url": { + "type": "string", + "format": "uri", + "description": "URL of the media to send. Specify this or base64." + }, + "base64": { + "type": "string", + "minLength": 1, + "description": "Base64-encoded media bytes. Specify this or url." + }, + "mimeType": { + "type": "string", + "description": "MIME type of the media." + }, + "caption": { + "type": "string", + "description": "Caption sent with the media." + }, + "filename": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "required": [ + "file" + ], + "additionalProperties": false }, - "product": { + { "type": "object", "properties": { - "businessOwnerJid": { - "type": "string", - "pattern": "^\\d+@s\\.whatsapp\\.net$" - }, - "id": { - "type": "string", - "minLength": 1 - }, - "title": { - "type": "string", - "minLength": 1 - }, - "description": { - "type": "string", - "minLength": 0 - }, - "currencyCode": { - "type": "string", - "pattern": "^[A-Z]{3}$" - }, - "priceAmount1000": { - "type": "integer", - "minimum": 0, - "maximum": 9007199254740991 - }, - "salePriceAmount1000": { - "type": "integer", - "minimum": 0, - "maximum": 9007199254740991 - }, - "retailerId": { - "type": "string", - "minLength": 0 - }, - "url": { - "type": "string", - "maxLength": 2048, - "format": "uri" - }, - "imageCount": { - "type": "integer", - "minimum": 0, - "maximum": 100 - }, - "image": { + "voice": { "type": "object", "properties": { "url": { "type": "string", - "maxLength": 4096, - "format": "uri" + "format": "uri", + "description": "URL of the media to send. Specify this or base64." }, "base64": { "type": "string", - "maxLength": 87384 + "minLength": 1, + "description": "Base64-encoded media bytes. Specify this or url." }, "mimeType": { "type": "string", - "minLength": 0 + "description": "MIME type of the media." + }, + "caption": { + "type": "string", + "description": "Caption sent with the media." + }, + "ptt": { + "type": "boolean" } - } - }, - "body": { - "type": "string", - "minLength": 0 - }, - "footer": { - "type": "string", - "minLength": 0 + }, + "additionalProperties": false } }, "required": [ - "businessOwnerJid", - "id", - "title", - "currencyCode", - "priceAmount1000" - ] + "voice" + ], + "additionalProperties": false }, - "productList": { + { "type": "object", "properties": { - "businessOwnerJid": { - "type": "string", - "pattern": "^\\d+@s\\.whatsapp\\.net$" - }, - "title": { - "type": "string", - "minLength": 1 - }, - "description": { - "type": "string", - "minLength": 0 - }, - "buttonText": { - "type": "string", - "minLength": 1 - }, - "footer": { - "type": "string", - "minLength": 0 - }, - "sections": { - "type": "array", - "items": { - "type": "object", - "properties": { - "title": { + "location": { + "type": "object", + "properties": { + "lat": { + "type": "number", + "minimum": -90, + "maximum": 90, + "description": "Latitude in decimal degrees." + }, + "long": { + "type": "number", + "minimum": -180, + "maximum": 180, + "description": "Longitude in decimal degrees." + }, + "address": { + "type": "string", + "description": "Display address for the location." + } + }, + "required": [ + "lat", + "long" + ], + "additionalProperties": false + } + }, + "required": [ + "location" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "poll": { + "type": "object", + "properties": { + "title": { + "type": "string", + "minLength": 1 + }, + "options": { + "type": "array", + "items": { "type": "string", - "minLength": 0 + "minLength": 1 }, - "productIds": { - "type": "array", - "items": { - "type": "string", - "minLength": 1 - }, - "minItems": 1, - "maxItems": 30 - } + "minItems": 2 }, - "required": [ - "productIds" - ] + "multiSelect": { + "type": "boolean" + } }, - "minItems": 1, - "maxItems": 10 + "required": [ + "title", + "options" + ], + "additionalProperties": false } }, "required": [ - "businessOwnerJid", - "title", - "buttonText", - "sections" - ] + "poll" + ], + "additionalProperties": false }, - "order": { + { "type": "object", "properties": { - "id": { - "type": "string", - "minLength": 1 - }, - "thumbnailBase64": { - "type": "string", - "maxLength": 87384 - }, - "itemCount": { - "type": "integer", - "minimum": 1, - "maximum": 100 - }, - "status": { - "type": "string", - "enum": [ - "inquiry", - "accepted", - "declined" + "contact": { + "type": "object", + "properties": { + "vcard": { + "type": "string", + "minLength": 1 + } + }, + "required": [ + "vcard" + ], + "additionalProperties": false + } + }, + "required": [ + "contact" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "requestPhoneNumber": { + "type": "object", + "properties": {}, + "additionalProperties": false + } + }, + "required": [ + "requestPhoneNumber" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "product": { + "type": "object", + "properties": { + "businessOwnerJid": { + "type": "string", + "pattern": "^\\d+@s\\.whatsapp\\.net$" + }, + "id": { + "type": "string", + "minLength": 1 + }, + "title": { + "type": "string", + "minLength": 1 + }, + "description": { + "type": "string", + "minLength": 0 + }, + "currencyCode": { + "type": "string", + "pattern": "^[A-Z]{3}$" + }, + "priceAmount1000": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "salePriceAmount1000": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "retailerId": { + "type": "string", + "minLength": 0 + }, + "url": { + "type": "string", + "maxLength": 2048, + "format": "uri" + }, + "imageCount": { + "type": "integer", + "minimum": 0, + "maximum": 100 + }, + "image": { + "type": "object", + "properties": { + "url": { + "type": "string", + "maxLength": 4096, + "format": "uri" + }, + "base64": { + "type": "string", + "maxLength": 87384 + }, + "mimeType": { + "type": "string", + "minLength": 0 + } + } + }, + "body": { + "type": "string", + "minLength": 0 + }, + "footer": { + "type": "string", + "minLength": 0 + } + }, + "required": [ + "businessOwnerJid", + "id", + "title", + "currencyCode", + "priceAmount1000" ] - }, - "message": { - "type": "string", - "minLength": 0 - }, - "title": { - "type": "string", - "minLength": 0 - }, - "sellerJid": { - "type": "string", - "pattern": "^\\d+@s\\.whatsapp\\.net$" - }, - "token": { - "type": "string", - "minLength": 0 - }, - "totalAmount1000": { - "type": "integer", - "minimum": 0, - "maximum": 9007199254740991 - }, - "totalCurrencyCode": { - "type": "string", - "pattern": "^[A-Z]{3}$" - }, - "catalogType": { - "type": "string", - "minLength": 0 } }, "required": [ - "id", - "itemCount", - "status", - "sellerJid", - "totalAmount1000", - "totalCurrencyCode" - ] + "product" + ], + "additionalProperties": false }, - "list": { + { "type": "object", "properties": { - "title": { - "type": "string", - "minLength": 1 - }, - "description": { - "type": "string", - "minLength": 0 - }, - "buttonText": { - "type": "string", - "minLength": 1 - }, - "footer": { - "type": "string", - "minLength": 0 - }, - "sections": { - "type": "array", - "items": { - "type": "object", - "properties": { - "title": { - "type": "string", - "minLength": 0 - }, - "rows": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { - "type": "string", - "minLength": 1 - }, - "title": { + "productList": { + "type": "object", + "properties": { + "businessOwnerJid": { + "type": "string", + "pattern": "^\\d+@s\\.whatsapp\\.net$" + }, + "title": { + "type": "string", + "minLength": 1 + }, + "description": { + "type": "string", + "minLength": 0 + }, + "buttonText": { + "type": "string", + "minLength": 1 + }, + "footer": { + "type": "string", + "minLength": 0 + }, + "sections": { + "type": "array", + "items": { + "type": "object", + "properties": { + "title": { + "type": "string", + "minLength": 0 + }, + "productIds": { + "type": "array", + "items": { "type": "string", "minLength": 1 }, - "description": { - "type": "string", - "minLength": 0 - } + "minItems": 1, + "maxItems": 30 + } + }, + "required": [ + "productIds" + ] + }, + "minItems": 1, + "maxItems": 10 + } + }, + "required": [ + "businessOwnerJid", + "title", + "buttonText", + "sections" + ] + } + }, + "required": [ + "productList" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "order": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1 + }, + "thumbnailBase64": { + "type": "string", + "maxLength": 87384 + }, + "itemCount": { + "type": "integer", + "minimum": 1, + "maximum": 100 + }, + "status": { + "type": "string", + "enum": [ + "inquiry", + "accepted", + "declined" + ] + }, + "message": { + "type": "string", + "minLength": 0 + }, + "title": { + "type": "string", + "minLength": 0 + }, + "sellerJid": { + "type": "string", + "pattern": "^\\d+@s\\.whatsapp\\.net$" + }, + "token": { + "type": "string", + "minLength": 0 + }, + "totalAmount1000": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "totalCurrencyCode": { + "type": "string", + "pattern": "^[A-Z]{3}$" + }, + "catalogType": { + "type": "string", + "minLength": 0 + } + }, + "required": [ + "id", + "itemCount", + "status", + "sellerJid", + "totalAmount1000", + "totalCurrencyCode" + ] + } + }, + "required": [ + "order" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "list": { + "type": "object", + "properties": { + "title": { + "type": "string", + "minLength": 1 + }, + "description": { + "type": "string", + "minLength": 0 + }, + "buttonText": { + "type": "string", + "minLength": 1 + }, + "footer": { + "type": "string", + "minLength": 0 + }, + "sections": { + "type": "array", + "items": { + "type": "object", + "properties": { + "title": { + "type": "string", + "minLength": 0 }, - "required": [ - "id", - "title" - ] + "rows": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1 + }, + "title": { + "type": "string", + "minLength": 1 + }, + "description": { + "type": "string", + "minLength": 0 + } + }, + "required": [ + "id", + "title" + ] + }, + "minItems": 1, + "maxItems": 30 + } }, - "minItems": 1, - "maxItems": 30 - } - }, - "required": [ - "rows" - ] + "required": [ + "rows" + ] + }, + "minItems": 1, + "maxItems": 10 + } }, - "minItems": 1, - "maxItems": 10 + "required": [ + "title", + "buttonText", + "sections" + ] } }, "required": [ - "title", - "buttonText", - "sections" - ] + "list" + ], + "additionalProperties": false }, - "buttons": { + { "type": "object", "properties": { - "title": { - "type": "string", - "minLength": 0 - }, - "body": { - "type": "string", - "minLength": 1 - }, - "footer": { - "type": "string", - "minLength": 0 - }, "buttons": { - "type": "array", - "items": { - "oneOf": [ - { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": [ + "type": "object", + "properties": { + "title": { + "type": "string", + "minLength": 0 + }, + "body": { + "type": "string", + "minLength": 1 + }, + "footer": { + "type": "string", + "minLength": 0 + }, + "buttons": { + "type": "array", + "items": { + "oneOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "url" + ] + }, + "text": { + "type": "string", + "minLength": 1 + }, + "url": { + "type": "string", + "maxLength": 2048, + "format": "uri" + } + }, + "required": [ + "type", + "text", "url" ] }, - "text": { - "type": "string", - "minLength": 1 - }, - "url": { - "type": "string", - "maxLength": 2048, - "format": "uri" - } - }, - "required": [ - "type", - "text", - "url" - ] - }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": [ - "call" + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "call" + ] + }, + "text": { + "type": "string", + "minLength": 1 + }, + "phoneNumber": { + "type": "string", + "pattern": "^\\+?\\d{6,20}$" + } + }, + "required": [ + "type", + "text", + "phoneNumber" ] }, - "text": { - "type": "string", - "minLength": 1 - }, - "phoneNumber": { - "type": "string", - "pattern": "^\\+?\\d{6,20}$" - } - }, - "required": [ - "type", - "text", - "phoneNumber" - ] - }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": [ - "reply" + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "reply" + ] + }, + "text": { + "type": "string", + "minLength": 1 + }, + "id": { + "type": "string", + "minLength": 1 + } + }, + "required": [ + "type", + "text", + "id" ] }, - "text": { - "type": "string", - "minLength": 1 - }, - "id": { - "type": "string", - "minLength": 1 - } - }, - "required": [ - "type", - "text", - "id" - ] - }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": [ - "copy" + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "copy" + ] + }, + "text": { + "type": "string", + "minLength": 1 + }, + "copyCode": { + "type": "string", + "minLength": 1 + } + }, + "required": [ + "type", + "text", + "copyCode" ] }, - "text": { - "type": "string", - "minLength": 1 - }, - "copyCode": { - "type": "string", - "minLength": 1 - } - }, - "required": [ - "type", - "text", - "copyCode" - ] - }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": [ - "catalog" + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "catalog" + ] + }, + "text": { + "type": "string", + "minLength": 1 + }, + "businessPhoneNumber": { + "type": "string", + "pattern": "^\\+?\\d{6,20}$" + }, + "catalogProductId": { + "type": "string", + "minLength": 0 + } + }, + "required": [ + "type", + "text", + "businessPhoneNumber" ] - }, - "text": { - "type": "string", - "minLength": 1 - }, - "businessPhoneNumber": { - "type": "string", - "pattern": "^\\+?\\d{6,20}$" - }, - "catalogProductId": { - "type": "string", - "minLength": 0 } - }, - "required": [ - "type", - "text", - "businessPhoneNumber" ] - } - ] + }, + "minItems": 1, + "maxItems": 3 + } }, - "minItems": 1, - "maxItems": 3 + "required": [ + "body", + "buttons" + ] } }, "required": [ - "body", "buttons" - ] + ], + "additionalProperties": false }, - "addressMessage": { + { "type": "object", "properties": { - "body": { - "type": "string", - "minLength": 1 - }, - "buttonText": { - "type": "string", - "minLength": 1 - }, - "footer": { - "type": "string", - "minLength": 0 - }, - "country": { - "type": "string", - "pattern": "^[A-Z]{2}$" + "addressMessage": { + "type": "object", + "properties": { + "body": { + "type": "string", + "minLength": 1 + }, + "buttonText": { + "type": "string", + "minLength": 1 + }, + "footer": { + "type": "string", + "minLength": 0 + }, + "country": { + "type": "string", + "pattern": "^[A-Z]{2}$" + } + }, + "required": [ + "body" + ] } }, "required": [ - "body" - ] + "addressMessage" + ], + "additionalProperties": false }, - "flow": { + { "type": "object", "properties": { - "body": { - "type": "string", - "minLength": 1 - }, - "buttonText": { - "type": "string", - "minLength": 1 - }, - "footer": { - "type": "string", - "minLength": 0 - }, - "id": { - "type": "string", - "minLength": 1 - }, - "token": { - "type": "string", - "minLength": 1 - }, - "action": { - "type": "string", - "enum": [ - "navigate", - "data_exchange" - ] - }, - "screen": { - "type": "string", - "minLength": 0 - }, - "dataJson": { - "type": "string", - "minLength": 0 - } - }, - "required": [ - "body", - "buttonText", - "id", - "token", - "action" - ], - "oneOf": [ - { + "flow": { + "type": "object", "properties": { + "body": { + "type": "string", + "minLength": 1 + }, + "buttonText": { + "type": "string", + "minLength": 1 + }, + "footer": { + "type": "string", + "minLength": 0 + }, + "id": { + "type": "string", + "minLength": 1 + }, + "token": { + "type": "string", + "minLength": 1 + }, "action": { + "type": "string", "enum": [ - "navigate" + "navigate", + "data_exchange" ] + }, + "screen": { + "type": "string", + "minLength": 0 + }, + "dataJson": { + "type": "string", + "minLength": 0 } }, "required": [ - "screen" - ] - }, - { - "properties": { - "action": { - "enum": [ - "data_exchange" + "body", + "buttonText", + "id", + "token", + "action" + ], + "oneOf": [ + { + "properties": { + "action": { + "enum": [ + "navigate" + ] + } + }, + "required": [ + "screen" ] - } - }, - "not": { - "anyOf": [ - { - "required": [ - "screen" - ] + }, + { + "properties": { + "action": { + "enum": [ + "data_exchange" + ] + } }, - { - "required": [ - "dataJson" + "not": { + "anyOf": [ + { + "required": [ + "screen" + ] + }, + { + "required": [ + "dataJson" + ] + } ] } - ] - } + } + ] } - ] + }, + "required": [ + "flow" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "template": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1 + }, + "language": { + "type": "string", + "minLength": 2 + }, + "components": { + "type": "array", + "items": {} + } + }, + "required": [ + "name", + "language" + ], + "additionalProperties": false + } + }, + "required": [ + "template" + ], + "additionalProperties": false + } + ] + }, + "SendMessageRequest": { + "type": "object", + "properties": { + "conversation": { + "$ref": "#/components/schemas/ConversationIdentifier" }, "isForwarded": { - "type": "boolean" + "type": "boolean", + "description": "Mark this message as forwarded." }, "mentions": { "type": "array", "items": { - "type": "string" - } + "type": "string", + "pattern": "^pmfa_lid_[1-9]\\d*$" + }, + "description": "User IDs to mention in this message." }, "quotedMessage": { "$ref": "#/components/schemas/QuotedMessage" }, - "template": { + "content": { + "$ref": "#/components/schemas/MessageContent" + } + }, + "required": [ + "conversation", + "content" + ], + "additionalProperties": false, + "description": "Specify conversation and content containing exactly one message kind. Shared options remain outside content." + }, + "MessageActionResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "enum": [ + true + ] + }, + "data": { "type": "object", "properties": { - "name": { - "type": "string", - "minLength": 1 - }, - "language": { - "type": "string", - "minLength": 2 - }, - "components": { - "type": "array", - "items": {} + "status": { + "type": "string" } }, "required": [ - "name", - "language" - ], - "description": "Template send (cloud_api only). When set, type is ignored. Rejected on whatsmeow sessions." + "status" + ] } }, "required": [ - "chatId", - "type" + "success", + "data" ] }, "SeenRequest": { "type": "object", "properties": { - "chatId": { - "type": "string", - "minLength": 1 + "conversation": { + "$ref": "#/components/schemas/ConversationIdentifier" }, - "messageId": { + "id": { "type": "string", "minLength": 1 }, "participant": { "type": "string", - "minLength": 1, - "description": "Sender JID of the message being marked read. Required by WhatsApp for group chats; when omitted the sender is resolved from the message id." + "description": "Sender ID or phone number of the message being marked read. Required by WhatsApp for group chats; when omitted the sender is resolved from the message id." } }, "required": [ - "chatId", - "messageId" - ] + "conversation", + "id" + ], + "additionalProperties": false }, "TypingRequest": { "type": "object", "properties": { - "chatId": { - "type": "string", - "minLength": 1 + "conversation": { + "$ref": "#/components/schemas/ConversationIdentifier" }, "state": { "type": "string", @@ -7117,8 +7416,34 @@ } }, "required": [ - "chatId", + "conversation", "state" + ], + "additionalProperties": false + }, + "MessageReceipt": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "conversation": { + "$ref": "#/components/schemas/ConversationIdentifier" + }, + "timestamp": { + "type": "string", + "format": "date-time" + }, + "status": { + "type": "string", + "description": "Upstream acceptance status. Delivery and read receipts arrive separately." + } + }, + "required": [ + "id", + "conversation", + "timestamp", + "status" ] }, "SendReactionResponse": { @@ -7131,7 +7456,7 @@ ] }, "data": { - "$ref": "#/components/schemas/MessageResponse" + "$ref": "#/components/schemas/MessageReceipt" } }, "required": [ @@ -7142,11 +7467,10 @@ "ReactRequest": { "type": "object", "properties": { - "chatId": { - "type": "string", - "minLength": 1 + "conversation": { + "$ref": "#/components/schemas/ConversationIdentifier" }, - "messageId": { + "id": { "type": "string", "minLength": 1 }, @@ -7155,37 +7479,19 @@ } }, "required": [ - "chatId", - "messageId", + "conversation", + "id", "reaction" - ] - }, - "StarMessageResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "enum": [ - true - ] - }, - "data": { - "$ref": "#/components/schemas/MessageResponse" - } - }, - "required": [ - "success", - "data" - ] + ], + "additionalProperties": false }, "StarRequest": { "type": "object", "properties": { - "chatId": { - "type": "string", - "minLength": 1 + "conversation": { + "$ref": "#/components/schemas/ConversationIdentifier" }, - "messageId": { + "id": { "type": "string", "minLength": 1 }, @@ -7200,10 +7506,11 @@ } }, "required": [ - "chatId", - "messageId", + "conversation", + "id", "star" - ] + ], + "additionalProperties": false }, "EditMessageRequest": { "type": "object", @@ -7258,8 +7565,8 @@ "properties": { "from": { "type": "string", - "minLength": 1, - "description": "JID of the incoming caller" + "pattern": "^pmfa_(?:lid|botid)_[1-9]\\d*$", + "description": "ID of the incoming caller" } }, "required": [ @@ -7507,8 +7814,7 @@ }, "to": { "type": "string", - "minLength": 1, - "maxLength": 128, + "pattern": "^(?:\\+[1-9]\\d{1,14}|pmfa_(?:lid|botid)_[1-9]\\d*)$", "example": "+15550100" }, "video": { @@ -7583,8 +7889,7 @@ "properties": { "to": { "type": "string", - "minLength": 1, - "maxLength": 128, + "pattern": "^(?:\\+[1-9]\\d{1,14}|pmfa_(?:lid|botid)_[1-9]\\d*)$", "example": "+15550100" } }, @@ -7776,10 +8081,6 @@ "id": { "type": "string" }, - "lid": { - "type": "string", - "deprecated": true - }, "phoneNumber": { "type": "string" }, @@ -7795,7 +8096,6 @@ }, "required": [ "id", - "lid", "isAdmin", "isSuperAdmin" ] @@ -7805,7 +8105,7 @@ "properties": { "id": { "type": "string", - "description": "Group JID (e.g. 120363...@g.us)" + "description": "Group ID, such as pmfa_gid_120363000000001" }, "name": { "type": "string" @@ -7816,10 +8116,6 @@ "ownerId": { "type": "string" }, - "ownerLid": { - "type": "string", - "deprecated": true - }, "createdAt": { "type": "number", "description": "Unix timestamp in seconds" @@ -7836,7 +8132,6 @@ "name", "description", "ownerId", - "ownerLid", "createdAt", "participants" ] @@ -7890,7 +8185,8 @@ "participants": { "type": "array", "items": { - "type": "string" + "type": "string", + "pattern": "^pmfa_lid_[1-9]\\d*$" }, "minItems": 1 } @@ -7912,10 +8208,6 @@ "creatorId": { "type": "string" }, - "creatorLid": { - "type": "string", - "deprecated": true - }, "createdAt": { "type": "number" }, @@ -7933,7 +8225,6 @@ "id", "subject", "creatorId", - "creatorLid", "createdAt", "size", "participants" @@ -8073,7 +8364,8 @@ "participants": { "type": "array", "items": { - "type": "string" + "type": "string", + "pattern": "^pmfa_lid_[1-9]\\d*$" }, "minItems": 1 } @@ -8136,10 +8428,6 @@ "id": { "type": "string" }, - "lid": { - "type": "string", - "deprecated": true - }, "phoneNumber": { "type": "string" }, @@ -8161,7 +8449,6 @@ }, "required": [ "id", - "lid", "name", "pushName" ] @@ -8196,10 +8483,6 @@ "id": { "type": "string" }, - "lid": { - "type": "string", - "deprecated": true - }, "phoneNumber": { "type": "string" }, @@ -8238,16 +8521,24 @@ "hash": { "type": "string" }, - "jids": { + "contacts": { "type": "array", "items": { - "type": "string" + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "phoneNumber": { + "type": "string" + } + } } } }, "required": [ "hash", - "jids" + "contacts" ] }, "GetBlocklistResponse": { @@ -8322,14 +8613,6 @@ "id": { "type": "string" }, - "jid": { - "type": "string", - "deprecated": true - }, - "lid": { - "type": "string", - "deprecated": true - }, "phoneNumber": { "type": "string" }, @@ -8348,14 +8631,26 @@ "devices": { "type": "array", "items": { - "type": "string" + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "phoneNumber": { + "type": "string" + }, + "device": { + "type": "integer" + } + }, + "required": [ + "device" + ] } } }, "required": [ "id", - "jid", - "lid", "status", "pictureId", "verifiedName", @@ -8392,7 +8687,21 @@ "data": { "type": "array", "items": { - "type": "string" + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "phoneNumber": { + "type": "string" + }, + "device": { + "type": "integer" + } + }, + "required": [ + "device" + ] } } }, @@ -8404,7 +8713,7 @@ "BusinessProfile": { "type": "object", "properties": { - "jid": { + "id": { "type": "string" }, "address": { @@ -8481,7 +8790,7 @@ } }, "required": [ - "jid", + "id", "address", "email", "description", @@ -10444,16 +10753,12 @@ "token" ] }, - "ResolveLIDResult": { + "ResolveIdentityResult": { "type": "object", "properties": { "id": { "type": "string" }, - "lid": { - "type": "string", - "deprecated": true - }, "phoneNumber": { "type": "string" }, @@ -10465,7 +10770,7 @@ } } }, - "ResolveLIDsResponse": { + "ResolveIdentityResponse": { "type": "object", "properties": { "success": { @@ -10475,7 +10780,7 @@ ] }, "data": { - "$ref": "#/components/schemas/ResolveLIDResult" + "$ref": "#/components/schemas/ResolveIdentityResult" } }, "required": [ @@ -10488,7 +10793,7 @@ "properties": { "id": { "type": "string", - "pattern": "^\\d+@lid$" + "pattern": "^pmfa_lid_[1-9]\\d*$" }, "phoneNumber": { "type": "string" @@ -10531,7 +10836,7 @@ "Channel": { "type": "object", "properties": { - "lid": { + "id": { "type": "string" }, "name": { @@ -10785,33 +11090,6 @@ "data" ] }, - "AsyncAcceptedResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "enum": [ - true - ] - }, - "data": { - "type": "object", - "properties": { - "requestId": { - "type": "string", - "format": "uuid" - } - }, - "required": [ - "requestId" - ] - } - }, - "required": [ - "success", - "data" - ] - }, "SetPresenceRequest": { "type": "object", "properties": { @@ -13671,7 +13949,7 @@ "security": [], "responses": { "200": { - "description": "All services healthy", + "description": "Required readiness checks pass; optional diagnostics may report degraded or in-progress state", "content": { "application/json": { "schema": { @@ -13693,7 +13971,7 @@ } } }, - "/api/info/version": { + "/messaging/info/version": { "get": { "operationId": "getVersion", "tags": [ @@ -13715,7 +13993,7 @@ } } }, - "/api/info/status": { + "/messaging/info/status": { "get": { "operationId": "getStatus", "tags": [ @@ -13737,7 +14015,7 @@ } } }, - "/v1/bridge/route": { + "/messaging/bridge/route": { "get": { "operationId": "getBridgeRoute", "x-required-scope": "bridge:connect", @@ -13808,19 +14086,17 @@ "content": { "application/json": { "schema": { - "type": "object", - "properties": { - "error": { - "type": "string" - }, - "message": { - "type": "string" - } + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null }, - "required": [ - "error", - "message" - ] + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -13830,19 +14106,17 @@ "content": { "application/json": { "schema": { - "type": "object", - "properties": { - "error": { - "type": "string" - }, - "message": { - "type": "string" - } + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "service_unavailable", + "message": "A required service is unavailable. Check completion before repeating a write.", + "param": null }, - "required": [ - "error", - "message" - ] + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#service-unavailable" } } } @@ -13854,7 +14128,7 @@ "description": "**Required scope:** `bridge:connect`" } }, - "/api/client-tokens": { + "/messaging/client-tokens": { "post": { "operationId": "mintClientToken", "tags": [ @@ -13900,7 +14174,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -13910,7 +14194,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -13920,7 +14214,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -13930,7 +14234,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -13940,7 +14254,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -13952,7 +14276,7 @@ "description": "**Required scopes (all):** `sessions:manage` · `messages:write` · `contacts:read` · `presence:read` · `presence:observe` · `mcp`" } }, - "/api/sessions/{session}/client-rules": { + "/messaging/sessions/{session}/client-rules": { "get": { "operationId": "getClientRules", "tags": [ @@ -13991,7 +14315,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -14001,7 +14335,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -14011,7 +14355,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -14021,7 +14375,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -14031,7 +14395,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -14097,7 +14471,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -14107,7 +14491,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -14117,7 +14511,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -14127,7 +14531,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -14137,7 +14551,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -14186,7 +14610,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -14196,7 +14630,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -14206,7 +14650,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -14216,7 +14670,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -14226,7 +14690,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -14238,119 +14712,7 @@ "description": "**Required scope:** `sessions:manage`" } }, - "/api/operations/{operation}": { - "get": { - "operationId": "getOperation", - "tags": [ - "Operations" - ], - "summary": "Get a durable operation", - "security": [ - { - "BearerAuth": [] - } - ], - "x-required-scopes": [ - "sessions:read", - "campaigns:read", - "webhooks:manage" - ], - "x-required-scope-mode": "any", - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid" - }, - "required": true, - "name": "operation", - "in": "path" - } - ], - "responses": { - "200": { - "description": "Operation state", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "enum": [ - true - ] - }, - "data": { - "$ref": "#/components/schemas/Operation" - } - }, - "required": [ - "success", - "data" - ] - } - } - } - }, - "400": { - "description": "Bad request — request body or params failed validation", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "401": { - "description": "Missing or invalid authentication token", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "403": { - "description": "Authenticated but not permitted (missing scope or rule violation)", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "404": { - "description": "Resource not found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "500": { - "description": "Internal server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - } - }, - "x-mint": { - "content": "sessions:read campaigns:read webhooks:manage" - }, - "description": "**Required scopes (any):** `sessions:read` · `campaigns:read` · `webhooks:manage`" - } - }, - "/api/sessions": { + "/messaging/sessions": { "get": { "operationId": "listSessions", "tags": [ @@ -14379,7 +14741,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -14389,7 +14761,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -14399,7 +14781,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -14409,7 +14801,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -14419,7 +14821,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -14429,7 +14841,9 @@ "content": "sessions:read" }, "description": "**Required scope:** `sessions:read`" - }, + } + }, + "/messaging/sessions/{projectId}/": { "post": { "operationId": "createSession", "tags": [ @@ -14442,6 +14856,18 @@ } ], "x-required-scope": "sessions:manage", + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "description": "Project that owns the session." + }, + "required": true, + "name": "projectId", + "in": "path" + } + ], "requestBody": { "content": { "application/json": { @@ -14467,7 +14893,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -14477,7 +14913,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -14487,7 +14933,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -14497,7 +14953,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -14507,7 +14973,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "conflict_error", + "code": "state_conflict", + "message": "The request conflicts with the resource state.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#state-conflict" } } } @@ -14517,7 +14993,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -14529,7 +15015,7 @@ "description": "**Required scope:** `sessions:manage`" } }, - "/api/sessions/{session}": { + "/messaging/sessions/{session}": { "get": { "operationId": "getSession", "tags": [ @@ -14568,7 +15054,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -14578,7 +15074,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -14588,7 +15094,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -14598,7 +15114,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -14608,7 +15134,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -14666,7 +15202,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -14676,7 +15222,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -14686,7 +15242,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -14696,7 +15262,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -14706,7 +15282,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -14716,7 +15302,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "service_unavailable", + "message": "A required service is unavailable. Check completion before repeating a write.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#service-unavailable" } } } @@ -14775,7 +15371,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -14785,7 +15391,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -14795,7 +15411,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -14805,7 +15431,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -14815,7 +15451,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -14827,7 +15473,7 @@ "description": "**Required scope:** `sessions:manage`" } }, - "/api/sessions/{session}/start": { + "/messaging/sessions/{session}/start": { "post": { "operationId": "startSession", "tags": [ @@ -14866,7 +15512,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -14876,7 +15532,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -14886,7 +15552,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -14896,7 +15572,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -14906,7 +15592,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -14918,7 +15614,7 @@ "description": "**Required scope:** `sessions:manage`" } }, - "/api/sessions/{session}/stop": { + "/messaging/sessions/{session}/stop": { "post": { "operationId": "stopSession", "tags": [ @@ -14957,7 +15653,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -14967,7 +15673,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -14977,7 +15693,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -14987,7 +15713,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -14997,7 +15733,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -15009,7 +15755,7 @@ "description": "**Required scope:** `sessions:manage`" } }, - "/api/sessions/{session}/restart": { + "/messaging/sessions/{session}/restart": { "post": { "operationId": "restartSession", "tags": [ @@ -15048,7 +15794,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -15058,7 +15814,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -15068,7 +15834,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -15078,7 +15854,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -15088,7 +15874,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -15100,7 +15896,7 @@ "description": "**Required scope:** `sessions:manage`" } }, - "/api/sessions/{session}/logout": { + "/messaging/sessions/{session}/logout": { "post": { "operationId": "logoutSession", "tags": [ @@ -15139,7 +15935,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -15149,7 +15955,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -15159,7 +15975,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -15169,7 +15995,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -15179,7 +16015,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -15191,7 +16037,7 @@ "description": "**Required scope:** `sessions:manage`" } }, - "/api/sessions/{session}/me": { + "/messaging/sessions/{session}/me": { "get": { "operationId": "getSessionAccount", "tags": [ @@ -15230,7 +16076,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -15240,7 +16096,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -15250,7 +16116,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -15260,7 +16136,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -15270,7 +16156,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -15282,7 +16178,7 @@ "description": "**Required scope:** `sessions:read`" } }, - "/api/sessions/{session}/handoff-keys": { + "/messaging/sessions/{session}/handoff-keys": { "post": { "operationId": "sessionHandoffKeys", "tags": [ @@ -15321,7 +16217,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -15331,7 +16237,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -15341,7 +16257,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -15351,7 +16277,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -15361,7 +16297,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -15373,7 +16319,7 @@ "description": "**Required scope:** `sessions:manage`" } }, - "/api/sessions/{session}/handoff-import": { + "/messaging/sessions/{session}/handoff-import": { "post": { "operationId": "sessionHandoffImport", "tags": [ @@ -15421,7 +16367,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -15431,7 +16387,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -15441,7 +16407,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -15451,7 +16427,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -15461,7 +16447,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -15473,7 +16469,7 @@ "description": "**Required scope:** `sessions:manage`" } }, - "/api/sessions/{session}/upload-appstate-keys": { + "/messaging/sessions/{session}/upload-appstate-keys": { "post": { "operationId": "sessionUploadAppStateKeys", "tags": [ @@ -15521,7 +16517,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -15531,7 +16537,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -15541,7 +16557,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -15551,7 +16577,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -15561,7 +16597,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -15573,7 +16619,7 @@ "description": "**Required scope:** `sessions:manage`" } }, - "/api/sessions/{session}/handoff-ack": { + "/messaging/sessions/{session}/handoff-ack": { "post": { "operationId": "sessionHandoffAck", "tags": [ @@ -15621,7 +16667,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -15631,7 +16687,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -15641,7 +16707,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -15651,7 +16727,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -15661,7 +16747,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -15673,13 +16769,14 @@ "description": "**Required scope:** `sessions:manage`" } }, - "/api/{session}/pair/qr": { + "/messaging/{session}/pair/qr": { "get": { "operationId": "getQRCode", "tags": [ "Pairing" ], "summary": "Get QR code for device pairing", + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `sessions:manage`\n\nDirect QR retrieval requires an explicit organization entitlement. Create a QuickLink for the standard pairing flow.", "security": [ { "BearerAuth": [] @@ -15731,7 +16828,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -15741,17 +16848,37 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } }, "403": { - "description": "Authenticated but not permitted (missing scope or rule violation)", + "description": "Direct pairing is unavailable; create a QuickLink unless the organization has the direct-pairing entitlement", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -15761,7 +16888,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -15771,7 +16908,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -15782,17 +16929,17 @@ }, "x-protocols": [ "Linked Device API" - ], - "description": "**Protocols:** Linked Device API\n\n**Required scope:** `sessions:manage`" + ] } }, - "/api/{session}/pair/code": { + "/messaging/{session}/pair/code": { "post": { "operationId": "requestPairCode", "tags": [ "Pairing" ], "summary": "Request a pairing code for a phone number", + "description": "**Protocols:** Linked Device API\n\n**Required scope:** `sessions:manage`\n\nDirect pairing-code retrieval requires an explicit organization entitlement. Create a QuickLink for the standard pairing flow.", "security": [ { "BearerAuth": [] @@ -15834,7 +16981,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -15844,17 +17001,37 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } }, "403": { - "description": "Authenticated but not permitted (missing scope or rule violation)", + "description": "Direct pairing is unavailable; create a QuickLink unless the organization has the direct-pairing entitlement", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -15864,7 +17041,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -15874,7 +17061,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -15885,18 +17082,17 @@ }, "x-protocols": [ "Linked Device API" - ], - "description": "**Protocols:** Linked Device API\n\n**Required scope:** `sessions:manage`" + ] } }, - "/api/{session}/messages/send": { + "/messaging/{session}/messages/send": { "post": { "operationId": "sendMessage", "tags": [ "Messages" ], "summary": "Send a message", - "description": "**Protocols:** Linked Device API · Meta Cloud API · Polymorfa Hybrid Link\n\n**Required scope:** `messages:write`\n\nTesting sessions accept a recipient testing number in E.164 format or as a phone-number JID, and can send only to active testing numbers in the same project. Malformed, unknown, stopped, deleted, and cross-project testing recipients all return 404 without creating recipient state.", + "description": "**Protocols:** Linked Device API · Meta Cloud API · Polymorfa Hybrid Link\n\n**Required scope:** `messages:write`\n\nSend a message to a conversation. Put exactly one message kind inside content. Testing sessions send only to active testing numbers in the same project; supply the recipient phoneNumber.", "security": [ { "BearerAuth": [] @@ -15918,6 +17114,14 @@ "application/json": { "schema": { "$ref": "#/components/schemas/SendMessageRequest" + }, + "example": { + "conversation": { + "phoneNumber": "+15550001111" + }, + "content": { + "text": "Hello" + } } } } @@ -15933,32 +17137,72 @@ } } }, + "202": { + "description": "Accepted for asynchronous processing in response to `Prefer: respond-async`; the result is not included", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AsyncAcceptedResponse" + } + } + } + }, "400": { - "description": "Bad request — request body or params failed validation", + "description": "Invalid request", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } }, "401": { - "description": "Missing or invalid authentication token", + "description": "Invalid credential", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } }, "403": { - "description": "Authenticated but not permitted (missing scope or rule violation)", + "description": "Missing scope or resource access", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -15968,17 +17212,117 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" + } + } + } + }, + "422": { + "description": "The supplied media URL could not be fetched", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } }, "500": { - "description": "Internal server error", + "description": "Unexpected service failure", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" + } + } + } + }, + "502": { + "description": "Messaging provider failure", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "upstream_error", + "code": "upstream_failure", + "message": "The messaging provider could not complete the request.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#upstream-failure" + } + } + } + }, + "503": { + "description": "Session or service unavailable", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "service_unavailable", + "message": "A required service is unavailable. Check completion before repeating a write.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#service-unavailable" + } + } + } + }, + "504": { + "description": "Result unknown after timeout", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "result_unknown", + "message": "The result was not obtained before the deadline. Check completion before repeating a write.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#result-unknown" } } } @@ -15994,7 +17338,7 @@ ] } }, - "/api/{session}/messages/seen": { + "/messaging/{session}/messages/seen": { "post": { "operationId": "sendSeen", "tags": [ @@ -16028,41 +17372,81 @@ }, "responses": { "200": { - "description": "Seen marker queued", + "description": "Seen marker confirmed by the messaging backend", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SuccessResponse" + "$ref": "#/components/schemas/MessageActionResponse" + } + } + } + }, + "202": { + "description": "Accepted for asynchronous processing in response to `Prefer: respond-async`; the result is not included", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AsyncAcceptedResponse" } } } }, "400": { - "description": "Bad request — request body or params failed validation", + "description": "Invalid request", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } }, "401": { - "description": "Missing or invalid authentication token", + "description": "Invalid credential", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } }, "403": { - "description": "Authenticated but not permitted (missing scope or rule violation)", + "description": "Missing scope or resource access", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -16072,17 +17456,97 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } }, "500": { - "description": "Internal server error", + "description": "Unexpected service failure", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" + } + } + } + }, + "502": { + "description": "Messaging provider failure", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "upstream_error", + "code": "upstream_failure", + "message": "The messaging provider could not complete the request.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#upstream-failure" + } + } + } + }, + "503": { + "description": "Session or service unavailable", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "service_unavailable", + "message": "A required service is unavailable. Check completion before repeating a write.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#service-unavailable" + } + } + } + }, + "504": { + "description": "Result unknown after timeout", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "result_unknown", + "message": "The result was not obtained before the deadline. Check completion before repeating a write.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#result-unknown" } } } @@ -16099,7 +17563,7 @@ "description": "**Protocols:** Linked Device API · Meta Cloud API · Polymorfa Hybrid Link\n\n**Required scope:** `messages:write`" } }, - "/api/{session}/messages/typing": { + "/messaging/{session}/messages/typing": { "post": { "operationId": "setTyping", "tags": [ @@ -16133,41 +17597,81 @@ }, "responses": { "200": { - "description": "Typing state queued", + "description": "Typing state confirmed by the messaging backend", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SuccessResponse" + "$ref": "#/components/schemas/MessageActionResponse" + } + } + } + }, + "202": { + "description": "Accepted for asynchronous processing in response to `Prefer: respond-async`; the result is not included", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AsyncAcceptedResponse" } } } }, "400": { - "description": "Bad request — request body or params failed validation", + "description": "Invalid request", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } }, "401": { - "description": "Missing or invalid authentication token", + "description": "Invalid credential", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } }, "403": { - "description": "Authenticated but not permitted (missing scope or rule violation)", + "description": "Missing scope or resource access", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -16177,17 +17681,97 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } }, "500": { - "description": "Internal server error", + "description": "Unexpected service failure", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" + } + } + } + }, + "502": { + "description": "Messaging provider failure", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "upstream_error", + "code": "upstream_failure", + "message": "The messaging provider could not complete the request.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#upstream-failure" + } + } + } + }, + "503": { + "description": "Session or service unavailable", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "service_unavailable", + "message": "A required service is unavailable. Check completion before repeating a write.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#service-unavailable" + } + } + } + }, + "504": { + "description": "Result unknown after timeout", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "result_unknown", + "message": "The result was not obtained before the deadline. Check completion before repeating a write.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#result-unknown" } } } @@ -16202,7 +17786,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `messages:write`" } }, - "/api/{session}/messages/react": { + "/messaging/{session}/messages/react": { "post": { "operationId": "sendReaction", "tags": [ @@ -16245,32 +17829,72 @@ } } }, + "202": { + "description": "Accepted for asynchronous processing in response to `Prefer: respond-async`; the result is not included", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AsyncAcceptedResponse" + } + } + } + }, "400": { - "description": "Bad request — request body or params failed validation", + "description": "Invalid request", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } }, "401": { - "description": "Missing or invalid authentication token", + "description": "Invalid credential", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } }, "403": { - "description": "Authenticated but not permitted (missing scope or rule violation)", + "description": "Missing scope or resource access", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -16280,17 +17904,97 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } }, "500": { - "description": "Internal server error", + "description": "Unexpected service failure", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" + } + } + } + }, + "502": { + "description": "Messaging provider failure", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "upstream_error", + "code": "upstream_failure", + "message": "The messaging provider could not complete the request.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#upstream-failure" + } + } + } + }, + "503": { + "description": "Session or service unavailable", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "service_unavailable", + "message": "A required service is unavailable. Check completion before repeating a write.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#service-unavailable" + } + } + } + }, + "504": { + "description": "Result unknown after timeout", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "result_unknown", + "message": "The result was not obtained before the deadline. Check completion before repeating a write.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#result-unknown" } } } @@ -16307,7 +18011,7 @@ "description": "**Protocols:** Linked Device API · Meta Cloud API · Polymorfa Hybrid Link\n\n**Required scope:** `messages:write`" } }, - "/api/{session}/messages/star": { + "/messaging/{session}/messages/star": { "post": { "operationId": "starMessage", "tags": [ @@ -16345,37 +18049,77 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/StarMessageResponse" + "$ref": "#/components/schemas/MessageActionResponse" + } + } + } + }, + "202": { + "description": "Accepted for asynchronous processing in response to `Prefer: respond-async`; the result is not included", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AsyncAcceptedResponse" } } } }, "400": { - "description": "Bad request — request body or params failed validation", + "description": "Invalid request", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } }, "401": { - "description": "Missing or invalid authentication token", + "description": "Invalid credential", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } }, "403": { - "description": "Authenticated but not permitted (missing scope or rule violation)", + "description": "Missing scope or resource access", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -16385,17 +18129,97 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } }, "500": { - "description": "Internal server error", + "description": "Unexpected service failure", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" + } + } + } + }, + "502": { + "description": "Messaging provider failure", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "upstream_error", + "code": "upstream_failure", + "message": "The messaging provider could not complete the request.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#upstream-failure" + } + } + } + }, + "503": { + "description": "Session or service unavailable", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "service_unavailable", + "message": "A required service is unavailable. Check completion before repeating a write.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#service-unavailable" + } + } + } + }, + "504": { + "description": "Result unknown after timeout", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "result_unknown", + "message": "The result was not obtained before the deadline. Check completion before repeating a write.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#result-unknown" } } } @@ -16410,7 +18234,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `messages:write`" } }, - "/api/{session}/chats/{chatId}/messages/{messageId}": { + "/messaging/{session}/chats/{conversation}/messages/{messageId}": { "put": { "operationId": "editMessage", "tags": [ @@ -16437,7 +18261,7 @@ "type": "string" }, "required": true, - "name": "chatId", + "name": "conversation", "in": "path" }, { @@ -16474,7 +18298,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -16484,7 +18318,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -16494,7 +18338,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -16504,7 +18358,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -16514,7 +18378,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -16554,7 +18428,7 @@ "type": "string" }, "required": true, - "name": "chatId", + "name": "conversation", "in": "path" }, { @@ -16582,7 +18456,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -16592,7 +18476,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -16602,7 +18496,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -16612,7 +18516,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -16622,7 +18536,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -16637,7 +18561,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `chats:manage`" } }, - "/api/{session}/chats/{chatId}/archive": { + "/messaging/{session}/chats/{conversation}/archive": { "post": { "operationId": "archiveChat", "tags": [ @@ -16664,7 +18588,7 @@ "type": "string" }, "required": true, - "name": "chatId", + "name": "conversation", "in": "path" } ], @@ -16684,7 +18608,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -16694,7 +18628,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -16704,7 +18648,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -16714,7 +18668,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -16724,7 +18688,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -16739,7 +18713,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `chats:manage`" } }, - "/api/{session}/chats/{chatId}/unarchive": { + "/messaging/{session}/chats/{conversation}/unarchive": { "post": { "operationId": "unarchiveChat", "tags": [ @@ -16766,7 +18740,7 @@ "type": "string" }, "required": true, - "name": "chatId", + "name": "conversation", "in": "path" } ], @@ -16786,7 +18760,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -16796,7 +18780,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -16806,7 +18800,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -16816,7 +18820,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -16826,7 +18840,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -16841,7 +18865,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `chats:manage`" } }, - "/api/{session}/chats/{chatId}/disappearing": { + "/messaging/{session}/chats/{conversation}/disappearing": { "put": { "operationId": "setChatDisappearingTimer", "tags": [ @@ -16868,7 +18892,7 @@ "type": "string" }, "required": true, - "name": "chatId", + "name": "conversation", "in": "path" } ], @@ -16897,7 +18921,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -16907,7 +18941,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -16917,7 +18961,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -16927,7 +18981,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -16937,7 +19001,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -16952,7 +19026,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `chats:manage`" } }, - "/api/{session}/calls/{callId}/reject": { + "/messaging/{session}/calls/{callId}/reject": { "post": { "operationId": "rejectCall", "tags": [ @@ -17010,7 +19084,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -17020,7 +19104,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -17030,7 +19124,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -17040,7 +19144,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -17050,7 +19164,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -17065,7 +19189,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `chats:manage`" } }, - "/api/voip/calls/{id}/offer": { + "/messaging/voip/calls/{id}/offer": { "post": { "operationId": "voipOffer", "tags": [ @@ -17115,7 +19239,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -17125,7 +19259,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -17135,7 +19279,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -17145,7 +19299,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -17155,7 +19319,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "conflict_error", + "code": "state_conflict", + "message": "The request conflicts with the resource state.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#state-conflict" } } } @@ -17165,7 +19339,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_gone", + "message": "The requested retained resource has expired or was removed.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-gone" } } } @@ -17175,7 +19359,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "rate_limit_error", + "code": "rate_limit_exceeded", + "message": "The request limit was reached. Follow Retry-After when supplied.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#rate-limit-exceeded" } } } @@ -17185,7 +19379,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -17195,7 +19399,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "service_unavailable", + "message": "A required service is unavailable. Check completion before repeating a write.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#service-unavailable" } } } @@ -17207,7 +19421,7 @@ "description": "**Required scope:** `sessions:manage`" } }, - "/api/voip/calls/{id}/renegotiate": { + "/messaging/voip/calls/{id}/renegotiate": { "post": { "operationId": "voipRenegotiate", "tags": [ @@ -17257,7 +19471,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -17267,7 +19491,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -17277,7 +19511,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -17287,7 +19531,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -17297,7 +19551,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "conflict_error", + "code": "state_conflict", + "message": "The request conflicts with the resource state.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#state-conflict" } } } @@ -17307,7 +19571,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_gone", + "message": "The requested retained resource has expired or was removed.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-gone" } } } @@ -17317,7 +19591,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -17327,7 +19611,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "service_unavailable", + "message": "A required service is unavailable. Check completion before repeating a write.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#service-unavailable" } } } @@ -17339,7 +19633,7 @@ "description": "**Required scope:** `sessions:manage`" } }, - "/api/voip/ws-ticket": { + "/messaging/voip/ws-ticket": { "post": { "operationId": "voipSocketTicket", "tags": [ @@ -17378,7 +19672,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -17388,7 +19692,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -17398,7 +19712,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -17408,7 +19732,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -17418,7 +19752,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -17429,7 +19773,7 @@ } } }, - "/api/voip/calls/{id}/agent-token": { + "/messaging/voip/calls/{id}/agent-token": { "post": { "operationId": "voipAgentToken", "tags": [ @@ -17480,7 +19824,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -17490,7 +19844,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -17500,7 +19864,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -17510,7 +19884,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -17520,7 +19904,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "conflict_error", + "code": "state_conflict", + "message": "The request conflicts with the resource state.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#state-conflict" } } } @@ -17530,7 +19924,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_gone", + "message": "The requested retained resource has expired or was removed.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-gone" } } } @@ -17540,7 +19944,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -17550,7 +19964,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "service_unavailable", + "message": "A required service is unavailable. Check completion before repeating a write.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#service-unavailable" } } } @@ -17561,14 +19985,14 @@ } } }, - "/api/voip/calls": { + "/messaging/voip/calls": { "post": { "operationId": "voipPlaceCall", "tags": [ "VoIP" ], "summary": "Place an outbound call from a session", - "description": "**Required scope:** `sessions:manage`\n\nOriginates a WhatsApp call to `to` (an E.164 phone number or a WhatsApp JID) from the named session. The call rings on the callee's device: `call.accepted` follows when they pick up and `call.ended` when either side hangs up. Attach media like any other call — `/offer` for a browser, the SDK media socket for programmatic audio/video. Client tokens place from their bound session; server keys must name one. Outbound starts share a rate limit per organization and source session across server keys and client tokens; client-token rules also apply.", + "description": "**Required scope:** `sessions:manage`\n\nOriginates a WhatsApp call to `to` (an E.164 phone number or a user ID) from the named session. The call rings on the callee's device: `call.accepted` follows when they pick up and `call.ended` when either side hangs up. Attach media like any other call — `/offer` for a browser, the SDK media socket for programmatic audio/video. Client tokens place from their bound session; server keys must name one. Outbound starts share a rate limit per organization and source session across server keys and client tokens; client-token rules also apply.", "security": [ { "BearerAuth": [] @@ -17600,7 +20024,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -17610,7 +20044,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -17620,7 +20064,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -17630,7 +20084,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -17640,7 +20104,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "conflict_error", + "code": "state_conflict", + "message": "The request conflicts with the resource state.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#state-conflict" } } } @@ -17650,7 +20124,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_gone", + "message": "The requested retained resource has expired or was removed.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-gone" } } } @@ -17660,7 +20144,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "rate_limit_error", + "code": "rate_limit_exceeded", + "message": "The request limit was reached. Follow Retry-After when supplied.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#rate-limit-exceeded" } } } @@ -17670,7 +20164,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -17680,7 +20184,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "operation_not_supported", + "message": "This operation is not supported.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#operation-not-supported" } } } @@ -17690,7 +20204,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "service_unavailable", + "message": "A required service is unavailable. Check completion before repeating a write.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#service-unavailable" } } } @@ -17701,7 +20225,7 @@ } } }, - "/api/voip/calls/{id}/accept": { + "/messaging/voip/calls/{id}/accept": { "post": { "operationId": "voipAcceptCall", "tags": [ @@ -17752,7 +20276,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -17762,7 +20296,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -17772,7 +20316,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -17782,7 +20336,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -17792,7 +20356,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "conflict_error", + "code": "state_conflict", + "message": "The request conflicts with the resource state.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#state-conflict" } } } @@ -17802,7 +20376,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_gone", + "message": "The requested retained resource has expired or was removed.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-gone" } } } @@ -17812,7 +20396,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -17822,7 +20416,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "service_unavailable", + "message": "A required service is unavailable. Check completion before repeating a write.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#service-unavailable" } } } @@ -17833,7 +20437,7 @@ } } }, - "/api/voip/calls/{id}/reject": { + "/messaging/voip/calls/{id}/reject": { "post": { "operationId": "voipRejectCall", "tags": [ @@ -17875,7 +20479,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -17885,7 +20499,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -17895,7 +20519,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -17905,7 +20539,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -17915,7 +20559,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "conflict_error", + "code": "state_conflict", + "message": "The request conflicts with the resource state.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#state-conflict" } } } @@ -17925,7 +20579,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_gone", + "message": "The requested retained resource has expired or was removed.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-gone" } } } @@ -17935,7 +20599,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -17945,7 +20619,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "service_unavailable", + "message": "A required service is unavailable. Check completion before repeating a write.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#service-unavailable" } } } @@ -17956,14 +20640,14 @@ } } }, - "/api/voip/calls/{id}/participants": { + "/messaging/voip/calls/{id}/participants": { "post": { "operationId": "voipAddParticipant", "tags": [ "VoIP" ], "summary": "Invite another party into a live call", - "description": "**Required scope:** `sessions:manage`\n\nRings `to` (an E.164 phone number or a WhatsApp JID) into the call, turning a 1:1 call into a group call. The invitee enters the roster as `invited`; roster changes reach the SDK media socket as `participant_joined` / `participant_state` / `participant_left` frames. 409 until the call has a live leg.", + "description": "**Required scope:** `sessions:manage`\n\nRings `to` (an E.164 phone number or a user ID) into the call, turning a 1:1 call into a group call. The invitee enters the roster as `invited`; roster changes reach the SDK media socket as `participant_joined` / `participant_state` / `participant_left` frames. 409 until the call has a live leg.", "security": [ { "BearerAuth": [] @@ -18007,7 +20691,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -18017,7 +20711,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -18027,7 +20731,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -18037,7 +20751,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -18047,7 +20771,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "conflict_error", + "code": "state_conflict", + "message": "The request conflicts with the resource state.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#state-conflict" } } } @@ -18057,7 +20791,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_gone", + "message": "The requested retained resource has expired or was removed.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-gone" } } } @@ -18067,7 +20811,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "rate_limit_error", + "code": "rate_limit_exceeded", + "message": "The request limit was reached. Follow Retry-After when supplied.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#rate-limit-exceeded" } } } @@ -18077,7 +20831,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -18087,7 +20851,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "service_unavailable", + "message": "A required service is unavailable. Check completion before repeating a write.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#service-unavailable" } } } @@ -18098,7 +20872,7 @@ } } }, - "/api/voip/mode": { + "/messaging/voip/mode": { "post": { "operationId": "voipSetMode", "tags": [ @@ -18137,7 +20911,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -18147,7 +20931,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -18157,7 +20951,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -18167,7 +20971,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -18177,7 +20991,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -18188,7 +21012,7 @@ } } }, - "/api/voip/calls/{id}/candidate": { + "/messaging/voip/calls/{id}/candidate": { "post": { "operationId": "voipCandidate", "tags": [ @@ -18238,7 +21062,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -18248,7 +21082,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -18258,7 +21102,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -18268,7 +21122,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -18278,7 +21142,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "conflict_error", + "code": "state_conflict", + "message": "The request conflicts with the resource state.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#state-conflict" } } } @@ -18288,7 +21162,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_gone", + "message": "The requested retained resource has expired or was removed.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-gone" } } } @@ -18298,7 +21182,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -18308,7 +21202,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "service_unavailable", + "message": "A required service is unavailable. Check completion before repeating a write.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#service-unavailable" } } } @@ -18320,7 +21224,7 @@ "description": "**Required scope:** `sessions:manage`" } }, - "/api/voip/calls/{id}/candidates": { + "/messaging/voip/calls/{id}/candidates": { "get": { "operationId": "voipCandidates", "tags": [ @@ -18361,7 +21265,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -18371,7 +21285,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -18381,7 +21305,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -18391,7 +21325,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -18401,7 +21345,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "conflict_error", + "code": "state_conflict", + "message": "The request conflicts with the resource state.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#state-conflict" } } } @@ -18411,7 +21365,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_gone", + "message": "The requested retained resource has expired or was removed.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-gone" } } } @@ -18421,7 +21385,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -18431,7 +21405,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "service_unavailable", + "message": "A required service is unavailable. Check completion before repeating a write.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#service-unavailable" } } } @@ -18443,7 +21427,7 @@ "description": "**Required scope:** `sessions:manage`" } }, - "/api/voip/calls/{id}": { + "/messaging/voip/calls/{id}": { "delete": { "operationId": "voipTeardown", "tags": [ @@ -18484,7 +21468,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -18494,7 +21488,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -18504,7 +21508,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -18514,7 +21528,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -18524,7 +21548,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "conflict_error", + "code": "state_conflict", + "message": "The request conflicts with the resource state.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#state-conflict" } } } @@ -18534,7 +21568,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_gone", + "message": "The requested retained resource has expired or was removed.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-gone" } } } @@ -18544,7 +21588,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -18554,7 +21608,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "service_unavailable", + "message": "A required service is unavailable. Check completion before repeating a write.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#service-unavailable" } } } @@ -18566,7 +21630,7 @@ "description": "**Required scope:** `sessions:manage`" } }, - "/api/voip/token": { + "/messaging/voip/token": { "post": { "operationId": "voipToken", "tags": [ @@ -18612,7 +21676,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -18622,7 +21696,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -18632,7 +21716,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -18642,7 +21736,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -18652,7 +21756,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -18664,7 +21778,7 @@ "description": "**Required scopes (all):** `sessions:manage` · `messages:write` · `contacts:read` · `presence:read` · `presence:observe` · `mcp`" } }, - "/api/{session}/groups": { + "/messaging/{session}/groups": { "get": { "operationId": "listGroups", "tags": [ @@ -18703,7 +21817,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -18713,7 +21837,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -18723,7 +21857,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -18733,7 +21877,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -18743,7 +21897,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -18804,7 +21968,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -18814,7 +21988,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -18824,7 +22008,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -18834,7 +22028,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -18844,7 +22048,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -18859,7 +22073,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `groups:manage`" } }, - "/api/{session}/groups/join-info": { + "/messaging/{session}/groups/join-info": { "get": { "operationId": "getGroupJoinInfo", "tags": [ @@ -18907,7 +22121,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -18917,7 +22141,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -18927,7 +22161,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -18937,7 +22181,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -18947,7 +22201,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -18962,7 +22226,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `groups:read`" } }, - "/api/{session}/groups/join": { + "/messaging/{session}/groups/join": { "post": { "operationId": "joinGroup", "tags": [ @@ -19010,7 +22274,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -19020,7 +22294,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -19030,7 +22314,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -19040,7 +22334,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -19050,7 +22354,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -19065,7 +22379,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `groups:manage`" } }, - "/api/{session}/groups/{id}": { + "/messaging/{session}/groups/{id}": { "get": { "operationId": "getGroup", "tags": [ @@ -19089,7 +22403,8 @@ }, { "schema": { - "type": "string" + "type": "string", + "pattern": "^pmfa_gid_[0-9]+(?:-[0-9]+)?$" }, "required": true, "name": "id", @@ -19112,7 +22427,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -19122,7 +22447,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -19132,7 +22467,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -19142,7 +22487,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -19152,7 +22507,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -19189,7 +22554,8 @@ }, { "schema": { - "type": "string" + "type": "string", + "pattern": "^pmfa_gid_[0-9]+(?:-[0-9]+)?$" }, "required": true, "name": "id", @@ -19212,7 +22578,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -19222,7 +22598,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -19232,7 +22618,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -19242,7 +22638,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -19252,7 +22658,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -19267,7 +22683,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `groups:manage`" } }, - "/api/{session}/groups/{id}/leave": { + "/messaging/{session}/groups/{id}/leave": { "post": { "operationId": "leaveGroup", "tags": [ @@ -19291,7 +22707,8 @@ }, { "schema": { - "type": "string" + "type": "string", + "pattern": "^pmfa_gid_[0-9]+(?:-[0-9]+)?$" }, "required": true, "name": "id", @@ -19314,7 +22731,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -19324,7 +22751,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -19334,7 +22771,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -19344,7 +22791,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -19354,7 +22811,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -19369,7 +22836,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `groups:manage`" } }, - "/api/{session}/groups/{id}/subject": { + "/messaging/{session}/groups/{id}/subject": { "put": { "operationId": "setGroupSubject", "tags": [ @@ -19393,7 +22860,8 @@ }, { "schema": { - "type": "string" + "type": "string", + "pattern": "^pmfa_gid_[0-9]+(?:-[0-9]+)?$" }, "required": true, "name": "id", @@ -19425,7 +22893,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -19435,7 +22913,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -19445,7 +22933,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -19455,7 +22953,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -19465,7 +22973,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -19480,7 +22998,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `groups:manage`" } }, - "/api/{session}/groups/{id}/description": { + "/messaging/{session}/groups/{id}/description": { "put": { "operationId": "setGroupDescription", "tags": [ @@ -19504,7 +23022,8 @@ }, { "schema": { - "type": "string" + "type": "string", + "pattern": "^pmfa_gid_[0-9]+(?:-[0-9]+)?$" }, "required": true, "name": "id", @@ -19536,7 +23055,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -19546,7 +23075,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -19556,7 +23095,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -19566,7 +23115,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -19576,7 +23135,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -19591,7 +23160,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `groups:manage`" } }, - "/api/{session}/groups/{id}/invite-code": { + "/messaging/{session}/groups/{id}/invite-code": { "get": { "operationId": "getGroupInviteCode", "tags": [ @@ -19615,7 +23184,8 @@ }, { "schema": { - "type": "string" + "type": "string", + "pattern": "^pmfa_gid_[0-9]+(?:-[0-9]+)?$" }, "required": true, "name": "id", @@ -19638,7 +23208,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -19648,7 +23228,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -19658,7 +23248,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -19668,7 +23268,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -19678,7 +23288,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -19693,7 +23313,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `groups:read`" } }, - "/api/{session}/groups/{id}/invite-code/revoke": { + "/messaging/{session}/groups/{id}/invite-code/revoke": { "post": { "operationId": "revokeGroupInviteCode", "tags": [ @@ -19717,7 +23337,8 @@ }, { "schema": { - "type": "string" + "type": "string", + "pattern": "^pmfa_gid_[0-9]+(?:-[0-9]+)?$" }, "required": true, "name": "id", @@ -19740,7 +23361,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -19750,7 +23381,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -19760,7 +23401,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -19770,7 +23421,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -19780,7 +23441,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -19795,7 +23466,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `groups:manage`" } }, - "/api/{session}/groups/{id}/participants": { + "/messaging/{session}/groups/{id}/participants": { "get": { "operationId": "getGroupParticipants", "tags": [ @@ -19819,7 +23490,8 @@ }, { "schema": { - "type": "string" + "type": "string", + "pattern": "^pmfa_gid_[0-9]+(?:-[0-9]+)?$" }, "required": true, "name": "id", @@ -19842,7 +23514,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -19852,7 +23534,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -19862,7 +23554,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -19872,7 +23574,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -19882,7 +23594,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -19897,7 +23619,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `groups:read`" } }, - "/api/{session}/groups/{id}/participants/add": { + "/messaging/{session}/groups/{id}/participants/add": { "post": { "operationId": "addGroupParticipants", "tags": [ @@ -19921,7 +23643,8 @@ }, { "schema": { - "type": "string" + "type": "string", + "pattern": "^pmfa_gid_[0-9]+(?:-[0-9]+)?$" }, "required": true, "name": "id", @@ -19953,7 +23676,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -19963,7 +23696,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -19973,7 +23716,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -19983,7 +23736,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -19993,7 +23756,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -20008,7 +23781,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `groups:manage`" } }, - "/api/{session}/groups/{id}/participants/remove": { + "/messaging/{session}/groups/{id}/participants/remove": { "post": { "operationId": "removeGroupParticipants", "tags": [ @@ -20032,7 +23805,8 @@ }, { "schema": { - "type": "string" + "type": "string", + "pattern": "^pmfa_gid_[0-9]+(?:-[0-9]+)?$" }, "required": true, "name": "id", @@ -20064,7 +23838,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -20074,7 +23858,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -20084,7 +23878,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -20094,7 +23898,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -20104,7 +23918,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -20119,7 +23943,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `groups:manage`" } }, - "/api/{session}/groups/{id}/admin/promote": { + "/messaging/{session}/groups/{id}/admin/promote": { "post": { "operationId": "promoteGroupAdmin", "tags": [ @@ -20143,7 +23967,8 @@ }, { "schema": { - "type": "string" + "type": "string", + "pattern": "^pmfa_gid_[0-9]+(?:-[0-9]+)?$" }, "required": true, "name": "id", @@ -20175,7 +24000,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -20185,7 +24020,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -20195,7 +24040,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -20205,7 +24060,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -20215,7 +24080,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -20230,7 +24105,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `groups:manage`" } }, - "/api/{session}/groups/{id}/admin/demote": { + "/messaging/{session}/groups/{id}/admin/demote": { "post": { "operationId": "demoteGroupAdmin", "tags": [ @@ -20254,7 +24129,8 @@ }, { "schema": { - "type": "string" + "type": "string", + "pattern": "^pmfa_gid_[0-9]+(?:-[0-9]+)?$" }, "required": true, "name": "id", @@ -20286,7 +24162,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -20296,7 +24182,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -20306,7 +24202,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -20316,7 +24222,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -20326,7 +24242,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -20341,7 +24267,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `groups:manage`" } }, - "/api/{session}/groups/{id}/picture": { + "/messaging/{session}/groups/{id}/picture": { "put": { "operationId": "setGroupPicture", "tags": [ @@ -20365,7 +24291,8 @@ }, { "schema": { - "type": "string" + "type": "string", + "pattern": "^pmfa_gid_[0-9]+(?:-[0-9]+)?$" }, "required": true, "name": "id", @@ -20397,7 +24324,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -20407,7 +24344,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -20417,7 +24364,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -20427,7 +24384,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -20437,7 +24404,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -20452,7 +24429,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `groups:manage`" } }, - "/api/{session}/groups/{id}/settings/info-edit": { + "/messaging/{session}/groups/{id}/settings/info-edit": { "put": { "operationId": "setGroupInfoEditing", "tags": [ @@ -20476,7 +24453,8 @@ }, { "schema": { - "type": "string" + "type": "string", + "pattern": "^pmfa_gid_[0-9]+(?:-[0-9]+)?$" }, "required": true, "name": "id", @@ -20508,7 +24486,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -20518,7 +24506,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -20528,7 +24526,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -20538,7 +24546,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -20548,7 +24566,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -20563,7 +24591,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `groups:manage`" } }, - "/api/{session}/groups/{id}/settings/messages": { + "/messaging/{session}/groups/{id}/settings/messages": { "put": { "operationId": "setGroupMessaging", "tags": [ @@ -20587,7 +24615,8 @@ }, { "schema": { - "type": "string" + "type": "string", + "pattern": "^pmfa_gid_[0-9]+(?:-[0-9]+)?$" }, "required": true, "name": "id", @@ -20619,7 +24648,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -20629,7 +24668,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -20639,7 +24688,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -20649,7 +24708,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -20659,7 +24728,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -20674,7 +24753,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `groups:manage`" } }, - "/api/{session}/groups/{id}/settings/member-add": { + "/messaging/{session}/groups/{id}/settings/member-add": { "put": { "operationId": "setGroupMemberAddMode", "tags": [ @@ -20698,7 +24777,8 @@ }, { "schema": { - "type": "string" + "type": "string", + "pattern": "^pmfa_gid_[0-9]+(?:-[0-9]+)?$" }, "required": true, "name": "id", @@ -20730,7 +24810,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -20740,7 +24830,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -20750,7 +24850,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -20760,7 +24870,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -20770,7 +24890,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -20785,7 +24915,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `groups:manage`" } }, - "/api/{session}/groups/{id}/settings/join-approval": { + "/messaging/{session}/groups/{id}/settings/join-approval": { "put": { "operationId": "setGroupJoinApproval", "tags": [ @@ -20809,7 +24939,8 @@ }, { "schema": { - "type": "string" + "type": "string", + "pattern": "^pmfa_gid_[0-9]+(?:-[0-9]+)?$" }, "required": true, "name": "id", @@ -20841,7 +24972,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -20851,7 +24992,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -20861,7 +25012,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -20871,7 +25032,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -20881,7 +25052,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -20896,7 +25077,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `groups:manage`" } }, - "/api/{session}/contacts": { + "/messaging/{session}/contacts": { "get": { "operationId": "listContacts", "tags": [ @@ -20935,7 +25116,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -20945,7 +25136,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -20955,7 +25156,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -20965,7 +25176,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -20975,7 +25196,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -20990,7 +25221,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `contacts:read`" } }, - "/api/{session}/contacts/check": { + "/messaging/{session}/contacts/check": { "get": { "operationId": "checkContacts", "tags": [ @@ -21049,7 +25280,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -21059,7 +25300,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -21069,7 +25320,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -21079,7 +25340,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -21089,7 +25360,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -21104,7 +25385,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `contacts:read`" } }, - "/api/{session}/contacts/blocked": { + "/messaging/{session}/contacts/blocked": { "get": { "operationId": "getBlocklist", "tags": [ @@ -21143,7 +25424,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -21153,7 +25444,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -21163,7 +25464,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -21173,7 +25484,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -21183,7 +25504,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -21198,7 +25529,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `contacts:read`" } }, - "/api/{session}/contacts/{contactId}": { + "/messaging/{session}/contacts/{contactId}": { "get": { "operationId": "getContact", "tags": [ @@ -21222,7 +25553,8 @@ }, { "schema": { - "type": "string" + "type": "string", + "pattern": "^pmfa_(?:lid|botid)_[1-9]\\d*$" }, "required": true, "name": "contactId", @@ -21245,7 +25577,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -21255,7 +25597,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -21265,7 +25617,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -21275,7 +25637,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -21285,7 +25657,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -21300,7 +25682,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `contacts:read`" } }, - "/api/{session}/contacts/{contactId}/picture": { + "/messaging/{session}/contacts/{contactId}/picture": { "get": { "operationId": "getContactPicture", "tags": [ @@ -21324,7 +25706,8 @@ }, { "schema": { - "type": "string" + "type": "string", + "pattern": "^pmfa_(?:lid|botid)_[1-9]\\d*$" }, "required": true, "name": "contactId", @@ -21347,7 +25730,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -21357,7 +25750,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -21367,7 +25770,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -21377,7 +25790,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -21387,7 +25810,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -21402,7 +25835,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `contacts:read`" } }, - "/api/{session}/contacts/{contactId}/info": { + "/messaging/{session}/contacts/{contactId}/info": { "get": { "operationId": "getUserInfo", "tags": [ @@ -21426,7 +25859,8 @@ }, { "schema": { - "type": "string" + "type": "string", + "pattern": "^pmfa_(?:lid|botid)_[1-9]\\d*$" }, "required": true, "name": "contactId", @@ -21449,7 +25883,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -21459,7 +25903,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -21469,7 +25923,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -21479,7 +25943,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -21489,7 +25963,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -21504,7 +25988,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `contacts:read`" } }, - "/api/{session}/contacts/{contactId}/devices": { + "/messaging/{session}/contacts/{contactId}/devices": { "get": { "operationId": "getUserDevices", "tags": [ @@ -21528,7 +26012,8 @@ }, { "schema": { - "type": "string" + "type": "string", + "pattern": "^pmfa_(?:lid|botid)_[1-9]\\d*$" }, "required": true, "name": "contactId", @@ -21537,7 +26022,7 @@ ], "responses": { "200": { - "description": "Linked-device JIDs", + "description": "Linked devices", "content": { "application/json": { "schema": { @@ -21551,7 +26036,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -21561,7 +26056,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -21571,7 +26076,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -21581,7 +26096,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -21591,7 +26116,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -21606,7 +26141,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `contacts:read`" } }, - "/api/{session}/contacts/{contactId}/business-profile": { + "/messaging/{session}/contacts/{contactId}/business-profile": { "get": { "operationId": "getBusinessProfile", "tags": [ @@ -21630,7 +26165,8 @@ }, { "schema": { - "type": "string" + "type": "string", + "pattern": "^pmfa_(?:lid|botid)_[1-9]\\d*$" }, "required": true, "name": "contactId", @@ -21653,7 +26189,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -21663,7 +26209,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -21673,7 +26229,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -21683,7 +26249,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -21693,7 +26269,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -21708,7 +26294,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `contacts:read`" } }, - "/api/{session}/contacts/{contactId}/block": { + "/messaging/{session}/contacts/{contactId}/block": { "post": { "operationId": "blockContact", "tags": [ @@ -21732,7 +26318,8 @@ }, { "schema": { - "type": "string" + "type": "string", + "pattern": "^pmfa_(?:lid|botid)_[1-9]\\d*$" }, "required": true, "name": "contactId", @@ -21755,7 +26342,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -21765,7 +26362,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -21775,7 +26382,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -21785,7 +26402,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -21795,7 +26422,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -21810,7 +26447,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `contacts:manage`" } }, - "/api/{session}/contacts/{contactId}/unblock": { + "/messaging/{session}/contacts/{contactId}/unblock": { "post": { "operationId": "unblockContact", "tags": [ @@ -21834,7 +26471,8 @@ }, { "schema": { - "type": "string" + "type": "string", + "pattern": "^pmfa_(?:lid|botid)_[1-9]\\d*$" }, "required": true, "name": "contactId", @@ -21857,7 +26495,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -21867,7 +26515,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -21877,7 +26535,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -21887,7 +26555,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -21897,7 +26575,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -21912,7 +26600,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `contacts:manage`" } }, - "/api/{session}/business/linked-accounts": { + "/messaging/{session}/business/linked-accounts": { "get": { "operationId": "getBusinessLinkedAccounts", "tags": [ @@ -21951,7 +26639,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -21961,7 +26659,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -21971,7 +26679,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -21981,7 +26699,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -21991,7 +26719,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -22006,7 +26744,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `business:read`" } }, - "/api/{session}/business/eligibility": { + "/messaging/{session}/business/eligibility": { "get": { "operationId": "getBusinessEligibility", "tags": [ @@ -22045,7 +26783,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -22055,7 +26803,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -22065,7 +26823,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -22075,7 +26843,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -22085,7 +26863,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -22100,7 +26888,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `business:read`" } }, - "/api/{session}/business/profile": { + "/messaging/{session}/business/profile": { "get": { "operationId": "getOwnBusinessProfile", "tags": [ @@ -22139,7 +26927,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -22149,7 +26947,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -22159,7 +26967,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -22169,7 +26987,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -22179,7 +27007,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -22241,7 +27079,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -22251,7 +27099,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -22261,7 +27119,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -22271,7 +27139,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -22281,7 +27159,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -22296,7 +27184,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:write`" } }, - "/api/{session}/business/profile/cover-photo": { + "/messaging/{session}/business/profile/cover-photo": { "put": { "operationId": "setBusinessCoverPhoto", "tags": [ @@ -22345,7 +27233,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -22355,7 +27253,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -22365,7 +27273,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -22375,7 +27293,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -22385,7 +27313,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -22400,7 +27338,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:write`" } }, - "/api/{session}/business/profile/cover-photo/{coverPhotoId}": { + "/messaging/{session}/business/profile/cover-photo/{coverPhotoId}": { "delete": { "operationId": "deleteBusinessCoverPhoto", "tags": [ @@ -22449,7 +27387,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -22459,7 +27407,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -22469,7 +27427,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -22479,7 +27447,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -22489,7 +27467,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -22504,7 +27492,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:write`" } }, - "/api/{session}/business/compliance": { + "/messaging/{session}/business/compliance": { "get": { "operationId": "getBusinessMerchantCompliance", "tags": [ @@ -22543,7 +27531,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -22553,7 +27551,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -22563,7 +27571,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -22573,7 +27591,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -22583,7 +27611,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -22645,7 +27683,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -22655,7 +27703,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -22665,7 +27723,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -22675,7 +27743,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -22685,7 +27763,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -22700,7 +27788,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:write`" } }, - "/api/{session}/business/quick-replies": { + "/messaging/{session}/business/quick-replies": { "post": { "operationId": "createBusinessQuickReply", "tags": [ @@ -22749,7 +27837,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -22759,7 +27857,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -22769,7 +27877,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -22779,7 +27897,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -22789,7 +27917,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -22841,7 +27979,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -22851,7 +27999,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -22861,7 +28019,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -22871,7 +28039,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -22881,7 +28059,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -22896,7 +28084,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:read`" } }, - "/api/{session}/business/quick-replies/{quickReplyId}": { + "/messaging/{session}/business/quick-replies/{quickReplyId}": { "put": { "operationId": "setBusinessQuickReply", "tags": [ @@ -22956,7 +28144,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -22966,7 +28164,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -22976,7 +28184,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -22986,7 +28204,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -22996,7 +28224,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -23059,7 +28297,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -23069,7 +28317,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -23079,7 +28337,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -23089,7 +28357,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -23099,7 +28377,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -23114,7 +28402,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:write`" } }, - "/api/{session}/business/catalog": { + "/messaging/{session}/business/catalog": { "get": { "operationId": "getBusinessCatalog", "tags": [ @@ -23140,10 +28428,10 @@ "schema": { "type": "string", "maxLength": 256, - "pattern": "^\\d{1,32}@(s\\.whatsapp\\.net|lid)$" + "pattern": "^pmfa_lid_[1-9]\\d*$" }, "required": true, - "name": "jid", + "name": "id", "in": "query" }, { @@ -23202,7 +28490,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -23212,7 +28510,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -23222,7 +28530,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -23232,7 +28550,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -23242,7 +28570,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -23252,7 +28590,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "upstream_error", + "code": "upstream_failure", + "message": "The messaging provider could not complete the request.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#upstream-failure" } } } @@ -23304,7 +28652,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -23314,7 +28672,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -23324,7 +28692,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -23334,7 +28712,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -23344,7 +28732,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -23359,7 +28757,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:write`" } }, - "/api/{session}/business/catalog/cart": { + "/messaging/{session}/business/catalog/cart": { "patch": { "operationId": "setBusinessCartEnabled", "tags": [ @@ -23408,7 +28806,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -23418,7 +28826,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -23428,7 +28846,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -23438,7 +28866,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -23448,7 +28886,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -23463,7 +28911,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:write`" } }, - "/api/{session}/business/products/{productId}": { + "/messaging/{session}/business/products/{productId}": { "get": { "operationId": "getBusinessProduct", "tags": [ @@ -23498,10 +28946,10 @@ "schema": { "type": "string", "maxLength": 256, - "pattern": "^\\d{1,32}@(s\\.whatsapp\\.net|lid)$" + "pattern": "^pmfa_lid_[1-9]\\d*$" }, "required": true, - "name": "jid", + "name": "id", "in": "query" } ], @@ -23521,7 +28969,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -23531,7 +28989,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -23541,7 +29009,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -23551,7 +29029,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -23561,7 +29049,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -23571,7 +29069,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "upstream_error", + "code": "upstream_failure", + "message": "The messaging provider could not complete the request.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#upstream-failure" } } } @@ -23642,7 +29150,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -23652,7 +29170,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -23662,7 +29190,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -23672,7 +29210,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -23682,7 +29230,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -23743,7 +29301,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -23753,7 +29321,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -23763,7 +29341,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -23773,7 +29361,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -23783,7 +29381,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -23798,7 +29406,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:write`" } }, - "/api/{session}/business/products": { + "/messaging/{session}/business/products": { "post": { "operationId": "createBusinessProduct", "tags": [ @@ -23847,7 +29455,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -23857,7 +29475,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -23867,7 +29495,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -23877,7 +29515,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -23887,7 +29535,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -23902,7 +29560,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:write`" } }, - "/api/{session}/business/products/{productId}/visibility": { + "/messaging/{session}/business/products/{productId}/visibility": { "patch": { "operationId": "setBusinessProductVisibility", "tags": [ @@ -23960,7 +29618,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -23970,7 +29638,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -23980,7 +29658,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -23990,7 +29678,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -24000,7 +29698,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -24015,7 +29723,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:write`" } }, - "/api/{session}/business/products/{productId}/appeal": { + "/messaging/{session}/business/products/{productId}/appeal": { "post": { "operationId": "appealBusinessProduct", "tags": [ @@ -24073,7 +29781,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -24083,7 +29801,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -24093,7 +29821,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -24103,7 +29841,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -24113,7 +29861,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -24128,7 +29886,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:write`" } }, - "/api/{session}/business/collections": { + "/messaging/{session}/business/collections": { "get": { "operationId": "getBusinessCollections", "tags": [ @@ -24154,10 +29912,10 @@ "schema": { "type": "string", "maxLength": 256, - "pattern": "^\\d{1,32}@(s\\.whatsapp\\.net|lid)$" + "pattern": "^pmfa_lid_[1-9]\\d*$" }, "required": true, - "name": "jid", + "name": "id", "in": "query" }, { @@ -24226,7 +29984,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -24236,7 +30004,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -24246,7 +30024,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -24256,7 +30044,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -24266,7 +30064,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -24276,7 +30084,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "upstream_error", + "code": "upstream_failure", + "message": "The messaging provider could not complete the request.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#upstream-failure" } } } @@ -24338,7 +30156,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -24348,7 +30176,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -24358,7 +30196,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -24368,7 +30216,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -24378,7 +30236,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -24393,7 +30261,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:write`" } }, - "/api/{session}/business/collections/{collectionId}": { + "/messaging/{session}/business/collections/{collectionId}": { "get": { "operationId": "getBusinessCollection", "tags": [ @@ -24428,10 +30296,10 @@ "schema": { "type": "string", "maxLength": 256, - "pattern": "^\\d{1,32}@(s\\.whatsapp\\.net|lid)$" + "pattern": "^pmfa_lid_[1-9]\\d*$" }, "required": true, - "name": "jid", + "name": "id", "in": "query" }, { @@ -24490,7 +30358,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -24500,7 +30378,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -24510,7 +30398,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -24520,7 +30418,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -24530,7 +30438,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -24540,7 +30458,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "upstream_error", + "code": "upstream_failure", + "message": "The messaging provider could not complete the request.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#upstream-failure" } } } @@ -24611,7 +30539,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -24621,7 +30559,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -24631,7 +30579,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -24641,7 +30599,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -24651,7 +30619,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -24712,7 +30690,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -24722,7 +30710,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -24732,7 +30730,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -24742,7 +30750,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -24752,7 +30770,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -24767,7 +30795,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:write`" } }, - "/api/{session}/business/collections/reorder": { + "/messaging/{session}/business/collections/reorder": { "post": { "operationId": "reorderBusinessCollections", "tags": [ @@ -24816,7 +30844,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -24826,7 +30864,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -24836,7 +30884,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -24846,7 +30904,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -24856,7 +30924,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -24871,7 +30949,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:write`" } }, - "/api/{session}/business/collections/{collectionId}/appeal": { + "/messaging/{session}/business/collections/{collectionId}/appeal": { "post": { "operationId": "appealBusinessCollection", "tags": [ @@ -24929,7 +31007,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -24939,7 +31027,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -24949,7 +31047,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -24959,7 +31067,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -24969,7 +31087,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -24984,7 +31112,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:write`" } }, - "/api/{session}/business/orders/{orderId}/lookup": { + "/messaging/{session}/business/orders/{orderId}/lookup": { "post": { "operationId": "getBusinessOrder", "tags": [ @@ -25042,7 +31170,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -25052,7 +31190,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -25062,7 +31210,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -25072,7 +31230,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -25082,7 +31250,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -25092,7 +31270,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "upstream_error", + "code": "upstream_failure", + "message": "The messaging provider could not complete the request.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#upstream-failure" } } } @@ -25107,11 +31295,11 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `business:read`" } }, - "/api/{session}/lids/resolve": { + "/messaging/{session}/identities/resolve": { "get": { - "operationId": "resolveLIDs", + "operationId": "resolveIdentity", "tags": [ - "LIDs" + "Identities" ], "summary": "Resolve a user alias to a stable user ID", "security": [ @@ -25139,21 +31327,13 @@ }, { "schema": { - "type": "string" + "type": "string", + "pattern": "^pmfa_lid_[1-9]\\d*$" }, "required": false, "name": "id", "in": "query" }, - { - "schema": { - "type": "string" - }, - "required": false, - "name": "lid", - "in": "query", - "deprecated": true - }, { "schema": { "type": "string", @@ -25180,7 +31360,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ResolveLIDsResponse" + "$ref": "#/components/schemas/ResolveIdentityResponse" } } } @@ -25190,7 +31370,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -25200,7 +31390,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -25210,7 +31410,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -25220,7 +31430,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -25230,7 +31450,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -25245,7 +31475,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `contacts:read`" } }, - "/api/{session}/users/{id}/security-code": { + "/messaging/{session}/users/{id}/security-code": { "get": { "operationId": "getUserSecurityCode", "tags": [ @@ -25270,7 +31500,7 @@ { "schema": { "type": "string", - "pattern": "^\\d+@lid$" + "pattern": "^pmfa_lid_[1-9]\\d*$" }, "required": true, "name": "id", @@ -25293,7 +31523,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -25303,7 +31543,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -25313,7 +31563,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -25323,7 +31583,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -25333,7 +31603,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -25348,7 +31628,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `contacts:read`" } }, - "/api/{session}/channels": { + "/messaging/{session}/channels": { "get": { "operationId": "listChannels", "tags": [ @@ -25387,7 +31667,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -25397,7 +31687,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -25407,7 +31707,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -25417,7 +31727,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -25427,7 +31747,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -25488,7 +31818,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -25498,7 +31838,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -25508,7 +31858,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -25518,7 +31878,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -25528,7 +31898,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -25543,7 +31923,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `channels:manage`" } }, - "/api/{session}/channels/{id}": { + "/messaging/{session}/channels/{id}": { "get": { "operationId": "getChannel", "tags": [ @@ -25590,7 +31970,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -25600,7 +31990,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -25610,7 +32010,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -25620,7 +32030,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -25630,7 +32050,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -25690,7 +32120,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -25700,7 +32140,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -25710,7 +32160,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -25720,7 +32180,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -25730,7 +32200,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -25740,7 +32220,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "upstream_error", + "code": "upstream_failure", + "message": "The messaging provider could not complete the request.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#upstream-failure" } } } @@ -25755,7 +32245,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `channels:manage`" } }, - "/api/{session}/channels/{id}/messages": { + "/messaging/{session}/channels/{id}/messages": { "get": { "operationId": "listChannelMessages", "tags": [ @@ -25823,7 +32313,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -25833,7 +32333,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -25843,7 +32353,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -25853,7 +32373,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -25863,7 +32393,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -25878,7 +32418,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `channels:read`" } }, - "/api/{session}/channels/{id}/message-updates": { + "/messaging/{session}/channels/{id}/message-updates": { "get": { "operationId": "listChannelMessageUpdates", "tags": [ @@ -25956,7 +32496,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -25966,7 +32516,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -25976,7 +32536,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -25986,7 +32556,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -25996,7 +32576,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -26011,7 +32601,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `channels:read`" } }, - "/api/{session}/channels/{id}/messages/{serverId}/viewed": { + "/messaging/{session}/channels/{id}/messages/{serverId}/viewed": { "post": { "operationId": "markChannelMessageViewed", "tags": [ @@ -26068,7 +32658,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -26078,7 +32678,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -26088,7 +32698,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -26098,7 +32718,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -26108,7 +32738,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -26123,7 +32763,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `channels:manage`" } }, - "/api/{session}/channels/{id}/messages/{serverId}/reaction": { + "/messaging/{session}/channels/{id}/messages/{serverId}/reaction": { "post": { "operationId": "reactToChannelMessage", "tags": [ @@ -26189,7 +32829,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -26199,7 +32849,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -26209,7 +32869,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -26219,7 +32889,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -26229,7 +32909,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -26244,7 +32934,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `channels:manage`" } }, - "/api/{session}/channels/{id}/live-updates": { + "/messaging/{session}/channels/{id}/live-updates": { "post": { "operationId": "subscribeChannelLiveUpdates", "tags": [ @@ -26291,7 +32981,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -26301,7 +33001,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -26311,7 +33021,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -26321,7 +33041,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -26331,7 +33061,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -26346,7 +33086,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `channels:read`" } }, - "/api/{session}/channels/{id}/follow": { + "/messaging/{session}/channels/{id}/follow": { "post": { "operationId": "followChannel", "tags": [ @@ -26393,7 +33133,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -26403,7 +33153,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -26413,7 +33173,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -26423,7 +33193,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -26433,7 +33213,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -26448,7 +33238,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `channels:manage`" } }, - "/api/{session}/channels/{id}/unfollow": { + "/messaging/{session}/channels/{id}/unfollow": { "post": { "operationId": "unfollowChannel", "tags": [ @@ -26495,7 +33285,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -26505,7 +33305,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -26515,7 +33325,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -26525,7 +33345,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -26535,7 +33365,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -26550,7 +33390,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `channels:manage`" } }, - "/api/{session}/channels/{id}/mute": { + "/messaging/{session}/channels/{id}/mute": { "post": { "operationId": "muteChannel", "tags": [ @@ -26597,7 +33437,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -26607,7 +33457,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -26617,7 +33477,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -26627,7 +33497,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -26637,7 +33517,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -26652,7 +33542,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `channels:manage`" } }, - "/api/{session}/channels/{id}/unmute": { + "/messaging/{session}/channels/{id}/unmute": { "post": { "operationId": "unmuteChannel", "tags": [ @@ -26699,7 +33589,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -26709,7 +33609,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -26719,7 +33629,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -26729,7 +33649,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -26739,7 +33669,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -26754,7 +33694,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `channels:manage`" } }, - "/api/{session}/presence": { + "/messaging/{session}/presence": { "post": { "operationId": "setPresence", "tags": [ @@ -26812,7 +33752,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -26822,7 +33772,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -26832,7 +33792,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -26842,7 +33812,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -26852,7 +33832,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -26904,7 +33894,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -26914,7 +33914,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -26924,7 +33934,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -26934,7 +33954,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -26944,7 +33974,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -26959,7 +33999,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `presence:read`" } }, - "/api/{session}/presence/{chatId}": { + "/messaging/{session}/presence/{conversation}": { "get": { "operationId": "getChatPresence", "tags": [ @@ -26986,7 +34026,7 @@ "type": "string" }, "required": true, - "name": "chatId", + "name": "conversation", "in": "path" } ], @@ -27006,7 +34046,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -27016,7 +34066,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -27026,7 +34086,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -27036,7 +34106,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -27046,7 +34126,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -27061,7 +34151,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `presence:read`" } }, - "/api/{session}/presence/{chatId}/subscribe": { + "/messaging/{session}/presence/{conversation}/subscribe": { "post": { "operationId": "subscribePresence", "tags": [ @@ -27088,7 +34178,7 @@ "type": "string" }, "required": true, - "name": "chatId", + "name": "conversation", "in": "path" } ], @@ -27118,7 +34208,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -27128,7 +34228,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -27138,7 +34248,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -27148,7 +34268,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -27158,7 +34288,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "rate_limit_error", + "code": "rate_limit_exceeded", + "message": "The request limit was reached. Follow Retry-After when supplied.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#rate-limit-exceeded" } } } @@ -27168,7 +34308,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -27183,7 +34333,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `presence:observe`" } }, - "/api/projects/{projectId}/safe-mode": { + "/messaging/projects/{projectId}/safe-mode": { "get": { "operationId": "getProjectSafeMode", "tags": [ @@ -27223,7 +34373,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -27233,7 +34393,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -27243,7 +34413,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -27253,7 +34433,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -27263,7 +34453,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -27368,7 +34568,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -27378,7 +34588,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -27388,7 +34608,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "entitlement_required", + "message": "The account needs the required entitlement for this action.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#entitlement-required" } } } @@ -27398,7 +34628,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -27408,7 +34648,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -27418,7 +34668,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -27428,7 +34688,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "service_unavailable", + "message": "A required service is unavailable. Check completion before repeating a write.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#service-unavailable" } } } @@ -27439,7 +34709,7 @@ } } }, - "/api/{session}/safe-mode": { + "/messaging/{session}/safe-mode": { "get": { "operationId": "getSessionSafeMode", "tags": [ @@ -27479,7 +34749,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -27489,7 +34769,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -27499,7 +34789,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -27509,7 +34809,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -27519,7 +34829,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -27621,7 +34941,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -27631,7 +34961,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -27641,7 +34981,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "entitlement_required", + "message": "The account needs the required entitlement for this action.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#entitlement-required" } } } @@ -27651,7 +35001,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -27661,7 +35021,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -27671,7 +35041,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -27681,7 +35061,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "service_unavailable", + "message": "A required service is unavailable. Check completion before repeating a write.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#service-unavailable" } } } @@ -27695,7 +35085,7 @@ ] } }, - "/api/projects/{projectId}/warmup-plan": { + "/messaging/projects/{projectId}/warmup-plan": { "get": { "operationId": "getProjectWarmupPlan", "tags": [ @@ -27735,7 +35125,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -27745,7 +35145,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -27755,7 +35165,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -27765,7 +35185,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -27775,7 +35205,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -27851,7 +35291,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -27861,7 +35311,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -27871,7 +35331,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "entitlement_required", + "message": "The account needs the required entitlement for this action.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#entitlement-required" } } } @@ -27881,7 +35351,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -27891,7 +35371,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -27901,7 +35391,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -27911,7 +35411,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "service_unavailable", + "message": "A required service is unavailable. Check completion before repeating a write.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#service-unavailable" } } } @@ -27922,7 +35432,7 @@ } } }, - "/api/projects/{projectId}/health-policy": { + "/messaging/projects/{projectId}/health-policy": { "get": { "operationId": "getProjectHealthPolicy", "tags": [ @@ -27962,7 +35472,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -27972,7 +35492,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -27982,7 +35512,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -27992,7 +35532,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -28002,7 +35552,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -28063,7 +35623,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -28073,7 +35643,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -28083,7 +35663,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -28093,7 +35683,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -28103,19 +35703,17 @@ "content": { "application/json": { "schema": { - "type": "object", - "properties": { - "error": { - "type": "string" - }, - "code": { - "type": "string" - } + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "conflict_error", + "code": "state_conflict", + "message": "The request conflicts with the resource state.", + "param": null }, - "required": [ - "error", - "code" - ] + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#state-conflict" } } } @@ -28125,7 +35723,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -28136,7 +35744,7 @@ } } }, - "/api/projects/{projectId}/insurance-evidence": { + "/messaging/projects/{projectId}/insurance-evidence": { "get": { "operationId": "getProjectInsuranceEvidence", "tags": [ @@ -28177,7 +35785,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -28187,7 +35805,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -28197,7 +35825,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -28207,7 +35845,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -28217,7 +35865,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -28285,7 +35943,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -28295,7 +35963,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -28305,7 +35983,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -28315,7 +36003,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -28325,7 +36023,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -28335,7 +36043,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "service_unavailable", + "message": "A required service is unavailable. Check completion before repeating a write.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#service-unavailable" } } } @@ -28346,7 +36064,7 @@ } } }, - "/api/projects/{projectId}/observation-policy": { + "/messaging/projects/{projectId}/observation-policy": { "get": { "operationId": "getProjectObservationPolicy", "tags": [ @@ -28387,7 +36105,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -28397,7 +36125,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -28407,7 +36145,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -28417,7 +36165,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -28427,7 +36185,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -28527,7 +36295,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -28537,7 +36315,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -28547,7 +36335,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -28557,7 +36355,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -28567,7 +36375,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "conflict_error", + "code": "state_conflict", + "message": "The request conflicts with the resource state.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#state-conflict" } } } @@ -28577,7 +36395,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -28587,7 +36415,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "service_unavailable", + "message": "A required service is unavailable. Check completion before repeating a write.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#service-unavailable" } } } @@ -28599,7 +36437,7 @@ "description": "**Required scope:** `presence:observe`" } }, - "/api/{session}/observation-policy": { + "/messaging/{session}/observation-policy": { "get": { "operationId": "getSessionObservationPolicy", "tags": [ @@ -28640,7 +36478,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -28650,7 +36498,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -28660,7 +36518,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -28670,7 +36538,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -28680,7 +36558,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -28787,7 +36675,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -28797,7 +36695,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -28807,7 +36715,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -28817,7 +36735,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -28827,7 +36755,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "conflict_error", + "code": "state_conflict", + "message": "The request conflicts with the resource state.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#state-conflict" } } } @@ -28837,7 +36775,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -28847,7 +36795,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "service_unavailable", + "message": "A required service is unavailable. Check completion before repeating a write.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#service-unavailable" } } } @@ -28862,7 +36820,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `presence:observe`" } }, - "/api/{session}/profile": { + "/messaging/{session}/profile": { "get": { "operationId": "getProfile", "tags": [ @@ -28901,7 +36859,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -28911,7 +36879,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -28921,7 +36899,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -28931,7 +36919,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -28941,7 +36939,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -28956,7 +36964,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:read`" } }, - "/api/{session}/profile/name": { + "/messaging/{session}/profile/name": { "put": { "operationId": "setProfileName", "tags": [ @@ -29004,7 +37012,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -29014,7 +37032,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -29024,7 +37052,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -29034,7 +37072,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -29044,7 +37092,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -29059,7 +37117,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:write`" } }, - "/api/{session}/profile/status": { + "/messaging/{session}/profile/status": { "put": { "operationId": "setProfileStatus", "tags": [ @@ -29107,7 +37165,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -29117,7 +37185,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -29127,7 +37205,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -29137,7 +37225,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -29147,7 +37245,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -29162,7 +37270,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:write`" } }, - "/api/{session}/profile/picture": { + "/messaging/{session}/profile/picture": { "put": { "operationId": "setProfilePicture", "tags": [ @@ -29210,7 +37318,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -29220,7 +37338,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -29230,7 +37358,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -29240,7 +37378,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -29250,7 +37398,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -29302,7 +37460,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -29312,7 +37480,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -29322,7 +37500,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -29332,7 +37520,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -29342,7 +37540,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -29357,7 +37565,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:write`" } }, - "/api/{session}/privacy": { + "/messaging/{session}/privacy": { "get": { "operationId": "getPrivacySettings", "tags": [ @@ -29396,7 +37604,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -29406,7 +37624,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -29416,7 +37644,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -29426,7 +37664,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -29436,7 +37684,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -29451,7 +37709,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:read`" } }, - "/api/{session}/privacy/disappearing/default": { + "/messaging/{session}/privacy/disappearing/default": { "put": { "operationId": "setDefaultDisappearingTimer", "tags": [ @@ -29499,7 +37757,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -29509,7 +37777,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -29519,7 +37797,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -29529,7 +37817,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -29539,7 +37837,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -29554,7 +37862,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:write`" } }, - "/api/{session}/privacy/{setting}": { + "/messaging/{session}/privacy/{setting}": { "put": { "operationId": "setPrivacySetting", "tags": [ @@ -29622,7 +37930,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -29632,7 +37950,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -29642,7 +37970,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -29652,7 +37990,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -29662,7 +38010,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -29677,7 +38035,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `profile:write`" } }, - "/api/{session}/labels": { + "/messaging/{session}/labels": { "get": { "operationId": "listLabels", "tags": [ @@ -29728,7 +38086,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -29738,7 +38106,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -29748,7 +38126,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -29758,7 +38146,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -29768,7 +38166,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -29829,7 +38237,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -29839,7 +38257,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -29849,7 +38277,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -29859,7 +38297,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -29869,7 +38317,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -29884,7 +38342,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `labels:manage`" } }, - "/api/{session}/labels/{labelId}": { + "/messaging/{session}/labels/{labelId}": { "put": { "operationId": "updateLabel", "tags": [ @@ -29940,7 +38398,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -29950,7 +38418,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -29960,7 +38438,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -29970,7 +38458,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -29980,7 +38478,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "conflict_error", + "code": "state_conflict", + "message": "The request conflicts with the resource state.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#state-conflict" } } } @@ -29990,7 +38498,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -30050,7 +38568,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -30060,7 +38588,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -30070,7 +38608,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -30080,7 +38628,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -30090,7 +38648,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -30105,7 +38673,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `labels:manage`" } }, - "/api/{session}/labels/chats/{chatId}": { + "/messaging/{session}/labels/chats/{conversation}": { "get": { "operationId": "getChatLabels", "tags": [ @@ -30132,7 +38700,7 @@ "type": "string" }, "required": true, - "name": "chatId", + "name": "conversation", "in": "path" }, { @@ -30164,7 +38732,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -30174,7 +38752,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -30184,7 +38772,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -30194,7 +38792,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -30204,7 +38812,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -30244,7 +38862,7 @@ "type": "string" }, "required": true, - "name": "chatId", + "name": "conversation", "in": "path" } ], @@ -30273,7 +38891,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -30283,7 +38911,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -30293,7 +38931,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -30303,7 +38951,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -30313,7 +38971,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "conflict_error", + "code": "state_conflict", + "message": "The request conflicts with the resource state.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#state-conflict" } } } @@ -30323,7 +38991,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -30338,7 +39016,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `labels:manage`" } }, - "/api/webhooks": { + "/messaging/webhooks": { "get": { "operationId": "listWebhooks", "tags": [ @@ -30367,7 +39045,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -30377,7 +39065,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -30387,7 +39085,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -30397,7 +39105,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -30407,7 +39125,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -30455,7 +39183,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -30465,7 +39203,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -30475,7 +39223,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -30485,7 +39243,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -30495,7 +39263,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -30507,7 +39285,7 @@ "description": "**Required scope:** `webhooks:manage`" } }, - "/api/webhooks/{id}": { + "/messaging/webhooks/{id}": { "get": { "operationId": "getWebhook", "tags": [ @@ -30546,7 +39324,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -30556,7 +39344,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -30566,7 +39364,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -30576,7 +39384,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -30586,7 +39404,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -30644,7 +39472,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -30654,7 +39492,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -30664,7 +39512,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -30674,7 +39532,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -30684,7 +39552,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -30733,7 +39611,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -30743,7 +39631,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -30753,7 +39651,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -30763,7 +39671,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -30773,7 +39691,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -30785,7 +39713,7 @@ "description": "**Required scope:** `webhooks:manage`" } }, - "/api/media/{id}": { + "/messaging/media/{id}": { "get": { "operationId": "downloadMedia", "tags": [ @@ -30820,7 +39748,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -30830,7 +39768,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -30840,7 +39788,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -30850,7 +39808,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -30860,7 +39828,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -30875,7 +39853,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `media:read`" } }, - "/api/media/{id}/info": { + "/messaging/media/{id}/info": { "get": { "operationId": "getMediaInfo", "tags": [ @@ -30914,7 +39892,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -30924,7 +39912,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -30934,7 +39932,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -30944,7 +39952,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -30954,7 +39972,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -30969,7 +39997,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `media:read`" } }, - "/api/media/{id}/download-and-save": { + "/messaging/media/{id}/download-and-save": { "post": { "operationId": "downloadAndSaveMedia", "tags": [ @@ -31008,7 +40036,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -31018,7 +40056,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -31028,7 +40076,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -31038,7 +40096,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -31048,7 +40116,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -31063,7 +40141,7 @@ "description": "**Protocols:** Linked Device API\n\n**Required scope:** `media:manage`" } }, - "/api/projects/{projectSlug}/templates": { + "/messaging/projects/{projectSlug}/templates": { "get": { "operationId": "listProjectTemplates", "tags": [ @@ -31102,7 +40180,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -31112,7 +40200,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -31122,7 +40220,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -31132,7 +40240,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -31142,7 +40260,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -31200,7 +40328,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -31210,7 +40348,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -31220,7 +40368,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -31230,7 +40388,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -31240,7 +40408,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -31252,7 +40430,7 @@ "description": "**Required scope:** `templates:manage`" } }, - "/api/projects/{projectSlug}/templates/{id}": { + "/messaging/projects/{projectSlug}/templates/{id}": { "get": { "operationId": "getProjectTemplate", "tags": [ @@ -31299,7 +40477,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -31309,7 +40497,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -31319,7 +40517,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -31329,7 +40537,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -31339,7 +40557,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -31405,7 +40633,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -31415,7 +40653,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -31425,7 +40673,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -31435,7 +40693,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -31445,7 +40713,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -31502,7 +40780,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -31512,7 +40800,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -31522,7 +40820,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -31532,7 +40840,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -31542,7 +40860,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -31554,7 +40882,7 @@ "description": "**Required scope:** `templates:manage`" } }, - "/api/projects/{projectSlug}/templates/{id}/preview": { + "/messaging/projects/{projectSlug}/templates/{id}/preview": { "post": { "operationId": "previewProjectTemplate", "tags": [ @@ -31610,7 +40938,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -31620,7 +40958,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -31630,7 +40978,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -31640,7 +40998,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -31650,7 +41018,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -31662,7 +41040,7 @@ "description": "**Required scope:** `templates:read`" } }, - "/api/projects/{projectSlug}/templates/{id}/submit": { + "/messaging/projects/{projectSlug}/templates/{id}/submit": { "post": { "operationId": "submitProjectTemplateToMeta", "tags": [ @@ -31719,7 +41097,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -31729,7 +41117,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -31739,7 +41137,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -31749,7 +41157,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -31759,7 +41177,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -31770,7 +41198,7 @@ } } }, - "/api/projects/{projectSlug}/campaigns": { + "/messaging/projects/{projectSlug}/campaigns": { "get": { "operationId": "listCampaigns", "tags": [ @@ -31809,7 +41237,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -31819,7 +41257,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -31829,7 +41277,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -31839,7 +41297,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -31849,7 +41317,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -31907,7 +41385,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -31917,7 +41405,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -31927,7 +41425,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "entitlement_required", + "message": "The account needs the required entitlement for this action.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#entitlement-required" } } } @@ -31937,7 +41445,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -31947,7 +41465,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -31957,7 +41485,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -31969,7 +41507,7 @@ "description": "**Required scope:** `campaigns:manage`" } }, - "/api/projects/{projectSlug}/campaigns/{id}": { + "/messaging/projects/{projectSlug}/campaigns/{id}": { "get": { "operationId": "getCampaign", "tags": [ @@ -32016,7 +41554,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -32026,7 +41574,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -32036,7 +41594,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "entitlement_required", + "message": "The account needs the required entitlement for this action.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#entitlement-required" } } } @@ -32046,7 +41614,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -32056,7 +41634,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -32066,7 +41654,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -32078,7 +41676,7 @@ "description": "**Required scope:** `campaigns:read`" } }, - "/api/projects/{projectSlug}/campaigns/{id}/analytics": { + "/messaging/projects/{projectSlug}/campaigns/{id}/analytics": { "get": { "operationId": "getCampaignAnalytics", "tags": [ @@ -32125,7 +41723,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -32135,7 +41743,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -32145,7 +41763,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "entitlement_required", + "message": "The account needs the required entitlement for this action.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#entitlement-required" } } } @@ -32155,7 +41783,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -32165,7 +41803,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -32175,7 +41823,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -32187,7 +41845,7 @@ "description": "**Required scope:** `campaigns:read`" } }, - "/api/projects/{projectSlug}/campaigns/{id}/launch": { + "/messaging/projects/{projectSlug}/campaigns/{id}/launch": { "post": { "operationId": "launchCampaign", "tags": [ @@ -32243,7 +41901,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -32253,7 +41921,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -32263,7 +41941,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "entitlement_required", + "message": "The account needs the required entitlement for this action.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#entitlement-required" } } } @@ -32273,7 +41961,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -32283,7 +41981,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -32293,7 +42001,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -32305,7 +42023,7 @@ "description": "**Required scope:** `campaigns:manage`" } }, - "/api/projects/{projectSlug}/campaigns/{id}/pause": { + "/messaging/projects/{projectSlug}/campaigns/{id}/pause": { "post": { "operationId": "pauseCampaign", "tags": [ @@ -32352,7 +42070,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -32362,7 +42090,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -32372,7 +42110,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "entitlement_required", + "message": "The account needs the required entitlement for this action.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#entitlement-required" } } } @@ -32382,7 +42130,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -32392,7 +42150,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -32402,7 +42170,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -32414,7 +42192,7 @@ "description": "**Required scope:** `campaigns:manage`" } }, - "/api/projects/{projectSlug}/campaigns/{id}/resume": { + "/messaging/projects/{projectSlug}/campaigns/{id}/resume": { "post": { "operationId": "resumeCampaign", "tags": [ @@ -32461,7 +42239,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -32471,7 +42259,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -32481,7 +42279,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "entitlement_required", + "message": "The account needs the required entitlement for this action.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#entitlement-required" } } } @@ -32491,7 +42299,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -32501,7 +42319,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -32511,7 +42339,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -32523,7 +42361,7 @@ "description": "**Required scope:** `campaigns:manage`" } }, - "/api/projects/{projectSlug}/campaigns/{id}/stop": { + "/messaging/projects/{projectSlug}/campaigns/{id}/stop": { "post": { "operationId": "stopCampaign", "tags": [ @@ -32570,7 +42408,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -32580,7 +42428,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -32590,7 +42448,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "entitlement_required", + "message": "The account needs the required entitlement for this action.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#entitlement-required" } } } @@ -32600,7 +42468,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -32610,7 +42488,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -32620,7 +42508,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -32632,7 +42530,7 @@ "description": "**Required scope:** `campaigns:manage`" } }, - "/api/projects/{projectSlug}/campaigns/{id}/requeue": { + "/messaging/projects/{projectSlug}/campaigns/{id}/requeue": { "post": { "operationId": "requeueCampaign", "tags": [ @@ -32688,7 +42586,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -32698,7 +42606,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -32708,7 +42626,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "entitlement_required", + "message": "The account needs the required entitlement for this action.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#entitlement-required" } } } @@ -32718,7 +42646,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -32728,7 +42666,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -32738,7 +42686,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -32750,7 +42708,7 @@ "description": "**Required scope:** `campaigns:manage`" } }, - "/api/quicklinks": { + "/messaging/quicklinks": { "post": { "operationId": "createQuickLink", "tags": [ @@ -32789,7 +42747,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -32799,7 +42767,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -32809,7 +42787,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -32819,7 +42807,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -32829,7 +42827,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -32840,7 +42848,7 @@ } } }, - "/api/quicklinks/{id}": { + "/messaging/quicklinks/{id}": { "get": { "operationId": "getQuickLink", "tags": [ @@ -32879,7 +42887,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -32889,7 +42907,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -32899,7 +42927,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -32909,7 +42947,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -32919,7 +42967,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -32984,7 +43042,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "invalid_parameter", + "message": "Correct the invalid request field.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-parameter" } } } @@ -32994,7 +43062,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "authentication_error", + "code": "invalid_credential", + "message": "Supply a valid credential.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#invalid-credential" } } } @@ -33004,7 +43082,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "permission_error", + "code": "permission_denied", + "message": "The credential does not have access to this resource.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#permission-denied" } } } @@ -33014,7 +43102,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "invalid_request_error", + "code": "resource_not_found", + "message": "The resource is unavailable to this caller.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#resource-not-found" } } } @@ -33024,7 +43122,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/PublicError" + }, + "example": { + "error": { + "type": "api_error", + "code": "internal_error", + "message": "An unexpected service failure occurred. Keep the request ID for support.", + "param": null + }, + "data": null, + "docs": "https://docs.polymorfa.com/api/errors#internal-error" } } } @@ -33799,30 +43907,6 @@ } } }, - "session.qr": { - "post": { - "operationId": "onSessionQr", - "summary": "QR code issued for device linking", - "tags": [ - "Webhooks" - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SessionQREvent" - } - } - } - }, - "responses": { - "2XX": { - "description": "Return any 2xx status to acknowledge receipt. Non-2xx responses are retried according to the retry policy." - } - } - } - }, "session.connected": { "post": { "operationId": "onSessionConnected", diff --git a/contracts/drafts/bansafe/openapi.platform.json b/contracts/drafts/bansafe/openapi.platform.json index 33cd06c..f40a6c1 100644 --- a/contracts/drafts/bansafe/openapi.platform.json +++ b/contracts/drafts/bansafe/openapi.platform.json @@ -3,7 +3,7 @@ "info": { "title": "Polymorfa Console & Management API", "version": "1.0.0", - "description": "Complete console/management surface. Resource-oriented REST: `{param}` path variables, single-word action sub-resources.\n\nNamespaces decide inclusion:\n- `/v1/…` — **public registry** (150 endpoints): each endpoint declares either a scoped `pmfa_` organization key or a verified live dashboard JWT, or dashboard-only authorization when a specific user's authority is required. Only implemented handlers are published to customers and SDKs.\n- `/console/…` — **console-only** (52 endpoints): verified dashboard identity. EXCLUDED from the published spec; reason per endpoint.\n- `/admin/…` — **staff-only** (53 endpoints): Polymorfa internal staff. EXCLUDED.\n\nThe published customer spec = this document filtered to `x-audience: public` endpoints with an implemented runtime handler.\nMost transitional body/response schemas remain loose (`additionalProperties: true`); session-control operations use explicit strict schemas." + "description": "Complete console/management surface. Resource-oriented REST: `{param}` path variables, single-word action sub-resources.\n\nNamespaces decide inclusion:\n- `/platform/…` — **public registry** (138 endpoints): each endpoint declares either a scoped `pmfa_` organization key or a verified live dashboard JWT, or dashboard-only authorization when a specific user's authority is required. Only implemented handlers are published to customers and SDKs.\n- `/console/…` — **console-only** (64 endpoints): verified dashboard identity. EXCLUDED from the published spec; reason per endpoint.\n- `/admin/…` — **staff-only** (53 endpoints): Polymorfa internal staff. EXCLUDED.\n\nThe published customer spec = this document filtered to `x-audience: public` endpoints with an implemented runtime handler.\nMost transitional body/response schemas remain loose (`additionalProperties: true`); session-control operations use explicit strict schemas." }, "servers": [ { @@ -15,14 +15,14 @@ } ], "paths": { - "/v1/sessions": { + "/platform/sessions": { "get": { "operationId": "listPlatformSessions", "tags": [ "sessions" ], "summary": "List sessions", - "description": "Lists every session in the authenticated organization or selected project, including disconnected sessions and their latest status reason.\n\nOrganization API-key callers require `sessions:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Lists every session in the authenticated organization or selected project, including disconnected sessions and their latest status reason.\n\nRequires `sessions:read`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -97,14 +97,14 @@ } } }, - "/v1/sessions/{sessionId}/start": { + "/platform/sessions/{sessionId}/start": { "post": { "operationId": "startPlatformSession", "tags": [ "sessions" ], "summary": "Start a session", - "description": "Starts a stopped session or retries a session whose runtime failed. The identifier may be the session UUID or stable session slug.\n\nOrganization API-key callers require `sessions:manage`; project-token callers require the same action scope and are accepted only for `session` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Starts a stopped session or retries a session whose runtime failed. The identifier may be the session UUID or stable session slug.\n\nRequires `sessions:manage`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "session", "x-excluded-from-public": false, @@ -190,14 +190,14 @@ } } }, - "/v1/sessions/{sessionId}/stop": { + "/platform/sessions/{sessionId}/stop": { "post": { "operationId": "stopPlatformSession", "tags": [ "sessions" ], "summary": "Stop a session", - "description": "Requests an asynchronous stop for one session. The identifier may be the session UUID or stable session slug.\n\nOrganization API-key callers require `sessions:manage`; project-token callers require the same action scope and are accepted only for `session` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Requests an asynchronous stop for one session. The identifier may be the session UUID or stable session slug.\n\nRequires `sessions:manage`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "session", "x-excluded-from-public": false, @@ -280,14 +280,14 @@ } } }, - "/v1/sessions/{sessionId}": { + "/platform/sessions/{sessionId}": { "delete": { "operationId": "deletePlatformSession", "tags": [ "sessions" ], "summary": "Remove a session", - "description": "Permanently removes one session and terminates its active connection when needed.\n\nOrganization API-key callers require `sessions:manage`; project-token callers require the same action scope and are accepted only for `session` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Permanently removes one session and terminates its active connection when needed.\n\nRequires `sessions:manage`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "session", "x-excluded-from-public": false, @@ -362,7 +362,7 @@ "sessions" ], "summary": "Set a session tier override", - "description": "Sets an explicit session tier or clears the override with null.\n\nOrganization API-key callers require `sessions:manage`; project-token callers require the same action scope and are accepted only for `session` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Sets an explicit session tier or clears the override with null.\n\nRequires `sessions:manage`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "session", "x-excluded-from-public": false, @@ -445,14 +445,14 @@ } } }, - "/v1/sessions/stop": { + "/platform/sessions/stop": { "post": { "operationId": "stopSessions", "tags": [ "sessions" ], "summary": "Stop multiple sessions", - "description": "Requests asynchronous stops for up to 100 session UUIDs or slugs in the authenticated project scope.\n\nOrganization API-key callers require `sessions:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Requests asynchronous stops for up to 100 session UUIDs or slugs in the authenticated project scope.\n\nRequires `sessions:manage`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -524,14 +524,14 @@ } } }, - "/v1/sessions/delete": { + "/platform/sessions/delete": { "post": { "operationId": "deleteSessions", "tags": [ "sessions" ], "summary": "Remove multiple sessions", - "description": "Permanently removes up to 100 session UUIDs or slugs and terminates any rows that were still active.\n\nOrganization API-key callers require `sessions:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Permanently removes up to 100 session UUIDs or slugs and terminates any rows that were still active.\n\nRequires `sessions:manage`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -600,14 +600,14 @@ } } }, - "/v1/sessions/testing": { + "/platform/sessions/testing": { "post": { "operationId": "createTestingSession", "tags": [ "sessions" ], "summary": "Create a testing number", - "description": "Creates a disconnected simulated session with testMode enabled. Organization keys and dashboard bearers must provide a projectId in the body.\n\nOrganization API-key callers require `sessions:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Creates a disconnected simulated session with testMode enabled. Team API keys require projectId in the body.\n\nRequires `sessions:manage`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -682,14 +682,14 @@ } } }, - "/v1/bans": { + "/platform/bans": { "get": { "operationId": "listSessionBans", "tags": [ "bans" ], "summary": "List session bans", - "description": "Public Management API. Organization API-key callers require `sessions:read`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "description": "Public Management API. Requires a team API key with `sessions:read`. Project tokens are not accepted.", "x-audience": "public", "x-polymorfa-resource-boundary": "organization", "x-excluded-from-public": false, @@ -739,14 +739,14 @@ } } }, - "/v1/bans/active": { + "/platform/bans/active": { "get": { "operationId": "listActiveSessionBans", "tags": [ "bans" ], "summary": "List active session bans", - "description": "Public Management API. Organization API-key callers require `sessions:read`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "description": "Public Management API. Requires a team API key with `sessions:read`. Project tokens are not accepted.", "x-audience": "public", "x-polymorfa-resource-boundary": "organization", "x-excluded-from-public": false, @@ -796,14 +796,14 @@ } } }, - "/v1/bansafe/health": { + "/platform/bansafe/health": { "get": { "operationId": "listBanSafeHealth", "tags": [ "bansafe" ], "summary": "List number safety", - "description": "Lists present Health, findings counts, and the active Polymorfa restriction for every number in one project. Health is a 0 to 100 estimate from rules v1 or a validated learned model. It remains null until enough fresh evidence is available.\n\nOrganization API-key callers require `sessions:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Lists present Health, findings counts, and the active Polymorfa restriction for every number in one project. Health is a 0 to 100 estimate from rules v1 or a validated learned model. It remains null until enough fresh evidence is available.\n\nRequires `sessions:read`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -901,14 +901,14 @@ } } }, - "/v1/bansafe/health/{session}": { + "/platform/bansafe/health/{session}": { "get": { "operationId": "getBanSafeHealth", "tags": [ "bansafe" ], "summary": "Get number safety", - "description": "Returns one number's present Health estimate and model metadata, retained open and acknowledged findings with their observation times, directly observed account state, the active Polymorfa restriction, and how that restriction lifts. Recorded findings and observed state remain separate from the estimate.\n\nOrganization API-key callers require `sessions:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Returns one number's present Health estimate and model metadata, retained open and acknowledged findings with their observation times, directly observed account state, the active Polymorfa restriction, and how that restriction lifts. Recorded findings and observed state remain separate from the estimate.\n\nRequires `sessions:read`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -980,14 +980,14 @@ } } }, - "/v1/bansafe/health/{session}/history": { + "/platform/bansafe/health/{session}/history": { "get": { "operationId": "listBanSafeHealthHistory", "tags": [ "bansafe" ], "summary": "List number health history", - "description": "Returns the newest Health evaluations since the requested date, up to the limit, ordered oldest to newest. Each point carries its estimator source and version, evidence coverage, reliability, and availability reason.\n\nOrganization API-key callers require `sessions:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Returns the newest Health evaluations since the requested date, up to the limit, ordered oldest to newest. Each point carries its estimator source and version, evidence coverage, reliability, and availability reason.\n\nRequires `sessions:read`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -1079,14 +1079,14 @@ } } }, - "/v1/bansafe/signals": { + "/platform/bansafe/signals": { "get": { "operationId": "listBanSafeSignals", "tags": [ "bansafe" ], "summary": "List BanSafe telemetry signals", - "description": "Lists the bounded numeric, boolean, enum, histogram, and error-code aggregate signals that BanSafe can return. The catalogue contains no message content, recipient identifiers, or raw telemetry records.\n\nOrganization API-key callers require `sessions:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Lists the bounded numeric, boolean, enum, histogram, and error-code aggregate signals that BanSafe can return. The catalogue contains no message content, recipient identifiers, or raw telemetry records.\n\nRequires `sessions:read`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -1151,14 +1151,14 @@ } } }, - "/v1/bansafe/telemetry/{session}": { + "/platform/bansafe/telemetry/{session}": { "get": { "operationId": "getBanSafeTelemetry", "tags": [ "bansafe" ], "summary": "Get latest BanSafe telemetry", - "description": "Returns collection availability and the latest supported telemetry snapshot for one number. Empty collection is reported as not collected, not as a disabled collector.\n\nOrganization API-key callers require `sessions:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Returns collection availability and the latest supported telemetry snapshot for one number. Empty collection is reported as not collected, not as a disabled collector.\n\nRequires `sessions:read`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -1230,14 +1230,14 @@ } } }, - "/v1/bansafe/telemetry/{session}/history": { + "/platform/bansafe/telemetry/{session}/history": { "get": { "operationId": "listBanSafeTelemetryHistory", "tags": [ "bansafe" ], "summary": "List BanSafe telemetry history", - "description": "Returns the newest supported telemetry snapshots for one number. Signals are fixed-schema safe aggregates with explicit measured state; raw records and identifiers inside them are not returned.\n\nOrganization API-key callers require `sessions:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Returns the newest supported telemetry snapshots for one number. Signals are fixed-schema safe aggregates with explicit measured state; raw records and identifiers inside them are not returned.\n\nRequires `sessions:read`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -1353,14 +1353,14 @@ } } }, - "/v1/bansafe/collection": { + "/platform/bansafe/collection": { "get": { "operationId": "listBanSafeCollection", "tags": [ "bansafe" ], "summary": "List BanSafe collection status", - "description": "Lists telemetry collection freshness for the numbers in one project. Status is derived from ingested records and does not guess whether a collector flag is configured.\n\nOrganization API-key callers require `sessions:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Lists telemetry collection freshness for the numbers in one project. Status is derived from ingested records and does not guess whether a collector flag is configured.\n\nRequires `sessions:read`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -1458,14 +1458,14 @@ } } }, - "/v1/bansafe/health-actions": { + "/platform/bansafe/health-actions": { "get": { "operationId": "listBanSafeHealthActions", "tags": [ "bansafe" ], "summary": "List Health rule actions", - "description": "Lists the durable customer-visible outcomes of project Health rule actions, newest first. Internal leases, retry bookkeeping, runtime identifiers, and free-form outcomes are omitted.\n\nOrganization API-key callers require `sessions:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Lists the durable customer-visible outcomes of project Health rule actions, newest first. Internal leases, retry bookkeeping, runtime identifiers, and free-form outcomes are omitted.\n\nRequires `sessions:read`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -1588,14 +1588,14 @@ } } }, - "/v1/bansafe/findings": { + "/platform/bansafe/findings": { "get": { "operationId": "listBanSafeFindings", "tags": [ "bansafe" ], "summary": "List safety findings", - "description": "Lists safety findings across the organization, filterable by project, number, status, and severity. Evidence is numbers only and never contains message content or a recipient identifier.\n\nOrganization API-key callers require `sessions:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Lists safety findings across the organization, filterable by project, number, status, and severity. Evidence is numbers only and never contains message content or a recipient identifier.\n\nRequires `sessions:read`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -1729,7 +1729,7 @@ } } }, - "/v1/bansafe/findings/{findingId}/acknowledge": { + "/platform/bansafe/findings/{findingId}/acknowledge": { "post": { "operationId": "acknowledgeBanSafeFinding", "tags": [ @@ -1816,14 +1816,14 @@ } } }, - "/v1/bansafe/enforcement": { + "/platform/bansafe/enforcement": { "get": { "operationId": "listBanSafeEnforcement", "tags": [ "bansafe" ], "summary": "List number restrictions", - "description": "Lists every number Polymorfa is currently restricting, what the restriction blocks, and the exact condition that lifts it.\n\nOrganization API-key callers require `sessions:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Lists every number Polymorfa is currently restricting, what the restriction blocks, and the exact condition that lifts it.\n\nRequires `sessions:read`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -1936,7 +1936,7 @@ } } }, - "/v1/bansafe/enforcement/{session}/appeal": { + "/platform/bansafe/enforcement/{session}/appeal": { "post": { "operationId": "appealBanSafeEnforcement", "tags": [ @@ -2025,14 +2025,14 @@ } } }, - "/v1/bansafe/incidents": { + "/platform/bansafe/incidents": { "get": { "operationId": "listBanSafeIncidents", "tags": [ "bansafe" ], "summary": "List safety incidents", - "description": "Lists the WhatsApp restrictions and customer reports recorded for the organization's numbers.\n\nOrganization API-key callers require `sessions:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Lists the WhatsApp restrictions and customer reports recorded for the organization's numbers.\n\nRequires `sessions:read`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -2145,7 +2145,7 @@ "bansafe" ], "summary": "Report a ban", - "description": "Records that WhatsApp restricted or banned one of your numbers. Send the same `Idempotency-Key` to retry safely for the same number; a repeat returns the original report. Reusing the key for a different number returns `409 bansafe_incident_idempotency_scope_conflict`.\n\nOrganization API-key callers require `sessions:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Records that WhatsApp restricted or banned one of your numbers. Send the same `Idempotency-Key` to retry safely for the same number; a repeat returns the original report. Reusing the key for a different number returns `409 bansafe_incident_idempotency_scope_conflict`.\n\nRequires `sessions:manage`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -2232,14 +2232,14 @@ } } }, - "/v1/bansafe/incidents/{incidentId}/retract": { + "/platform/bansafe/incidents/{incidentId}/retract": { "post": { "operationId": "retractBanSafeIncident", "tags": [ "bansafe" ], "summary": "Withdraw a ban report", - "description": "Withdraws a customer report and returns its incident record. Repeating the request returns the closed record. An incident observed from WhatsApp cannot be withdrawn and returns `409 bansafe_incident_not_a_report`. An unknown incident returns 404.\n\nOrganization API-key callers require `sessions:manage`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "description": "Withdraws a customer report and returns its incident record. Repeating the request returns the closed record. An incident observed from WhatsApp cannot be withdrawn and returns `409 bansafe_incident_not_a_report`. An unknown incident returns 404.\n\nRequires a team API key with `sessions:manage`. Project tokens are not accepted.", "x-audience": "public", "x-polymorfa-resource-boundary": "organization", "x-excluded-from-public": false, @@ -2314,14 +2314,14 @@ } } }, - "/v1/bansafe/claims": { + "/platform/bansafe/claims": { "get": { "operationId": "listBanSafeClaims", "tags": [ "bansafe" ], "summary": "List Ban Insurance claims", - "description": "Lists the Ban Insurance claims filed on your numbers, newest first. A claim is filed automatically when a ban is recorded on a number whose plan includes insurance; there is no request to file one.\n\nOrganization API-key callers require `sessions:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Lists the Ban Insurance claims filed on your numbers, newest first. A claim is filed automatically when a ban is recorded on a number whose plan includes insurance; there is no request to file one.\n\nRequires `sessions:read`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -2445,14 +2445,14 @@ } } }, - "/v1/bansafe/claims/{claimId}": { + "/platform/bansafe/claims/{claimId}": { "get": { "operationId": "getBanSafeClaim", "tags": [ "bansafe" ], "summary": "Get a Ban Insurance claim", - "description": "Returns one claim: the 30 days it covers, the credits that number consumed in them, the most the plan returns, what the claim returns, what the ban was attributed to, and the evidence counts behind that.\n\nOrganization API-key callers require `sessions:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Returns one claim: the 30 days it covers, the credits that number consumed in them, the most the plan returns, what the claim returns, what the ban was attributed to, and the evidence counts behind that.\n\nRequires `sessions:read`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -2524,14 +2524,14 @@ } } }, - "/v1/projects/{projectId}/safe-mode": { + "/platform/projects/{projectId}/safe-mode": { "get": { "operationId": "getProjectSafeModeCeiling", "tags": [ "bansafe" ], "summary": "Get a project's Safe Mode ceiling", - "description": "Returns the most visible sending behaviour any number in this project may use. Every setting is off by default. `entitled` reports whether the plan includes BanSafe Lite, which Safe Mode is part of, and `entitlementReason` gives the reason a raise would be refused.\n\nOrganization API-key callers require `sessions:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Returns the most visible sending behaviour any number in this project may use. Every setting is off by default. `entitled` reports whether the plan includes BanSafe Lite, which Safe Mode is part of, and `entitlementReason` gives the reason a raise would be refused.\n\nRequires `sessions:read`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -2609,7 +2609,7 @@ "bansafe" ], "summary": "Set a project's Safe Mode ceiling", - "description": "Sets the most visible behaviour any number in this project may use. Send only the settings you want to change. Presence and read receipts are visible to the people these numbers message: turning them on makes a number appear online, exposes last seen subject to the account's privacy settings, and puts blue ticks on incoming messages. Raising a setting requires a plan that includes BanSafe Lite, and lowering one is always allowed. A signed-in caller must be an organization owner, admin, or developer.\n\nOrganization API-key callers require `sessions:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Sets the most visible behaviour any number in this project may use. Send only the settings you want to change. Presence and read receipts are visible to the people these numbers message: turning them on makes a number appear online, exposes last seen subject to the account's privacy settings, and puts blue ticks on incoming messages. Raising a setting requires a plan that includes BanSafe Lite, and lowering one is always allowed. A signed-in caller must be an organization owner, admin, or developer.\n\nRequires `sessions:manage`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -2698,14 +2698,14 @@ } } }, - "/v1/sessions/{sessionId}/safe-mode": { + "/platform/sessions/{sessionId}/safe-mode": { "get": { "operationId": "getNumberSafeMode", "tags": [ "bansafe" ], "summary": "Get a number's Safe Mode", - "description": "Returns the project ceiling, this number's override, the policy in force, and what the number last reported it is running. `mismatch` is true when the two differ. `entitled` reports whether the plan includes BanSafe Lite, which Safe Mode is part of, and `entitlementReason` gives the reason a raise would be refused.\n\nOrganization API-key callers require `sessions:read`; project-token callers require the same action scope and are accepted only for `session` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Returns the project ceiling, this number's override, the policy in force, and what the number last reported it is running. `mismatch` is true when the two differ. `entitled` reports whether the plan includes BanSafe Lite, which Safe Mode is part of, and `entitlementReason` gives the reason a raise would be refused.\n\nRequires `sessions:read`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "session", "x-excluded-from-public": false, @@ -2783,7 +2783,7 @@ "bansafe" ], "summary": "Set a number's Safe Mode", - "description": "Sets one number's Safe Mode. Each setting accepts `inherit` to follow the project ceiling. An override may only be equally or more conservative than the ceiling; a more visible value is refused with `safe_mode_exceeds_project_ceiling`. Raising a setting requires a plan that includes BanSafe Lite, and lowering one is always allowed. A signed-in caller must be an organization owner, admin, or developer.\n\nOrganization API-key callers require `sessions:manage`; project-token callers require the same action scope and are accepted only for `session` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Sets one number's Safe Mode. Each setting accepts `inherit` to follow the project ceiling. An override may only be equally or more conservative than the ceiling; a more visible value is refused with `safe_mode_exceeds_project_ceiling`. Raising a setting requires a plan that includes BanSafe Lite, and lowering one is always allowed. A signed-in caller must be an organization owner, admin, or developer.\n\nRequires `sessions:manage`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "session", "x-excluded-from-public": false, @@ -2872,14 +2872,14 @@ } } }, - "/v1/projects/{projectId}/warmup-plan": { + "/platform/projects/{projectId}/warmup-plan": { "get": { "operationId": "getProjectWarmupPlanSettings", "tags": [ "bansafe" ], "summary": "Get a project's warm-up plan", - "description": "Returns whether numbers in this project have a daily allowance, the two settings that shape the ramp, the per-number daily cap it climbs to, and the projected allowance day by day. `entitled` reports whether the plan includes BanSafe Lite, which the warm-up plan is part of.\n\nOrganization API-key callers require `sessions:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Returns whether numbers in this project have a daily allowance, the two settings that shape the ramp, the per-number daily cap it climbs to, and the projected allowance day by day. `entitled` reports whether the plan includes BanSafe Lite, which the warm-up plan is part of.\n\nRequires `sessions:read`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -2957,7 +2957,7 @@ "bansafe" ], "summary": "Set a project's warm-up plan", - "description": "Turns the warm-up plan on or off for a project and sets how long the ramp takes and how many messages a number may send on its first day. Send only the settings you want to change. While the plan is on, a send past a number's allowance is refused with `bansafe_daily_allowance_reached` and campaign recipients are deferred to the next reset. Turning the plan on requires a plan that includes BanSafe Lite; turning it off is always allowed. A signed-in caller must be an organization owner, admin, or developer.\n\nOrganization API-key callers require `sessions:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Turns the warm-up plan on or off for a project and sets how long the ramp takes and how many messages a number may send on its first day. Send only the settings you want to change. While the plan is on, a send past a number's allowance is refused with `bansafe_daily_allowance_reached` and campaign recipients are deferred to the next reset. Turning the plan on requires a plan that includes BanSafe Lite; turning it off is always allowed. A signed-in caller must be an organization owner, admin, or developer.\n\nRequires `sessions:manage`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -3046,14 +3046,14 @@ } } }, - "/v1/projects/{projectId}/health-policy": { + "/platform/projects/{projectId}/health-policy": { "get": { "operationId": "getProjectHealthPolicySettings", "tags": [ "bansafe" ], "summary": "Get a project's health policy", - "description": "Returns the health threshold and the actions configured for numbers in this project. Integration flags report whether email and webhook delivery are ready to use.\n\nOrganization API-key callers require `sessions:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Returns the health threshold and the actions configured for numbers in this project. Integration flags report whether email and webhook delivery are ready to use.\n\nRequires `sessions:read`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -3131,7 +3131,7 @@ "bansafe" ], "summary": "Set a project's health policy", - "description": "Replaces the project policy when the supplied version matches the stored version. The rule applies only when an available health estimate is below the threshold; an unavailable estimate triggers no action. Stopping disconnects a session and retains its linked credentials. Logging out requires relinking.\n\nOrganization API-key callers require `sessions:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Replaces the project policy when the supplied version matches the stored version. The rule applies only when an available health estimate is below the threshold; an unavailable estimate triggers no action. Stopping disconnects a session and retains its linked credentials. Logging out requires relinking.\n\nRequires `sessions:manage`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -3217,14 +3217,14 @@ } } }, - "/v1/projects/{projectId}/insurance-evidence": { + "/platform/projects/{projectId}/insurance-evidence": { "get": { "operationId": "getInsuranceEvidenceSettings", "tags": [ "bansafe" ], "summary": "Get a project's insurance evidence setting", - "description": "Returns whether evidence collection about other linked devices is enabled and whether any number in the project has Ban Insurance included in its plan. Collection is off until explicitly enabled.\n\nOrganization API-key callers require `sessions:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Returns whether evidence collection about other linked devices is enabled and whether any number in the project has Ban Insurance included in its plan. Collection is off until explicitly enabled.\n\nRequires `sessions:read`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -3302,7 +3302,7 @@ "bansafe" ], "summary": "Set a project's insurance evidence setting", - "description": "Enables or disables collection of counts about other linked devices. Collection never includes messages, recipient identities, or device names. Disabling collection discards stored device evidence. A 503 `propagation_pending` means the setting was stored but a connected number has not confirmed it; retry the request. A signed-in caller must be an organization owner, admin, or developer.\n\nOrganization API-key callers require `sessions:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Enables or disables collection of counts about other linked devices. Collection never includes messages, recipient identities, or device names. Disabling collection discards stored device evidence. A 503 `propagation_pending` means the setting was stored but a connected number has not confirmed it; retry the request. A signed-in caller must be an organization owner, admin, or developer.\n\nRequires `sessions:manage`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -3388,14 +3388,14 @@ } } }, - "/v1/campaigns": { + "/platform/campaigns": { "get": { "operationId": "listPlatformCampaigns", "tags": [ "campaigns" ], "summary": "List platform campaigns", - "description": "Public Management API. Organization API-key callers require `campaigns:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Public Management API. Requires `campaigns:read`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -3468,7 +3468,7 @@ "campaigns" ], "summary": "Create campaign", - "description": "Public Management API. Organization API-key callers require `campaigns:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Public Management API. Requires `campaigns:manage`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -3529,14 +3529,14 @@ } } }, - "/v1/campaigns/{campaignId}": { + "/platform/campaigns/{campaignId}": { "get": { "operationId": "getPlatformCampaign", "tags": [ "campaigns" ], "summary": "Get campaign", - "description": "Public Management API. Organization API-key callers require `campaigns:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Public Management API. Requires `campaigns:read`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -3601,7 +3601,7 @@ "campaigns" ], "summary": "Update campaign", - "description": "Public Management API. Organization API-key callers require `campaigns:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Public Management API. Requires `campaigns:manage`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -3677,7 +3677,7 @@ "campaigns" ], "summary": "Delete campaign", - "description": "Public Management API. Organization API-key callers require `campaigns:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Public Management API. Requires `campaigns:manage`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -3737,14 +3737,14 @@ } } }, - "/v1/campaigns/{campaignId}/launch": { + "/platform/campaigns/{campaignId}/launch": { "post": { "operationId": "launchPlatformCampaign", "tags": [ "campaigns" ], "summary": "Launch campaign", - "description": "Public Management API. Organization API-key callers require `campaigns:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Public Management API. Requires `campaigns:manage`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -3815,14 +3815,14 @@ } } }, - "/v1/campaigns/{campaignId}/pause": { + "/platform/campaigns/{campaignId}/pause": { "post": { "operationId": "pausePlatformCampaign", "tags": [ "campaigns" ], "summary": "Pause campaign", - "description": "Public Management API. Organization API-key callers require `campaigns:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Public Management API. Requires `campaigns:manage`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -3893,14 +3893,14 @@ } } }, - "/v1/campaigns/{campaignId}/resume": { + "/platform/campaigns/{campaignId}/resume": { "post": { "operationId": "resumePlatformCampaign", "tags": [ "campaigns" ], "summary": "Resume campaign", - "description": "Public Management API. Organization API-key callers require `campaigns:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Public Management API. Requires `campaigns:manage`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -3971,14 +3971,14 @@ } } }, - "/v1/campaigns/{campaignId}/stop": { + "/platform/campaigns/{campaignId}/stop": { "post": { "operationId": "stopPlatformCampaign", "tags": [ "campaigns" ], "summary": "Stop campaign", - "description": "Public Management API. Organization API-key callers require `campaigns:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Public Management API. Requires `campaigns:manage`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -4049,14 +4049,14 @@ } } }, - "/v1/campaigns/{campaignId}/archive": { + "/platform/campaigns/{campaignId}/archive": { "post": { "operationId": "archiveCampaign", "tags": [ "campaigns" ], "summary": "Archive campaign", - "description": "Public Management API. Organization API-key callers require `campaigns:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Public Management API. Requires `campaigns:manage`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -4127,14 +4127,14 @@ } } }, - "/v1/campaigns/{campaignId}/duplicate": { + "/platform/campaigns/{campaignId}/duplicate": { "post": { "operationId": "duplicateCampaign", "tags": [ "campaigns" ], "summary": "Duplicate campaign", - "description": "Public Management API. Organization API-key callers require `campaigns:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Public Management API. Requires `campaigns:manage`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -4205,14 +4205,14 @@ } } }, - "/v1/campaigns/{campaignId}/requeue": { + "/platform/campaigns/{campaignId}/requeue": { "post": { "operationId": "requeueFailedCampaign", "tags": [ "campaigns" ], "summary": "Requeue failed campaign", - "description": "Public Management API. Organization API-key callers require `campaigns:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Public Management API. Requires `campaigns:manage`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -4283,14 +4283,14 @@ } } }, - "/v1/campaigns/{campaignId}/analytics": { + "/platform/campaigns/{campaignId}/analytics": { "get": { "operationId": "getPlatformCampaignAnalytics", "tags": [ "campaigns" ], "summary": "Get campaign analytics", - "description": "Public Management API. Organization API-key callers require `campaigns:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Public Management API. Requires `campaigns:read`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -4350,14 +4350,14 @@ } } }, - "/v1/campaigns/{campaignId}/events": { + "/platform/campaigns/{campaignId}/events": { "get": { "operationId": "listCampaignEvents", "tags": [ "campaigns" ], "summary": "List campaign events", - "description": "Public Management API. Organization API-key callers require `campaigns:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Public Management API. Requires `campaigns:read`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -4417,14 +4417,14 @@ } } }, - "/v1/campaigns/{campaignId}/recipients": { + "/platform/campaigns/{campaignId}/recipients": { "get": { "operationId": "listCampaignRecipients", "tags": [ "campaigns" ], "summary": "List campaign recipients", - "description": "Public Management API. Organization API-key callers require `campaigns:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Public Management API. Requires `campaigns:read`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -4484,14 +4484,14 @@ } } }, - "/v1/audiences": { + "/platform/audiences": { "get": { "operationId": "listAudiences", "tags": [ "audiences" ], "summary": "List audiences", - "description": "Public Management API. Organization API-key callers require `campaigns:read`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "description": "Public Management API. Requires a team API key with `campaigns:read`. Project tokens are not accepted.", "x-audience": "public", "x-polymorfa-resource-boundary": "organization", "x-excluded-from-public": false, @@ -4546,7 +4546,7 @@ "audiences" ], "summary": "Create audience", - "description": "Public Management API. Organization API-key callers require `campaigns:manage`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "description": "Public Management API. Requires a team API key with `campaigns:manage`. Project tokens are not accepted.", "x-audience": "public", "x-polymorfa-resource-boundary": "organization", "x-excluded-from-public": false, @@ -4607,14 +4607,14 @@ } } }, - "/v1/audiences/{listId}": { + "/platform/audiences/{listId}": { "get": { "operationId": "getAudience", "tags": [ "audiences" ], "summary": "Get audience", - "description": "Public Management API. Organization API-key callers require `campaigns:read`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "description": "Public Management API. Requires a team API key with `campaigns:read`. Project tokens are not accepted.", "x-audience": "public", "x-polymorfa-resource-boundary": "organization", "x-excluded-from-public": false, @@ -4679,7 +4679,7 @@ "audiences" ], "summary": "Delete audience", - "description": "Public Management API. Organization API-key callers require `campaigns:manage`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "description": "Public Management API. Requires a team API key with `campaigns:manage`. Project tokens are not accepted.", "x-audience": "public", "x-polymorfa-resource-boundary": "organization", "x-excluded-from-public": false, @@ -4739,14 +4739,14 @@ } } }, - "/v1/audiences/uploads": { + "/platform/audiences/uploads": { "post": { "operationId": "createAudienceUploadUrl", "tags": [ "audiences" ], "summary": "Create audience upload url", - "description": "Public Management API. Organization API-key callers require `campaigns:manage`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "description": "Public Management API. Requires a team API key with `campaigns:manage`. Project tokens are not accepted.", "x-audience": "public", "x-polymorfa-resource-boundary": "organization", "x-excluded-from-public": false, @@ -4807,14 +4807,14 @@ } } }, - "/v1/templates": { + "/platform/templates": { "get": { "operationId": "listMessageTemplates", "tags": [ "templates" ], "summary": "List message templates", - "description": "Lists the message-template drafts in one project.\n\nOrganization API-key callers require `templates:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Lists the message-template drafts in one project.\n\nRequires `templates:read`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -4895,7 +4895,7 @@ "templates" ], "summary": "Create a message-template draft", - "description": "Creates an incomplete or complete message-template draft in one project.\n\nOrganization API-key callers require `templates:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Creates an incomplete or complete message-template draft in one project.\n\nRequires `templates:manage`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -4967,14 +4967,14 @@ } } }, - "/v1/templates/{templateId}": { + "/platform/templates/{templateId}": { "get": { "operationId": "getMessageTemplate", "tags": [ "templates" ], "summary": "Get a message-template draft", - "description": "Gets one message-template draft from the specified project.\n\nOrganization API-key callers require `templates:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Gets one message-template draft from the specified project.\n\nRequires `templates:read`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -5065,7 +5065,7 @@ "templates" ], "summary": "Update a message-template draft", - "description": "Updates one message-template draft in the project supplied in the request body.\n\nOrganization API-key callers require `templates:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Updates one message-template draft in the project supplied in the request body.\n\nRequires `templates:manage`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -5152,7 +5152,7 @@ "templates" ], "summary": "Delete a message-template draft", - "description": "Deletes one message-template draft from the specified project.\n\nOrganization API-key callers require `templates:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Deletes one message-template draft from the specified project.\n\nRequires `templates:manage`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -5232,14 +5232,14 @@ } } }, - "/v1/flows": { + "/platform/flows": { "get": { "operationId": "listFlows", "tags": [ "flows" ], "summary": "List Flow drafts", - "description": "Lists compact WhatsApp Flow draft summaries in one project.\n\nOrganization API-key callers require `sessions:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Lists compact WhatsApp Flow draft summaries in one project.\n\nRequires `sessions:read`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -5320,7 +5320,7 @@ "flows" ], "summary": "Create a Flow draft", - "description": "Creates a project-scoped WhatsApp Flow draft. A supplied draftId makes retries idempotent.\n\nOrganization API-key callers require `sessions:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Creates a project-scoped WhatsApp Flow draft. A supplied draftId makes retries idempotent.\n\nRequires `sessions:manage`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -5392,14 +5392,14 @@ } } }, - "/v1/flows/{flowId}": { + "/platform/flows/{flowId}": { "get": { "operationId": "getFlow", "tags": [ "flows" ], "summary": "Get a Flow draft", - "description": "Gets one project-scoped WhatsApp Flow draft.\n\nOrganization API-key callers require `sessions:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Gets one project-scoped WhatsApp Flow draft.\n\nRequires `sessions:read`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -5490,7 +5490,7 @@ "flows" ], "summary": "Update a Flow draft", - "description": "Updates a Flow draft when expectedUpdatedAt matches the stored revision.\n\nOrganization API-key callers require `sessions:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Updates a Flow draft when expectedUpdatedAt matches the stored revision.\n\nRequires `sessions:manage`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -5580,7 +5580,7 @@ "flows" ], "summary": "Delete a Flow draft", - "description": "Deletes a local Flow draft without deleting linked Meta Flow assets.\n\nOrganization API-key callers require `sessions:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Deletes a local Flow draft without deleting linked Meta Flow assets.\n\nRequires `sessions:manage`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -5660,14 +5660,14 @@ } } }, - "/v1/optouts": { + "/platform/optouts": { "get": { "operationId": "listOptOuts", "tags": [ "optouts" ], "summary": "List opt outs", - "description": "Public Management API. Organization API-key callers require `campaigns:read`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "description": "Public Management API. Requires a team API key with `campaigns:read`. Project tokens are not accepted.", "x-audience": "public", "x-polymorfa-resource-boundary": "organization", "x-excluded-from-public": false, @@ -5722,7 +5722,7 @@ "optouts" ], "summary": "Create opt out", - "description": "Public Management API. Organization API-key callers require `campaigns:manage`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "description": "Public Management API. Requires a team API key with `campaigns:manage`. Project tokens are not accepted.", "x-audience": "public", "x-polymorfa-resource-boundary": "organization", "x-excluded-from-public": false, @@ -5783,14 +5783,14 @@ } } }, - "/v1/optouts/batch": { + "/platform/optouts/batch": { "post": { "operationId": "createOptOuts", "tags": [ "optouts" ], "summary": "Create opt outs", - "description": "Public Management API. Organization API-key callers require `campaigns:manage`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "description": "Public Management API. Requires a team API key with `campaigns:manage`. Project tokens are not accepted.", "x-audience": "public", "x-polymorfa-resource-boundary": "organization", "x-excluded-from-public": false, @@ -5851,14 +5851,14 @@ } } }, - "/v1/optouts/{phone}": { + "/platform/optouts/{phone}": { "delete": { "operationId": "deleteOptOut", "tags": [ "optouts" ], "summary": "Delete opt out", - "description": "Public Management API. Organization API-key callers require `campaigns:manage`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "description": "Public Management API. Requires a team API key with `campaigns:manage`. Project tokens are not accepted.", "x-audience": "public", "x-polymorfa-resource-boundary": "organization", "x-excluded-from-public": false, @@ -5918,14 +5918,14 @@ } } }, - "/v1/billing": { + "/platform/billing": { "get": { "operationId": "getBilling", "tags": [ "billing" ], "summary": "Get billing", - "description": "Public Management API. Organization API-key callers require `sessions:read`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "description": "Public Management API. Requires a team API key with `sessions:read`. Project tokens are not accepted.", "x-audience": "public", "x-polymorfa-resource-boundary": "organization", "x-excluded-from-public": false, @@ -5975,14 +5975,14 @@ } } }, - "/v1/billing/usage": { + "/platform/billing/usage": { "get": { "operationId": "listUsageMeters", "tags": [ "billing" ], "summary": "List usage meters", - "description": "Public Management API. Organization API-key callers require `sessions:read`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "description": "Public Management API. Requires a team API key with `sessions:read`. Project tokens are not accepted.", "x-audience": "public", "x-polymorfa-resource-boundary": "organization", "x-excluded-from-public": false, @@ -6032,14 +6032,14 @@ } } }, - "/v1/billing/transactions": { + "/platform/billing/transactions": { "get": { "operationId": "listBillingTransactions", "tags": [ "billing" ], "summary": "List billing transactions", - "description": "Public Management API. Organization API-key callers require `sessions:read`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "description": "Public Management API. Requires a team API key with `sessions:read`. Project tokens are not accepted.", "x-audience": "public", "x-polymorfa-resource-boundary": "organization", "x-excluded-from-public": false, @@ -6089,14 +6089,14 @@ } } }, - "/v1/billing/pricing": { + "/platform/billing/pricing": { "get": { "operationId": "listTierPricing", "tags": [ "billing" ], "summary": "List tier pricing", - "description": "Public Management API. Organization API-key callers require `sessions:read`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "description": "Public Management API. Requires a team API key with `sessions:read`. Project tokens are not accepted.", "x-audience": "public", "x-polymorfa-resource-boundary": "organization", "x-excluded-from-public": false, @@ -6146,14 +6146,14 @@ } } }, - "/v1/billing/reminders": { + "/platform/billing/reminders": { "patch": { "operationId": "updateBillingReminderSettings", "tags": [ "billing" ], "summary": "Update billing reminder settings", - "description": "Public Management API. Organization API-key callers require `sessions:manage`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "description": "Public Management API. Requires a team API key with `sessions:manage`. Project tokens are not accepted.", "x-audience": "public", "x-polymorfa-resource-boundary": "organization", "x-excluded-from-public": false, @@ -6214,14 +6214,14 @@ } } }, - "/v1/organization": { + "/platform/team": { "get": { "operationId": "getOrganization", "tags": [ - "organization" + "team" ], "summary": "Get organization", - "description": "Public Management API. Organization API-key callers require `sessions:read`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "description": "Public Management API. Requires a team API key with `sessions:read`. Project tokens are not accepted.", "x-audience": "public", "x-polymorfa-resource-boundary": "organization", "x-excluded-from-public": false, @@ -6269,17 +6269,20 @@ "$ref": "#/components/responses/NotImplemented" } } - }, + } + }, + "/console/organization": { "patch": { "operationId": "updateOrganization", "tags": [ "organization" ], "summary": "Update organization", - "description": "Public Management API. Requires a verified dashboard bearer and current organization authorization. The signed-in member must be an organization owner or admin. Organization keys and project tokens are not accepted.", - "x-audience": "public", + "description": "**EXCLUDED from the public API** (`console`). Organization changes require an authenticated console member.", + "x-audience": "console", "x-polymorfa-resource-boundary": "human_only", - "x-excluded-from-public": false, + "x-excluded-from-public": true, + "x-exclusion-reason": "Organization changes require an authenticated console member.", "x-dashboard-only": true, "x-required-organization-role": "owner_or_admin", "security": [ @@ -6335,14 +6338,14 @@ } } }, - "/v1/projects": { + "/platform/projects": { "get": { "operationId": "listProjects", "tags": [ "projects" ], "summary": "List projects", - "description": "Public Management API. Organization API-key callers require `sessions:read`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "description": "Public Management API. Requires a team API key with `sessions:read`. Project tokens are not accepted.", "x-audience": "public", "x-polymorfa-resource-boundary": "organization", "x-excluded-from-public": false, @@ -6397,7 +6400,7 @@ "projects" ], "summary": "Create project", - "description": "Public Management API. Organization API-key callers require `sessions:manage`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "description": "Public Management API. Requires a team API key with `sessions:manage`. Project tokens are not accepted.", "x-audience": "public", "x-polymorfa-resource-boundary": "organization", "x-excluded-from-public": false, @@ -6606,14 +6609,14 @@ } } }, - "/v1/projects/{projectId}/promote": { + "/platform/projects/{projectId}/promote": { "post": { "operationId": "requestProductionEnrollment", "tags": [ "projects" ], "summary": "Request production enrollment", - "description": "Creates a durable production-enrollment operation. The project stays in development until provisioning succeeds. Poll the returned operationId for progress.\n\nOrganization API-key callers require `sessions:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Creates a durable production-enrollment operation. The project stays in development until provisioning succeeds. Poll the returned operationId for progress.\n\nRequires `sessions:manage`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -6699,14 +6702,14 @@ } } }, - "/v1/projects/{projectId}/customers/status": { + "/platform/projects/{projectId}/customers/status": { "get": { "operationId": "getCustomersStatus", "tags": [ "customers" ], "summary": "Get Customers status", - "description": "Returns whether Customers is enabled for the exact project and its protected default Customer when enabled.\n\nOrganization API-key callers require `customers:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Returns whether Customers is enabled for the exact project and its protected default Customer when enabled.\n\nRequires `customers:read`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -6779,14 +6782,14 @@ } } }, - "/v1/projects/{projectId}/customers/enable": { + "/platform/projects/{projectId}/customers/enable": { "post": { "operationId": "enableCustomers", "tags": [ "customers" ], "summary": "Enable Customers", - "description": "Enables Customers once, creates the default Customer, and assigns every existing Number in the project to it atomically.\n\nOrganization API-key callers require `customers:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Enables Customers once, creates the default Customer, and assigns every existing Number in the project to it atomically.\n\nRequires `customers:manage`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -6872,14 +6875,14 @@ } } }, - "/v1/projects/{projectId}/production-enrollments/{operationId}/approve": { + "/platform/projects/{projectId}/production-enrollments/{operationId}/approve": { "post": { "operationId": "approveProductionEnrollment", "tags": [ "projects" ], "summary": "Approve production enrollment", - "description": "Resumes a production-enrollment operation that requires approval.\n\nOrganization API-key callers require `sessions:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Resumes a production-enrollment operation that requires approval.\n\nRequires `sessions:manage`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -6972,14 +6975,14 @@ } } }, - "/v1/projects/{projectId}/production-enrollments/{operationId}/cancel": { + "/platform/projects/{projectId}/production-enrollments/{operationId}/cancel": { "post": { "operationId": "cancelProductionEnrollment", "tags": [ "projects" ], "summary": "Cancel production enrollment", - "description": "Requests cancellation of an active production-enrollment operation. Provisioned resources are compensated before cancellation completes.\n\nOrganization API-key callers require `sessions:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Requests cancellation of an active production-enrollment operation. Provisioned resources are compensated before cancellation completes.\n\nRequires `sessions:manage`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -7072,14 +7075,14 @@ } } }, - "/v1/webhooks": { + "/platform/webhooks": { "get": { "operationId": "listOrganizationWebhooks", "tags": [ "webhooks" ], "summary": "List organization webhooks", - "description": "Lists only organization-owned webhook endpoints. Project-owned endpoints are excluded.\n\nOrganization API-key callers require `webhooks:read`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "description": "Lists only organization-owned webhook endpoints. Project-owned endpoints are excluded.\n\nRequires a team API key with `webhooks:read`. Project tokens are not accepted.", "x-audience": "public", "x-polymorfa-resource-boundary": "organization", "x-excluded-from-public": false, @@ -7189,7 +7192,7 @@ "webhooks" ], "summary": "Create an organization webhook", - "description": "Creates an organization-owned webhook and returns its generated signing secret once.\n\nOrganization API-key callers require `webhooks:manage`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "description": "Creates an organization-owned webhook and returns its generated signing secret once.\n\nRequires a team API key with `webhooks:manage`. Project tokens are not accepted.", "x-audience": "public", "x-polymorfa-resource-boundary": "organization", "x-excluded-from-public": false, @@ -7273,14 +7276,14 @@ } } }, - "/v1/webhooks/{webhookId}": { + "/platform/webhooks/{webhookId}": { "get": { "operationId": "getOrganizationWebhook", "tags": [ "webhooks" ], "summary": "Get an organization webhook", - "description": "Returns one organization-owned webhook without secret values.\n\nOrganization API-key callers require `webhooks:read`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "description": "Returns one organization-owned webhook without secret values.\n\nRequires a team API key with `webhooks:read`. Project tokens are not accepted.", "x-audience": "public", "x-polymorfa-resource-boundary": "organization", "x-excluded-from-public": false, @@ -7358,7 +7361,7 @@ "webhooks" ], "summary": "Update an organization webhook", - "description": "Updates settings without rotating the signing secret.\n\nOrganization API-key callers require `webhooks:manage`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "description": "Updates settings without rotating the signing secret.\n\nRequires a team API key with `webhooks:manage`. Project tokens are not accepted.", "x-audience": "public", "x-polymorfa-resource-boundary": "organization", "x-excluded-from-public": false, @@ -7459,7 +7462,7 @@ "webhooks" ], "summary": "Delete an organization webhook", - "description": "Deletes one organization-owned webhook.\n\nOrganization API-key callers require `webhooks:manage`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "description": "Deletes one organization-owned webhook.\n\nRequires a team API key with `webhooks:manage`. Project tokens are not accepted.", "x-audience": "public", "x-polymorfa-resource-boundary": "organization", "x-excluded-from-public": false, @@ -7545,14 +7548,14 @@ } } }, - "/v1/webhooks/{webhookId}/secret-rotations": { + "/platform/webhooks/{webhookId}/secret-rotations": { "post": { "operationId": "rotateOrganizationWebhookSecret", "tags": [ "webhooks" ], "summary": "Rotate an organization webhook secret", - "description": "Rotates the signing secret and returns the new secret once.\n\nOrganization API-key callers require `webhooks:manage`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "description": "Rotates the signing secret and returns the new secret once.\n\nRequires a team API key with `webhooks:manage`. Project tokens are not accepted.", "x-audience": "public", "x-polymorfa-resource-boundary": "organization", "x-excluded-from-public": false, @@ -7648,14 +7651,14 @@ } } }, - "/v1/webhooks/{webhookId}/tests": { + "/platform/webhooks/{webhookId}/tests": { "post": { "operationId": "testOrganizationWebhook", "tags": [ "webhooks" ], "summary": "Send an organization webhook test", - "description": "Creates a synthetic organization event and a traceable webhook delivery.\n\nOrganization API-key callers require `webhooks:manage`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "description": "Creates a synthetic organization event and a traceable webhook delivery.\n\nRequires a team API key with `webhooks:manage`. Project tokens are not accepted.", "x-audience": "public", "x-polymorfa-resource-boundary": "organization", "x-excluded-from-public": false, @@ -7751,14 +7754,14 @@ } } }, - "/v1/projects/{projectId}/webhooks": { + "/platform/projects/{projectId}/webhooks": { "get": { "operationId": "listProjectWebhooks", "tags": [ "webhooks" ], "summary": "List project webhooks", - "description": "Lists webhooks owned by the exact project in the route.\n\nOrganization API-key callers require `webhooks:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Lists webhooks owned by the exact project in the route.\n\nRequires `webhooks:read`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -7880,7 +7883,7 @@ "webhooks" ], "summary": "Create a project webhook", - "description": "Creates a project-owned webhook and returns its generated signing secret once.\n\nOrganization API-key callers require `webhooks:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Creates a project-owned webhook and returns its generated signing secret once.\n\nRequires `webhooks:manage`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -7976,14 +7979,14 @@ } } }, - "/v1/projects/{projectId}/webhooks/{webhookId}": { + "/platform/projects/{projectId}/webhooks/{webhookId}": { "get": { "operationId": "getProjectWebhook", "tags": [ "webhooks" ], "summary": "Get a project webhook", - "description": "Returns one webhook owned by the exact project without secret values.\n\nOrganization API-key callers require `webhooks:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Returns one webhook owned by the exact project without secret values.\n\nRequires `webhooks:read`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -8070,7 +8073,7 @@ "webhooks" ], "summary": "Update a project webhook", - "description": "Updates settings without rotating the signing secret.\n\nOrganization API-key callers require `webhooks:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Updates settings without rotating the signing secret.\n\nRequires `webhooks:manage`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -8180,7 +8183,7 @@ "webhooks" ], "summary": "Delete a project webhook", - "description": "Deletes one webhook owned by the exact project.\n\nOrganization API-key callers require `webhooks:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Deletes one webhook owned by the exact project.\n\nRequires `webhooks:manage`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -8275,14 +8278,14 @@ } } }, - "/v1/projects/{projectId}/webhooks/{webhookId}/secret-rotations": { + "/platform/projects/{projectId}/webhooks/{webhookId}/secret-rotations": { "post": { "operationId": "rotateProjectWebhookSecret", "tags": [ "webhooks" ], "summary": "Rotate a project webhook secret", - "description": "Rotates the signing secret and returns the new secret once.\n\nOrganization API-key callers require `webhooks:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Rotates the signing secret and returns the new secret once.\n\nRequires `webhooks:manage`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -8387,14 +8390,14 @@ } } }, - "/v1/projects/{projectId}/webhooks/{webhookId}/tests": { + "/platform/projects/{projectId}/webhooks/{webhookId}/tests": { "post": { "operationId": "testProjectWebhook", "tags": [ "webhooks" ], "summary": "Send a project webhook test", - "description": "Creates a synthetic project event and a traceable webhook delivery. An optional complete native envelope is accepted only with an exact HMS-enabled project session.\n\nOrganization API-key callers require `webhooks:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Creates a synthetic project event and a traceable webhook delivery. An optional complete native envelope is accepted only with an exact HMS-enabled project session.\n\nRequires `webhooks:manage`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -8502,14 +8505,14 @@ } } }, - "/v1/events": { + "/platform/events": { "get": { "operationId": "listOrganizationEvents", "tags": [ "events" ], "summary": "List organization events", - "description": "Lists organization-owned event metadata. Project-owned events are excluded.\n\nOrganization API-key callers require `events:read`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "description": "Lists organization-owned event metadata. Project-owned events are excluded.\n\nRequires a team API key with `events:read`. Project tokens are not accepted.", "x-audience": "public", "x-polymorfa-resource-boundary": "organization", "x-excluded-from-public": false, @@ -8622,14 +8625,14 @@ } } }, - "/v1/events/{eventId}": { + "/platform/events/{eventId}": { "get": { "operationId": "getOrganizationEvent", "tags": [ "events" ], "summary": "Get an organization event", - "description": "Returns one organization-owned event and includes exact payload bytes only when requested and available.\n\nOrganization API-key callers require `events:read`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "description": "Returns one organization-owned event and includes exact payload bytes only when requested and available.\n\nRequires a team API key with `events:read`. Project tokens are not accepted.", "x-audience": "public", "x-polymorfa-resource-boundary": "organization", "x-excluded-from-public": false, @@ -8711,14 +8714,14 @@ } } }, - "/v1/events/{eventId}/replays": { + "/platform/events/{eventId}/replays": { "post": { "operationId": "replayOrganizationEvent", "tags": [ "events" ], "summary": "Replay an organization event", - "description": "Creates a new logical delivery for a retained organization event.\n\nOrganization API-key callers require `events:replay`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "description": "Creates a new logical delivery for a retained organization event.\n\nRequires a team API key with `events:replay`. Project tokens are not accepted.", "x-audience": "public", "x-polymorfa-resource-boundary": "organization", "x-excluded-from-public": false, @@ -8817,14 +8820,14 @@ } } }, - "/v1/projects/{projectId}/events": { + "/platform/projects/{projectId}/events": { "get": { "operationId": "listProjectEvents", "tags": [ "events" ], "summary": "List project events", - "description": "Lists event metadata owned by the exact project in the route.\n\nOrganization API-key callers require `events:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Lists event metadata owned by the exact project in the route.\n\nRequires `events:read`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -8949,14 +8952,14 @@ } } }, - "/v1/projects/{projectId}/events/{eventId}": { + "/platform/projects/{projectId}/events/{eventId}": { "get": { "operationId": "getProjectEvent", "tags": [ "events" ], "summary": "Get a project event", - "description": "Returns one event owned by the exact project and includes exact payload bytes only when requested and available.\n\nOrganization API-key callers require `events:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Returns one event owned by the exact project and includes exact payload bytes only when requested and available.\n\nRequires `events:read`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -9047,14 +9050,14 @@ } } }, - "/v1/projects/{projectId}/events/{eventId}/replays": { + "/platform/projects/{projectId}/events/{eventId}/replays": { "post": { "operationId": "replayProjectEvent", "tags": [ "events" ], "summary": "Replay a project event", - "description": "Creates a new logical delivery for a retained event owned by the exact project.\n\nOrganization API-key callers require `events:replay`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Creates a new logical delivery for a retained event owned by the exact project.\n\nRequires `events:replay`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -9162,14 +9165,14 @@ } } }, - "/v1/webhook-deliveries": { + "/platform/webhook-deliveries": { "get": { "operationId": "listOrganizationWebhookDeliveries", "tags": [ "webhook deliveries" ], "summary": "List organization webhook deliveries", - "description": "Lists logical deliveries for organization-owned webhooks. Project-owned deliveries are excluded.\n\nOrganization API-key callers require `webhook-deliveries:read`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "description": "Lists logical deliveries for organization-owned webhooks. Project-owned deliveries are excluded.\n\nRequires a team API key with `webhook-deliveries:read`. Project tokens are not accepted.", "x-audience": "public", "x-polymorfa-resource-boundary": "organization", "x-excluded-from-public": false, @@ -9307,14 +9310,14 @@ } } }, - "/v1/webhook-deliveries/{deliveryId}": { + "/platform/webhook-deliveries/{deliveryId}": { "get": { "operationId": "getOrganizationWebhookDelivery", "tags": [ "webhook deliveries" ], "summary": "Get an organization webhook delivery", - "description": "Returns one logical organization webhook delivery.\n\nOrganization API-key callers require `webhook-deliveries:read`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "description": "Returns one logical organization webhook delivery.\n\nRequires a team API key with `webhook-deliveries:read`. Project tokens are not accepted.", "x-audience": "public", "x-polymorfa-resource-boundary": "organization", "x-excluded-from-public": false, @@ -9387,14 +9390,14 @@ } } }, - "/v1/webhook-deliveries/{deliveryId}/retry": { + "/platform/webhook-deliveries/{deliveryId}/retry": { "post": { "operationId": "retryOrganizationWebhookDelivery", "tags": [ "webhook deliveries" ], "summary": "Retry an organization webhook delivery", - "description": "Appends a new immutable attempt to the same logical delivery.\n\nOrganization API-key callers require `webhook-deliveries:retry`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "description": "Appends a new immutable attempt to the same logical delivery.\n\nRequires a team API key with `webhook-deliveries:retry`. Project tokens are not accepted.", "x-audience": "public", "x-polymorfa-resource-boundary": "organization", "x-excluded-from-public": false, @@ -9483,14 +9486,14 @@ } } }, - "/v1/webhook-deliveries/{deliveryId}/attempts": { + "/platform/webhook-deliveries/{deliveryId}/attempts": { "get": { "operationId": "listOrganizationWebhookDeliveryAttempts", "tags": [ "webhook deliveries" ], "summary": "List organization delivery attempts", - "description": "Lists immutable network attempts for one organization webhook delivery.\n\nOrganization API-key callers require `webhook-deliveries:read`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "description": "Lists immutable network attempts for one organization webhook delivery.\n\nRequires a team API key with `webhook-deliveries:read`. Project tokens are not accepted.", "x-audience": "public", "x-polymorfa-resource-boundary": "organization", "x-excluded-from-public": false, @@ -9589,14 +9592,14 @@ } } }, - "/v1/webhook-deliveries/{deliveryId}/attempts/{attemptId}": { + "/platform/webhook-deliveries/{deliveryId}/attempts/{attemptId}": { "get": { "operationId": "getOrganizationWebhookDeliveryAttempt", "tags": [ "webhook deliveries" ], "summary": "Get organization delivery attempt", - "description": "Returns one immutable network attempt.\n\nOrganization API-key callers require `webhook-deliveries:read`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "description": "Returns one immutable network attempt.\n\nRequires a team API key with `webhook-deliveries:read`. Project tokens are not accepted.", "x-audience": "public", "x-polymorfa-resource-boundary": "organization", "x-excluded-from-public": false, @@ -9678,14 +9681,14 @@ } } }, - "/v1/projects/{projectId}/webhook-deliveries": { + "/platform/projects/{projectId}/webhook-deliveries": { "get": { "operationId": "listProjectWebhookDeliveries", "tags": [ "webhook deliveries" ], "summary": "List project webhook deliveries", - "description": "Lists logical webhook deliveries owned by the exact project in the route.\n\nOrganization API-key callers require `webhook-deliveries:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Lists logical webhook deliveries owned by the exact project in the route.\n\nRequires `webhook-deliveries:read`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -9835,14 +9838,14 @@ } } }, - "/v1/projects/{projectId}/webhook-deliveries/{deliveryId}": { + "/platform/projects/{projectId}/webhook-deliveries/{deliveryId}": { "get": { "operationId": "getProjectWebhookDelivery", "tags": [ "webhook deliveries" ], "summary": "Get a project webhook delivery", - "description": "Returns one logical webhook delivery owned by the exact project.\n\nOrganization API-key callers require `webhook-deliveries:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Returns one logical webhook delivery owned by the exact project.\n\nRequires `webhook-deliveries:read`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -9924,14 +9927,14 @@ } } }, - "/v1/projects/{projectId}/webhook-deliveries/{deliveryId}/retry": { + "/platform/projects/{projectId}/webhook-deliveries/{deliveryId}/retry": { "post": { "operationId": "retryProjectWebhookDelivery", "tags": [ "webhook deliveries" ], "summary": "Retry a project webhook delivery", - "description": "Appends a new immutable attempt to the same logical delivery owned by the exact project.\n\nOrganization API-key callers require `webhook-deliveries:retry`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Appends a new immutable attempt to the same logical delivery owned by the exact project.\n\nRequires `webhook-deliveries:retry`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -10029,14 +10032,14 @@ } } }, - "/v1/projects/{projectId}/webhook-deliveries/{deliveryId}/attempts": { + "/platform/projects/{projectId}/webhook-deliveries/{deliveryId}/attempts": { "get": { "operationId": "listProjectWebhookDeliveryAttempts", "tags": [ "webhook deliveries" ], "summary": "List project webhook delivery attempts", - "description": "Lists immutable network attempts for one project webhook delivery.\n\nOrganization API-key callers require `webhook-deliveries:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Lists immutable network attempts for one project webhook delivery.\n\nRequires `webhook-deliveries:read`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -10144,14 +10147,14 @@ } } }, - "/v1/projects/{projectId}/webhook-deliveries/{deliveryId}/attempts/{attemptId}": { + "/platform/projects/{projectId}/webhook-deliveries/{deliveryId}/attempts/{attemptId}": { "get": { "operationId": "getProjectWebhookDeliveryAttempt", "tags": [ "webhook deliveries" ], "summary": "Get a project webhook delivery attempt", - "description": "Returns one immutable network attempt owned by the exact project.\n\nOrganization API-key callers require `webhook-deliveries:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Returns one immutable network attempt owned by the exact project.\n\nRequires `webhook-deliveries:read`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -10242,22 +10245,19 @@ } } }, - "/v1/operations": { + "/console/operations": { "get": { "operationId": "listOrganizationOperations", "tags": [ "operations" ], "summary": "List organization operations", - "description": "Lists only organization-owned asynchronous operations. Project-owned operations are excluded.\n\nOrganization API-key callers require `operations:read`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", - "x-audience": "public", + "description": "Lists only organization-owned asynchronous operations. Project-owned operations are excluded.\n\nRequires a verified dashboard bearer and current organization authorization. Organization keys and project tokens are not accepted.", + "x-audience": "console", "x-polymorfa-resource-boundary": "organization", - "x-excluded-from-public": false, - "x-required-scope": "operations:read", + "x-excluded-from-public": true, + "x-exclusion-reason": "Dashboard operation bookkeeping; unavailable to machine credentials.", "security": [ - { - "ApiKeyAuth": [] - }, { "ConsoleSession": [] } @@ -10407,22 +10407,19 @@ } } }, - "/v1/operations/{operationId}": { + "/console/operations/{operationId}": { "get": { "operationId": "getOrganizationOperation", "tags": [ "operations" ], "summary": "Get an organization operation", - "description": "Returns one organization-owned asynchronous operation.\n\nOrganization API-key callers require `operations:read`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", - "x-audience": "public", + "description": "Returns one organization-owned asynchronous operation.\n\nRequires a verified dashboard bearer and current organization authorization. Organization keys and project tokens are not accepted.", + "x-audience": "console", "x-polymorfa-resource-boundary": "organization", - "x-excluded-from-public": false, - "x-required-scope": "operations:read", + "x-excluded-from-public": true, + "x-exclusion-reason": "Dashboard operation bookkeeping; unavailable to machine credentials.", "security": [ - { - "ApiKeyAuth": [] - }, { "ConsoleSession": [] } @@ -10487,22 +10484,19 @@ } } }, - "/v1/operations/{operationId}/transitions": { + "/console/operations/{operationId}/transitions": { "get": { "operationId": "listOrganizationOperationTransitions", "tags": [ "operations" ], "summary": "List organization operation transitions", - "description": "Lists immutable transitions for one organization-owned operation in ascending sequence.\n\nOrganization API-key callers require `operations:read`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", - "x-audience": "public", + "description": "Lists immutable transitions for one organization-owned operation in ascending sequence.\n\nRequires a verified dashboard bearer and current organization authorization. Organization keys and project tokens are not accepted.", + "x-audience": "console", "x-polymorfa-resource-boundary": "organization", - "x-excluded-from-public": false, - "x-required-scope": "operations:read", + "x-excluded-from-public": true, + "x-exclusion-reason": "Dashboard operation bookkeeping; unavailable to machine credentials.", "security": [ - { - "ApiKeyAuth": [] - }, { "ConsoleSession": [] } @@ -10603,22 +10597,19 @@ } } }, - "/v1/operations/{operationId}/cancel": { + "/console/operations/{operationId}/cancel": { "post": { "operationId": "cancelOrganizationOperation", "tags": [ "operations" ], "summary": "Cancel an organization operation", - "description": "Requests cancellation after transactionally rechecking that the operation is cancellable.\n\nOrganization API-key callers require `operations:cancel`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", - "x-audience": "public", + "description": "Requests cancellation after transactionally rechecking that the operation is cancellable.\n\nRequires a verified dashboard bearer and current organization authorization. Organization keys and project tokens are not accepted.", + "x-audience": "console", "x-polymorfa-resource-boundary": "organization", - "x-excluded-from-public": false, - "x-required-scope": "operations:cancel", + "x-excluded-from-public": true, + "x-exclusion-reason": "Dashboard operation bookkeeping; unavailable to machine credentials.", "security": [ - { - "ApiKeyAuth": [] - }, { "ConsoleSession": [] } @@ -10696,22 +10687,19 @@ } } }, - "/v1/projects/{projectId}/operations": { + "/console/projects/{projectId}/operations": { "get": { "operationId": "listProjectOperations", "tags": [ "operations" ], "summary": "List project operations", - "description": "Lists asynchronous operations owned by the exact project in the route.\n\nOrganization API-key callers require `operations:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", - "x-audience": "public", + "description": "Lists asynchronous operations owned by the exact project in the route.\n\nRequires a verified dashboard bearer and current organization authorization. Organization keys and project tokens are not accepted.", + "x-audience": "console", "x-polymorfa-resource-boundary": "project", - "x-excluded-from-public": false, - "x-required-scope": "operations:read", + "x-excluded-from-public": true, + "x-exclusion-reason": "Dashboard operation bookkeeping; unavailable to machine credentials.", "security": [ - { - "ApiKeyAuth": [] - }, { "ConsoleSession": [] } @@ -10873,22 +10861,19 @@ } } }, - "/v1/projects/{projectId}/operations/{operationId}": { + "/console/projects/{projectId}/operations/{operationId}": { "get": { "operationId": "getProjectOperation", "tags": [ "operations" ], "summary": "Get a project operation", - "description": "Returns one asynchronous operation owned by the exact project in the route.\n\nOrganization API-key callers require `operations:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", - "x-audience": "public", + "description": "Returns one asynchronous operation owned by the exact project in the route.\n\nRequires a verified dashboard bearer and current organization authorization. Organization keys and project tokens are not accepted.", + "x-audience": "console", "x-polymorfa-resource-boundary": "project", - "x-excluded-from-public": false, - "x-required-scope": "operations:read", + "x-excluded-from-public": true, + "x-exclusion-reason": "Dashboard operation bookkeeping; unavailable to machine credentials.", "security": [ - { - "ApiKeyAuth": [] - }, { "ConsoleSession": [] } @@ -10962,22 +10947,19 @@ } } }, - "/v1/projects/{projectId}/operations/{operationId}/transitions": { + "/console/projects/{projectId}/operations/{operationId}/transitions": { "get": { "operationId": "listProjectOperationTransitions", "tags": [ "operations" ], "summary": "List project operation transitions", - "description": "Lists immutable transitions for one project-owned operation in ascending sequence.\n\nOrganization API-key callers require `operations:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", - "x-audience": "public", + "description": "Lists immutable transitions for one project-owned operation in ascending sequence.\n\nRequires a verified dashboard bearer and current organization authorization. Organization keys and project tokens are not accepted.", + "x-audience": "console", "x-polymorfa-resource-boundary": "project", - "x-excluded-from-public": false, - "x-required-scope": "operations:read", + "x-excluded-from-public": true, + "x-exclusion-reason": "Dashboard operation bookkeeping; unavailable to machine credentials.", "security": [ - { - "ApiKeyAuth": [] - }, { "ConsoleSession": [] } @@ -11087,22 +11069,19 @@ } } }, - "/v1/projects/{projectId}/operations/{operationId}/cancel": { + "/console/projects/{projectId}/operations/{operationId}/cancel": { "post": { "operationId": "cancelProjectOperation", "tags": [ "operations" ], "summary": "Cancel a project operation", - "description": "Requests cancellation for an operation in the exact project after transactionally rechecking that it is cancellable.\n\nOrganization API-key callers require `operations:cancel`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", - "x-audience": "public", + "description": "Requests cancellation for an operation in the exact project after transactionally rechecking that it is cancellable.\n\nRequires a verified dashboard bearer and current organization authorization. Organization keys and project tokens are not accepted.", + "x-audience": "console", "x-polymorfa-resource-boundary": "project", - "x-excluded-from-public": false, - "x-required-scope": "operations:cancel", + "x-excluded-from-public": true, + "x-exclusion-reason": "Dashboard operation bookkeeping; unavailable to machine credentials.", "security": [ - { - "ApiKeyAuth": [] - }, { "ConsoleSession": [] } @@ -11189,14 +11168,14 @@ } } }, - "/v1/customers": { + "/platform/customers": { "get": { "operationId": "listCustomers", "tags": [ "customers" ], "summary": "List Customers", - "description": "Lists masked Customer summaries in the exact authenticated project with cursor pagination and filters.\n\nOrganization API-key callers require `customers:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Lists masked Customer summaries in the exact authenticated project with cursor pagination and filters.\n\nRequires `customers:read`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -11345,7 +11324,7 @@ "customers" ], "summary": "Create a Customer", - "description": "Creates a Customer with optional name, phone, and caller-defined external identifier.\n\nOrganization API-key callers require `customers:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Creates a Customer with optional name, phone, and caller-defined external identifier.\n\nRequires `customers:manage`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -11432,14 +11411,14 @@ } } }, - "/v1/customers/{customerId}": { + "/platform/customers/{customerId}": { "get": { "operationId": "getCustomer", "tags": [ "customers" ], "summary": "Get a Customer", - "description": "Returns one Customer from the exact authenticated project.\n\nOrganization API-key callers require `customers:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Returns one Customer from the exact authenticated project.\n\nRequires `customers:read`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -11525,7 +11504,7 @@ "customers" ], "summary": "Update a Customer", - "description": "Updates supplied Customer profile fields. Null clears an optional field.\n\nOrganization API-key callers require `customers:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Updates supplied Customer profile fields. Null clears an optional field.\n\nRequires `customers:manage`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -11611,14 +11590,14 @@ } } }, - "/v1/customers/{customerId}/archive": { + "/platform/customers/{customerId}/archive": { "post": { "operationId": "archiveCustomer", "tags": [ "customers" ], "summary": "Archive a Customer", - "description": "Archives a non-default Customer. The default Customer cannot be archived.\n\nOrganization API-key callers require `customers:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Archives a non-default Customer. The default Customer cannot be archived.\n\nRequires `customers:manage`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -11714,14 +11693,14 @@ } } }, - "/v1/customers/{customerId}/restore": { + "/platform/customers/{customerId}/restore": { "post": { "operationId": "restoreCustomer", "tags": [ "customers" ], "summary": "Restore a Customer", - "description": "Restores an archived Customer.\n\nOrganization API-key callers require `customers:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Restores an archived Customer.\n\nRequires `customers:manage`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -11817,14 +11796,14 @@ } } }, - "/v1/customers/{customerId}/numbers": { + "/platform/customers/{customerId}/numbers": { "get": { "operationId": "listCustomerNumbers", "tags": [ "customers" ], "summary": "List Customer Numbers", - "description": "Lists Numbers assigned to one Customer in the exact project.\n\nOrganization API-key callers require `customers:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Lists Numbers assigned to one Customer in the exact project.\n\nRequires `customers:read`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -11908,14 +11887,14 @@ } } }, - "/v1/customers/{customerId}/events": { + "/platform/customers/{customerId}/events": { "get": { "operationId": "listCustomerEvents", "tags": [ "customers" ], "summary": "List recent Customer events", - "description": "Lists the newest Customer lifecycle events with safe metadata. Actor identities, message content, phone values, invitation tokens, and URLs are excluded.\n\nOrganization API-key callers require `customers:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Lists the newest Customer lifecycle events with safe metadata. Actor identities, message content, phone values, invitation tokens, and URLs are excluded.\n\nRequires `customers:read`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -12010,14 +11989,14 @@ } } }, - "/v1/customers/{customerId}/pairing-links": { + "/platform/customers/{customerId}/pairing-links": { "post": { "operationId": "createCustomerPairingLink", "tags": [ "customers" ], "summary": "Create a Customer pairing link", - "description": "Creates a revocable Customer invitation. The raw URL is returned only in this response.\n\nOrganization API-key callers require `customers:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Creates a revocable Customer invitation. The raw URL is returned only in this response.\n\nRequires `customers:manage`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -12118,7 +12097,7 @@ "customers" ], "summary": "List Customer pairing links", - "description": "Lists safe pairing-link metadata. Raw invitation tokens and URLs are never returned.\n\nOrganization API-key callers require `customers:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Lists safe pairing-link metadata. Raw invitation tokens and URLs are never returned.\n\nRequires `customers:read`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -12202,14 +12181,14 @@ } } }, - "/v1/customers/{customerId}/pairing-links/{pairingLinkId}": { + "/platform/customers/{customerId}/pairing-links/{pairingLinkId}": { "delete": { "operationId": "revokeCustomerPairingLink", "tags": [ "customers" ], "summary": "Revoke a Customer pairing link", - "description": "Revokes an open pairing link.\n\nOrganization API-key callers require `customers:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Revokes an open pairing link.\n\nRequires `customers:manage`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -12301,14 +12280,14 @@ } } }, - "/v1/customers/{customerId}/numbers/{sessionId}/transfer": { + "/platform/customers/{customerId}/numbers/{sessionId}/transfer": { "post": { "operationId": "transferCustomerNumber", "tags": [ "customers" ], "summary": "Transfer a Customer Number", - "description": "Atomically transfers one eligible Number from the explicitly confirmed source Customer to the destination Customer.\n\nOrganization API-key callers require `customers:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Atomically transfers one eligible Number from the explicitly confirmed source Customer to the destination Customer.\n\nRequires `customers:manage`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -12413,14 +12392,14 @@ } } }, - "/v1/members": { + "/platform/members": { "get": { "operationId": "listMembers", "tags": [ "members" ], "summary": "List members", - "description": "Public Management API. Organization API-key callers require `sessions:read`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "description": "Public Management API. Requires a team API key with `sessions:read`. Project tokens are not accepted.", "x-audience": "public", "x-polymorfa-resource-boundary": "organization", "x-excluded-from-public": false, @@ -12470,17 +12449,18 @@ } } }, - "/v1/members/invites": { + "/console/members/invites": { "post": { "operationId": "inviteMember", "tags": [ "members" ], "summary": "Invite member", - "description": "Public Management API. Requires a verified dashboard bearer and current organization authorization. The signed-in member must be an organization owner or admin. Organization keys and project tokens are not accepted.", - "x-audience": "public", + "description": "**EXCLUDED from the public API** (`console`). Membership administration requires an authenticated console member.", + "x-audience": "console", "x-polymorfa-resource-boundary": "human_only", - "x-excluded-from-public": false, + "x-excluded-from-public": true, + "x-exclusion-reason": "Membership administration requires an authenticated console member.", "x-dashboard-only": true, "x-required-organization-role": "owner_or_admin", "security": [ @@ -12536,17 +12516,18 @@ } } }, - "/v1/members/{memberId}": { + "/console/members/{memberId}": { "patch": { "operationId": "updateMemberRole", "tags": [ "members" ], "summary": "Update member role", - "description": "Public Management API. Requires a verified dashboard bearer and current organization authorization. The signed-in member must be an organization owner or admin. Organization keys and project tokens are not accepted.", - "x-audience": "public", + "description": "**EXCLUDED from the public API** (`console`). Membership administration requires an authenticated console member.", + "x-audience": "console", "x-polymorfa-resource-boundary": "human_only", - "x-excluded-from-public": false, + "x-excluded-from-public": true, + "x-exclusion-reason": "Membership administration requires an authenticated console member.", "x-dashboard-only": true, "x-required-organization-role": "owner_or_admin", "security": [ @@ -12617,10 +12598,11 @@ "members" ], "summary": "Delete member", - "description": "Public Management API. Requires a verified dashboard bearer and current organization authorization. The signed-in member must be an organization owner or admin. Organization keys and project tokens are not accepted.", - "x-audience": "public", + "description": "**EXCLUDED from the public API** (`console`). Membership administration requires an authenticated console member.", + "x-audience": "console", "x-polymorfa-resource-boundary": "human_only", - "x-excluded-from-public": false, + "x-excluded-from-public": true, + "x-exclusion-reason": "Membership administration requires an authenticated console member.", "x-dashboard-only": true, "x-required-organization-role": "owner_or_admin", "security": [ @@ -12675,14 +12657,14 @@ } } }, - "/v1/keys": { + "/platform/keys": { "get": { "operationId": "listApiKeys", "tags": [ "keys" ], "summary": "List api keys", - "description": "Public Management API. Organization API-key callers require `sessions:read`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "description": "Public Management API. Requires a team API key with `sessions:read`. Project tokens are not accepted.", "x-audience": "public", "x-polymorfa-resource-boundary": "organization", "x-excluded-from-public": false, @@ -12732,14 +12714,14 @@ } } }, - "/v1/keys/{keyId}": { + "/platform/keys/{keyId}": { "delete": { "operationId": "deactivateApiKey", "tags": [ "keys" ], "summary": "Deactivate api key", - "description": "Public Management API. Organization API-key callers require `sessions:manage`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "description": "Public Management API. Requires a team API key with `sessions:manage`. Project tokens are not accepted.", "x-audience": "public", "x-polymorfa-resource-boundary": "organization", "x-excluded-from-public": false, @@ -12799,14 +12781,14 @@ } } }, - "/v1/tokens": { + "/platform/tokens": { "get": { "operationId": "listPolymorfaTokens", "tags": [ "tokens" ], "summary": "List polymorfa tokens", - "description": "Public Management API. Organization API-key callers require `sessions:read`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Public Management API. Requires `sessions:read`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -12866,14 +12848,14 @@ } } }, - "/v1/audit": { + "/platform/audit": { "get": { "operationId": "listAuditLogs", "tags": [ "audit" ], "summary": "List audit logs", - "description": "Public Management API. Organization API-key callers require `sessions:read`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "description": "Public Management API. Requires a team API key with `sessions:read`. Project tokens are not accepted.", "x-audience": "public", "x-polymorfa-resource-boundary": "organization", "x-excluded-from-public": false, @@ -12923,14 +12905,14 @@ } } }, - "/v1/incidents": { + "/platform/incidents": { "get": { "operationId": "listSecurityIncidents", "tags": [ "incidents" ], "summary": "List security incidents", - "description": "Public Management API. Organization API-key callers require `sessions:read`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "description": "Public Management API. Requires a team API key with `sessions:read`. Project tokens are not accepted.", "x-audience": "public", "x-polymorfa-resource-boundary": "organization", "x-excluded-from-public": false, @@ -12980,14 +12962,14 @@ } } }, - "/v1/incidents/{incidentId}/acknowledge": { + "/platform/incidents/{incidentId}/acknowledge": { "post": { "operationId": "acknowledgeSecurityIncident", "tags": [ "incidents" ], "summary": "Acknowledge security incident", - "description": "Public Management API. Organization API-key callers require `sessions:manage`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "description": "Public Management API. Requires a team API key with `sessions:manage`. Project tokens are not accepted.", "x-audience": "public", "x-polymorfa-resource-boundary": "organization", "x-excluded-from-public": false, @@ -13058,14 +13040,14 @@ } } }, - "/v1/media/{mediaId}": { + "/platform/media/{mediaId}": { "get": { "operationId": "getMediaUrl", "tags": [ "media" ], "summary": "Get media url", - "description": "Public Management API. Organization API-key callers require `media:read`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "description": "Public Management API. Requires a team API key with `media:read`. Project tokens are not accepted.", "x-audience": "public", "x-polymorfa-resource-boundary": "organization", "x-excluded-from-public": false, @@ -13130,7 +13112,7 @@ "media" ], "summary": "Delete media", - "description": "Public Management API. Organization API-key callers require `media:manage`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "description": "Public Management API. Requires a team API key with `media:manage`. Project tokens are not accepted.", "x-audience": "public", "x-polymorfa-resource-boundary": "organization", "x-excluded-from-public": false, @@ -13190,14 +13172,14 @@ } } }, - "/v1/media/uploads": { + "/platform/media/uploads": { "post": { "operationId": "createMediaUploadUrl", "tags": [ "media" ], "summary": "Create media upload url", - "description": "Public Management API. Organization API-key callers require `media:manage`; dashboard callers require current organization membership and authorization. Project tokens are rejected.", + "description": "Public Management API. Requires a team API key with `media:manage`. Project tokens are not accepted.", "x-audience": "public", "x-polymorfa-resource-boundary": "organization", "x-excluded-from-public": false, @@ -13258,14 +13240,14 @@ } } }, - "/v1/quicklink": { + "/platform/quicklink": { "get": { "operationId": "getQuickLinkSettings", "tags": [ "quicklink" ], "summary": "Read QuickLink settings", - "description": "Returns the saved QuickLink settings for the authenticated organization or one project, or null when nothing has been saved for that scope. There is no separate read permission: reading and updating both require `quicklink:manage`, because the settings include the redirect allowlist and branding that only a QuickLink manager should see.\n\nOrganization API-key callers require `quicklink:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Returns the saved QuickLink settings for the authenticated organization or one project, or null when nothing has been saved for that scope. There is no separate read permission: reading and updating both require `quicklink:manage`, because the settings include the redirect allowlist and branding that only a QuickLink manager should see.\n\nRequires `quicklink:manage`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -13341,7 +13323,7 @@ "quicklink" ], "summary": "Update QuickLink settings", - "description": "Updates the saved QuickLink settings for the authenticated organization or project and returns the saved record.\n\nOrganization API-key callers require `quicklink:manage`; project-token callers require the same action scope and are accepted only for `project` resources inside the authenticated project; dashboard callers require current organization membership and authorization.", + "description": "Updates the saved QuickLink settings for the authenticated organization or project and returns the saved record.\n\nRequires `quicklink:manage`. Project tokens only access resources in their own project.", "x-audience": "public", "x-polymorfa-resource-boundary": "project", "x-excluded-from-public": false, @@ -20210,29 +20192,62 @@ }, "ErrorEnvelope": { "type": "object", + "required": [ + "error", + "data", + "docs" + ], "properties": { "error": { - "type": "string", - "description": "Human-readable sentence describing the failure." + "type": "object", + "required": [ + "type", + "code", + "message", + "param" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "invalid_request_error", + "authentication_error", + "permission_error", + "conflict_error", + "rate_limit_error", + "api_error", + "upstream_error" + ] + }, + "code": { + "type": "string", + "description": "Stable failure code. Use this value for programmatic handling." + }, + "message": { + "type": "string", + "description": "Safe explanation of the failure." + }, + "param": { + "type": "string", + "nullable": true, + "description": "Invalid request field, or null when no field applies." + } + } }, - "code": { + "data": { "type": "string", - "description": "Stable, documented identifier for this failure. Present when the failure has one." + "nullable": true, + "enum": [ + null + ], + "description": "Always null for a failed request." }, "docs": { "type": "string", "format": "uri", - "description": "Documentation for this failure, when one is published." - }, - "retryAfter": { - "type": "integer", - "minimum": 0, - "description": "Seconds to wait before retrying, on a paced refusal or retryable service pause." + "description": "Documentation link to this failure code." } - }, - "required": [ - "error" - ] + } }, "ProjectId": { "type": "string", diff --git a/contracts/drafts/bansafe/source.json b/contracts/drafts/bansafe/source.json index 240da1c..30910e4 100644 --- a/contracts/drafts/bansafe/source.json +++ b/contracts/drafts/bansafe/source.json @@ -1,17 +1,17 @@ { "repository": "polymorfa/polymorfa", - "sourceBaseCommit": "77e157729d5f3d630d08c1e13f3aa93449e6065e", - "sourceState": "uncommitted-bansafe-draft", + "sourceCommit": "c9439c05305e4ccea6938a6ad2d5534494172743", + "sourceState": "pull-request-head", "contracts": { "messaging": { "sourcePath": "apps/api/docs/openapi.json", "snapshotPath": "contracts/drafts/bansafe/openapi.messaging.json", - "sha256": "1018fc4b096d79ad5bcfa45e7d1c0d46248decdb79348775c6f2b14d346da9c5" + "sha256": "6220a15d9f14ce177c526047612dd46bd1c8c69e1aaf3b56733b0490e3c3e0c8" }, "platform": { "sourcePath": "apps/api/docs/openapi.management.json", "snapshotPath": "contracts/drafts/bansafe/openapi.platform.json", - "sha256": "d529a62ddcc8e5b661b90db7ca9a36dddc30ca48a6a016c4f6b46e0fd471b9df" + "sha256": "a7f9d3b449aa93ebdf1e52c5c04519dd405d963a2da59db85d43748f671c95bf" } } } diff --git a/packages/typescript/README.md b/packages/typescript/README.md index 71ee1f0..1a8eed1 100644 --- a/packages/typescript/README.md +++ b/packages/typescript/README.md @@ -1255,7 +1255,7 @@ pending session. Connected links cannot be cancelled. The source exposes no list, recover, or history operation. `Client.quickLinkSettings.retrieve` and `update` map the management -`GET /v1/quicklink` and `PUT /v1/quicklink` operations. Use them on the root +`GET /platform/quicklink` and `PUT /platform/quicklink` operations. Use them on the root organization client or an immutable project view: ```ts @@ -1270,7 +1270,7 @@ const projectSettings = await platform These methods manage saved settings only. Hosted lifecycle methods stay on `MessagingClient.quickLinks`, not `Client` or `client.project(...)`, because -the `/api/quicklinks/{id}` routes do not carry an immutable project path for an +the `/messaging/quicklinks/{id}` routes do not carry an immutable project path for an organization-key project view. Console-only logo routes are outside the SDK. ## Management session lifecycle diff --git a/packages/typescript/src/platform/bansafe.ts b/packages/typescript/src/platform/bansafe.ts index 951a3fe..1adf608 100644 --- a/packages/typescript/src/platform/bansafe.ts +++ b/packages/typescript/src/platform/bansafe.ts @@ -40,7 +40,7 @@ export class BanSafeResource { params: ListBanSafeHealthParams = {}, options: RequestOptions = {}, ): Promise> { - return this.get("/v1/bansafe/health", params, options); + return this.get("/platform/bansafe/health", params, options); } getHealth( @@ -48,7 +48,7 @@ export class BanSafeResource { options: RequestOptions = {}, ): Promise>> { return this.get( - `/v1/bansafe/health/${encodeURIComponent(session)}`, + `/platform/bansafe/health/${encodeURIComponent(session)}`, {}, options, ); @@ -60,7 +60,7 @@ export class BanSafeResource { options: RequestOptions = {}, ): Promise>> { return this.get( - `/v1/bansafe/health/${encodeURIComponent(session)}/history`, + `/platform/bansafe/health/${encodeURIComponent(session)}/history`, params, options, ); @@ -69,7 +69,7 @@ export class BanSafeResource { listSignals( options: RequestOptions = {}, ): Promise>> { - return this.get("/v1/bansafe/signals", {}, options); + return this.get("/platform/bansafe/signals", {}, options); } getTelemetry( @@ -77,7 +77,7 @@ export class BanSafeResource { options: RequestOptions = {}, ): Promise>> { return this.get( - `/v1/bansafe/telemetry/${encodeURIComponent(session)}`, + `/platform/bansafe/telemetry/${encodeURIComponent(session)}`, {}, options, ); @@ -89,7 +89,7 @@ export class BanSafeResource { options: RequestOptions = {}, ): Promise> { return this.get( - `/v1/bansafe/telemetry/${encodeURIComponent(session)}/history`, + `/platform/bansafe/telemetry/${encodeURIComponent(session)}/history`, params, options, ); @@ -99,35 +99,35 @@ export class BanSafeResource { params: ListBanSafeCollectionParams = {}, options: RequestOptions = {}, ): Promise> { - return this.get("/v1/bansafe/collection", params, options); + return this.get("/platform/bansafe/collection", params, options); } listHealthActions( params: ListBanSafeHealthActionsParams = {}, options: RequestOptions = {}, ): Promise> { - return this.get("/v1/bansafe/health-actions", params, options); + return this.get("/platform/bansafe/health-actions", params, options); } listFindings( params: ListBanSafeFindingsParams = {}, options: RequestOptions = {}, ): Promise> { - return this.get("/v1/bansafe/findings", params, options); + return this.get("/platform/bansafe/findings", params, options); } listEnforcement( params: ListBanSafeEnforcementParams = {}, options: RequestOptions = {}, ): Promise> { - return this.get("/v1/bansafe/enforcement", params, options); + return this.get("/platform/bansafe/enforcement", params, options); } listIncidents( params: ListBanSafeIncidentsParams = {}, options: RequestOptions = {}, ): Promise> { - return this.get("/v1/bansafe/incidents", params, options); + return this.get("/platform/bansafe/incidents", params, options); } createIncident( @@ -136,7 +136,7 @@ export class BanSafeResource { ): Promise>> { return this.transport.request({ method: "POST", - path: "/v1/bansafe/incidents", + path: "/platform/bansafe/incidents", body, ...options, }); @@ -148,7 +148,7 @@ export class BanSafeResource { ): Promise>> { return this.transport.request({ method: "POST", - path: `/v1/bansafe/incidents/${encodeURIComponent(incidentId)}/retract`, + path: `/platform/bansafe/incidents/${encodeURIComponent(incidentId)}/retract`, ...options, }); } @@ -157,7 +157,7 @@ export class BanSafeResource { params: ListBanSafeClaimsParams = {}, options: RequestOptions = {}, ): Promise> { - return this.get("/v1/bansafe/claims", params, options); + return this.get("/platform/bansafe/claims", params, options); } getClaim( @@ -165,7 +165,7 @@ export class BanSafeResource { options: RequestOptions = {}, ): Promise>> { return this.get( - `/v1/bansafe/claims/${encodeURIComponent(claimId)}`, + `/platform/bansafe/claims/${encodeURIComponent(claimId)}`, {}, options, ); diff --git a/packages/typescript/src/platform/projects.ts b/packages/typescript/src/platform/projects.ts index a983323..b4635f2 100644 --- a/packages/typescript/src/platform/projects.ts +++ b/packages/typescript/src/platform/projects.ts @@ -185,7 +185,7 @@ export class ProjectsResource { ): Promise>> { return this.transport.request({ method: "GET", - path: `/v1/projects/${encodeURIComponent(projectId)}/${setting}`, + path: `/platform/projects/${encodeURIComponent(projectId)}/${setting}`, ...options, }); } @@ -199,7 +199,7 @@ export class ProjectsResource { ): Promise>> { return this.transport.request({ method: "PUT", - path: `/v1/projects/${encodeURIComponent(projectId)}/${setting}`, + path: `/platform/projects/${encodeURIComponent(projectId)}/${setting}`, body, ...options, }); diff --git a/packages/typescript/src/transport/http.ts b/packages/typescript/src/transport/http.ts index 01192dc..f670727 100644 --- a/packages/typescript/src/transport/http.ts +++ b/packages/typescript/src/transport/http.ts @@ -370,6 +370,10 @@ function apiError( function errorMessage(body: unknown, status: number): string { if (typeof body === "object" && body !== null) { const record = body as Record; + if (typeof record.error === "object" && record.error !== null) { + const message = (record.error as Record).message; + if (typeof message === "string") return message; + } if (typeof record.error === "string") return record.error; if (typeof record.message === "string") return record.message; } @@ -379,7 +383,12 @@ function errorMessage(body: unknown, status: number): string { function errorCode(body: unknown): Pick { if (typeof body === "object" && body !== null) { - const code = (body as Record).code; + const record = body as Record; + if (typeof record.error === "object" && record.error !== null) { + const code = (record.error as Record).code; + if (typeof code === "string") return { code }; + } + const code = record.code; if (typeof code === "string") return { code }; } return {}; diff --git a/packages/typescript/test/bansafe-contract.test.ts b/packages/typescript/test/bansafe-contract.test.ts index ead0b82..d10aa9c 100644 --- a/packages/typescript/test/bansafe-contract.test.ts +++ b/packages/typescript/test/bansafe-contract.test.ts @@ -42,7 +42,7 @@ const platform = JSON.parse( describe("BanSafe draft contract coverage", () => { it("pins the generated draft by content hash without claiming a merged source", () => { - expect(source.sourceState).toBe("uncommitted-bansafe-draft"); + expect(source.sourceState).toBe("pull-request-head"); for (const contract of Object.values(source.contracts)) { const hash = createHash("sha256") .update(readFileSync(resolve(root, contract.snapshotPath))) diff --git a/packages/typescript/test/bansafe.test.ts b/packages/typescript/test/bansafe.test.ts index 51089d7..2e668ed 100644 --- a/packages/typescript/test/bansafe.test.ts +++ b/packages/typescript/test/bansafe.test.ts @@ -116,14 +116,14 @@ describe("Client BanSafe resources", () => { ApiResponse >(); expect(requests.map(({ method, path }) => `${method} ${path}`)).toEqual([ - "GET /v1/bansafe/health?projectId=project%2Fa&cursor=cursor%2Fa&limit=25", - "GET /v1/bansafe/health/session%2Fa", - "GET /v1/bansafe/health/session%2Fa/history?since=2026-09-07T00%3A00%3A00.000Z&limit=12", - "GET /v1/bansafe/signals", - "GET /v1/bansafe/telemetry/session%2Fa", - "GET /v1/bansafe/telemetry/session%2Fa/history?since=2026-09-07T00%3A00%3A00.000Z&until=2026-09-08T00%3A00%3A00.000Z&cursor=cursor%2Fb&limit=10", - "GET /v1/bansafe/collection?projectId=project%2Fa&cursor=cursor%2Fc&limit=25", - "GET /v1/bansafe/health-actions?projectId=project%2Fa&session=session%2Fa&status=succeeded&cursor=cursor%2Fd&limit=25", + "GET /platform/bansafe/health?projectId=project%2Fa&cursor=cursor%2Fa&limit=25", + "GET /platform/bansafe/health/session%2Fa", + "GET /platform/bansafe/health/session%2Fa/history?since=2026-09-07T00%3A00%3A00.000Z&limit=12", + "GET /platform/bansafe/signals", + "GET /platform/bansafe/telemetry/session%2Fa", + "GET /platform/bansafe/telemetry/session%2Fa/history?since=2026-09-07T00%3A00%3A00.000Z&until=2026-09-08T00%3A00%3A00.000Z&cursor=cursor%2Fb&limit=10", + "GET /platform/bansafe/collection?projectId=project%2Fa&cursor=cursor%2Fc&limit=25", + "GET /platform/bansafe/health-actions?projectId=project%2Fa&session=session%2Fa&status=succeeded&cursor=cursor%2Fd&limit=25", ]); }); @@ -161,13 +161,13 @@ describe("Client BanSafe resources", () => { await client.banSafe.getClaim("claim/a"); expect(requests.map(({ method, path }) => `${method} ${path}`)).toEqual([ - "GET /v1/bansafe/findings?projectId=project%2Fa&session=session%2Fa&status=open&severity=critical&limit=5", - "GET /v1/bansafe/enforcement?projectId=project%2Fa&rung=throttle", - "GET /v1/bansafe/incidents?projectId=project%2Fa&session=session%2Fa", - "POST /v1/bansafe/incidents", - "POST /v1/bansafe/incidents/incident%2Fa/retract", - "GET /v1/bansafe/claims?projectId=project%2Fa&session=session%2Fa&status=under_review", - "GET /v1/bansafe/claims/claim%2Fa", + "GET /platform/bansafe/findings?projectId=project%2Fa&session=session%2Fa&status=open&severity=critical&limit=5", + "GET /platform/bansafe/enforcement?projectId=project%2Fa&rung=throttle", + "GET /platform/bansafe/incidents?projectId=project%2Fa&session=session%2Fa", + "POST /platform/bansafe/incidents", + "POST /platform/bansafe/incidents/incident%2Fa/retract", + "GET /platform/bansafe/claims?projectId=project%2Fa&session=session%2Fa&status=under_review", + "GET /platform/bansafe/claims/claim%2Fa", ]); expect(requests[3]?.headers["idempotency-key"]).toBe("incident/a"); expect(JSON.parse(requests[3]!.body)).toEqual({ @@ -208,16 +208,16 @@ describe("Client BanSafe resources", () => { ApiResponse> >(); expect(requests.map(({ method, path }) => `${method} ${path}`)).toEqual([ - "GET /v1/projects/project%2Fa/safe-mode", - "PUT /v1/projects/project%2Fa/safe-mode", - "GET /v1/projects/project%2Fa/warmup-plan", - "PUT /v1/projects/project%2Fa/warmup-plan", - "GET /v1/projects/project%2Fa/insurance-evidence", - "PUT /v1/projects/project%2Fa/insurance-evidence", - "GET /v1/projects/project%2Fa/health-policy", - "PUT /v1/projects/project%2Fa/health-policy", - "GET /v1/sessions/session%2Fa/safe-mode", - "PUT /v1/sessions/session%2Fa/safe-mode", + "GET /platform/projects/project%2Fa/safe-mode", + "PUT /platform/projects/project%2Fa/safe-mode", + "GET /platform/projects/project%2Fa/warmup-plan", + "PUT /platform/projects/project%2Fa/warmup-plan", + "GET /platform/projects/project%2Fa/insurance-evidence", + "PUT /platform/projects/project%2Fa/insurance-evidence", + "GET /platform/projects/project%2Fa/health-policy", + "PUT /platform/projects/project%2Fa/health-policy", + "GET /platform/sessions/session%2Fa/safe-mode", + "PUT /platform/sessions/session%2Fa/safe-mode", ]); }); }); diff --git a/packages/typescript/test/business.test.ts b/packages/typescript/test/business.test.ts index 1210ba8..3ca6968 100644 --- a/packages/typescript/test/business.test.ts +++ b/packages/typescript/test/business.test.ts @@ -118,7 +118,11 @@ describe("MessagingClient business", () => { expect( requests.map(({ method, path, body }) => ({ method, path, body })), ).toEqual([ - { method: "GET", path: "/messaging/sales%2Feu/business/profile", body: "" }, + { + method: "GET", + path: "/messaging/sales%2Feu/business/profile", + body: "", + }, { method: "PATCH", path: "/messaging/sales%2Feu/business/profile", diff --git a/packages/typescript/test/coverage-issues.test.ts b/packages/typescript/test/coverage-issues.test.ts index be35bd9..b7bb9b5 100644 --- a/packages/typescript/test/coverage-issues.test.ts +++ b/packages/typescript/test/coverage-issues.test.ts @@ -63,7 +63,12 @@ async function runScript( describe("coverage issue synchronizer", () => { it("creates the label, reopens and updates matches, creates new gaps, and closes resolved issues", async () => { const requests: RecordedRequest[] = []; - const existingMarker = marker("dev", "messaging", "GET", "/messaging/sessions"); + const existingMarker = marker( + "dev", + "messaging", + "GET", + "/messaging/sessions", + ); const staleMarker = marker("dev", "platform", "GET", "/platform/old"); const server = await startTestServer((request) => { requests.push(request); diff --git a/packages/typescript/test/system.test.ts b/packages/typescript/test/system.test.ts index 7f434b6..7370fff 100644 --- a/packages/typescript/test/system.test.ts +++ b/packages/typescript/test/system.test.ts @@ -51,7 +51,12 @@ describe("SystemClient", () => { expectTypeOf(ping).toEqualTypeOf>(); expect( fetch.mock.calls.map(([input]) => new URL(String(input)).pathname), - ).toEqual(["/messaging/info/status", "/messaging/info/version", "/health", "/ping"]); + ).toEqual([ + "/messaging/info/status", + "/messaging/info/version", + "/health", + "/ping", + ]); for (const [, init] of fetch.mock.calls) { expect(new Headers(init?.headers).has("authorization")).toBe(false); } diff --git a/packages/typescript/test/transport.test.ts b/packages/typescript/test/transport.test.ts index a65a5fc..827f921 100644 --- a/packages/typescript/test/transport.test.ts +++ b/packages/typescript/test/transport.test.ts @@ -163,7 +163,7 @@ describe("HttpTransport", () => { "content-type": "application/json", "x-request-id": "req_auth", }, - body: '{"error":"bad key","code":"invalid_key"}', + body: '{"error":{"type":"authentication_error","code":"invalid_credential","message":"Supply a valid credential.","param":null},"data":null,"docs":"https://docs.polymorfa.com/api/errors#invalid-credential"}', }; } return { @@ -172,7 +172,7 @@ describe("HttpTransport", () => { "content-type": "application/json", "x-request-id": "req_validation", }, - body: '{"error":"invalid project"}', + body: '{"error":{"type":"invalid_request_error","code":"invalid_parameter","message":"Correct the invalid project field.","param":"projectId"},"data":null,"docs":"https://docs.polymorfa.com/api/errors#invalid-parameter"}', }; }); const transport = makeTransport(server.url); @@ -184,7 +184,18 @@ describe("HttpTransport", () => { expect(authError).toMatchObject({ status: 401, requestId: "req_auth", - code: "invalid_key", + code: "invalid_credential", + message: "Supply a valid credential.", + details: { + error: { + type: "authentication_error", + code: "invalid_credential", + message: "Supply a valid credential.", + param: null, + }, + data: null, + docs: "https://docs.polymorfa.com/api/errors#invalid-credential", + }, }); const validationError = await transport @@ -194,6 +205,8 @@ describe("HttpTransport", () => { expect(validationError).toMatchObject({ status: 400, requestId: "req_validation", + code: "invalid_parameter", + message: "Correct the invalid project field.", }); }); From 254da4c4723488120ebb0f7d66a8c0e22b2fc373 Mon Sep 17 00:00:00 2001 From: Rajeh Taher Date: Wed, 9 Sep 2026 09:17:46 +0300 Subject: [PATCH 8/8] chore(contracts): pin final BanSafe API head --- contracts/drafts/bansafe/source.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/drafts/bansafe/source.json b/contracts/drafts/bansafe/source.json index 30910e4..dce5b44 100644 --- a/contracts/drafts/bansafe/source.json +++ b/contracts/drafts/bansafe/source.json @@ -1,6 +1,6 @@ { "repository": "polymorfa/polymorfa", - "sourceCommit": "c9439c05305e4ccea6938a6ad2d5534494172743", + "sourceCommit": "579a53488d6af339ef358857ad0de2a45e8a5d30", "sourceState": "pull-request-head", "contracts": { "messaging": {