{"openapi":"3.0.3","info":{"title":"AlmaTalk Customer API","description":"Customer API reference for AlmaTalk and supported ALMA CRM integrations. The authentication and server\nlisted on each operation are part of its contract.","version":"1.0.0"},"servers":[{"url":"/api/v1","description":"API v1"}],"tags":[{"name":"Introduction","description":"<h2>Welcome to AlmaTalk API</h2>\n\nAlmaTalk provides a powerful REST API for automating AI-powered voice calls. Whether you're building customer outreach, appointment reminders, lead qualification, or interactive voice applications, the API exposes the account operations listed in this reference.\n\n<br /><br />\n\n---\n\n<br />\n\n<h2>Getting Started</h2>\n\n<br />\n\n<h3>Step 1: Generate an API Key</h3>\n\nNavigate to your AlmaTalk dashboard → Settings → API and webhooks to create an API key.\n\n<br />\n\n**A key is scoped, not all-powerful.** You choose the scopes when you create it, and the key can do exactly those things and nothing else. A key holding only `calls:read` can list calls and cannot place one. Give each integration its own key with the smallest set of scopes it needs, and keep the secret out of client-side code: it is shown once, at creation, and is stored only as a hash afterwards.\n\n<br />\n\n<h3>Step 2: Make Your First Request</h3>\n\nTest your connection with a simple health check:\n\n```bash\ncurl -X GET \"https://almatalk.ca/api/v1/health\"\n```\n\n<br />\n\n<h3>Step 3: Authenticate Requests</h3>\n\nInclude your API key in every request using one of these methods:\n\n```bash\ncurl -H \"Authorization: Bearer YOUR_API_KEY\" ...\n\ncurl -H \"X-API-Key: YOUR_API_KEY\" ...\n```\n\n<br /><br />\n\n---\n\n<br />\n\n<h2>Core Concepts</h2>\n\n<br />\n\n| Concept | Description |\n|---------|-------------|\n| **Agents** | AI voice agents that handle conversations. Two types: Flow (visual conversation builder) and Incoming (for inbound calls). |\n| **Campaigns** | Bulk calling operations targeting multiple contacts with the same agent. |\n| **Calls** | Individual voice call records with transcripts, recordings, and analytics. |\n| **Contacts** | Lead records with phone numbers, custom fields, and AI-enriched data. See **Contact identity** below: `/contacts` is not the same store as the caller profiles the phone system builds. |\n| **Credits** | Talk time, metered by the second. See **Credits and metering** below. |\n| **Webhooks** | Event notifications delivered to your endpoints. |\n\n<br /><br />\n\n---\n\n<br />\n\n<h2>Credits and Metering</h2>\n\nCredits are **metered per second of answered conversation**, not per minute and not rounded up to one. On the standard model tier one second of talk time costs one credit, so a minute costs 60 and a 70-second call costs 70.\n\n<br />\n\nA higher AI model tier costs more per second: the effective rate is the base rate multiplied by that tier's multiplier, both read live from your account. Your dashboard's model picker shows the exact credits per minute for every tier you can select, and the pricing page shows what each plan includes. Do not hard-code a rate; read `GET /credits/balance` for the balance and take the rate from the dashboard or the pricing page.\n\n<br />\n\nFor reference, the Starter plan includes 9,000 credits, which is about 150 minutes of answered conversation on the standard tier.\n\n<br />\n\n**`GET /credits/usage` reports `minutes` as a copy of `credits`, not as measured call duration.** Treat `credits` as the truth and derive time from it with the rate above. Measured duration lives in `GET /analytics/calls` (`totalDurationMinutes`, `averageDurationSeconds`), which sums the recorded call length.\n\n<br /><br />\n\n---\n\n<br />\n\n<h2>Telephony Engines</h2>\n\nAlmaTalk supports two telephony engines for different use cases:\n\n<br />\n\n| Engine | Best For |\n|--------|----------|\n| AlmaTalk Voice (`almatalk-voice`) | Conversational voice agents |\n| Alma realtime (`alma-realtime`) | Realtime voice connection |\n\n<br /><br />\n\n---\n\n<br />\n\n<h2>Authentication</h2>\n\nThe v1 discovery root and `/health` are public. Other v1 operations require an API key; dashboard and embed operations use the separate authentication shown on their cards. For API-key operations:\n\n<br />\n\n- **Authorization Header**: `Authorization: Bearer YOUR_API_KEY`\n- **X-API-Key Header**: `X-API-Key: YOUR_API_KEY`\n\n<br />\n\nRequests handled by API-key authentication receive an `X-Request-ID` header. Quote it when you report a problem.\n\n<br /><br />\n\n---\n\n<br />\n\n<h2>Scopes</h2>\n\nA key carries a list of scopes and is refused with `403 INSUFFICIENT_SCOPES` on anything outside them. These are the scopes enforced by mounted v1 routes. The ALMA CRM section lists its additional connected scopes:\n\n<br />\n\n| Scope | Unlocks |\n|-------|---------|\n| `calls:read` | `GET /calls`, `GET /calls/{id}` |\n| `calls:write` | `POST /calls`, `POST /calls/{id}/hangup` |\n| `campaigns:read` | `GET /campaigns`, `GET /campaigns/{id}` |\n| `campaigns:write` | Create, start and pause campaigns, and add or upload contacts to them |\n| `agents:read` | `GET /agents`, `GET /agents/{id}`, `GET /agents/{id}/flow` |\n| `agents:write` | `PUT /agents/{id}/flow` |\n| `contacts:read` | `GET /contacts`, `GET /contacts/{id}` |\n| `contacts:write` | Create, update, delete and bulk-import contacts |\n| `appointments:read` | List and read appointments, check availability |\n| `appointments:write` | Create, reschedule and cancel appointments |\n| `credits:read` | `GET /credits/balance`, `GET /credits/usage` |\n| `analytics:read` | Everything under `/analytics`, plus `/credits/calls` and `/credits/campaigns` |\n| `webhooks:read` | `GET /webhooks`, `GET /webhooks/events` |\n| `webhooks:write` | Create, update, delete and test webhook subscriptions |\n| `admin` | A super-scope that satisfies every check above. It cannot be granted through self-service key creation or updates. Account-owner sessions manage keys; team sessions cannot. |\n\n<br />\n\n`403 INSUFFICIENT_SCOPES` names the scope that was missing and lists the scopes the key does hold, so you can fix it without guessing.\n\n<br /><br />\n\n---\n\n<br />\n\n<h2>Rate Limiting</h2>\n\nThe limit is **per key**, not per plan. Each key carries its own request ceiling and window, and both are visible on the key in your dashboard. A new key is created with a ceiling of **100 requests per 60 seconds**; the account owner can set the ceiling from 10 to 10,000 requests when creating or editing a key. The server controls the time window.\n\n<br />\n\nOver the ceiling the API answers `429 RATE_LIMIT_EXCEEDED` with `details.retryAfter` in seconds. Responses that pass key and IP validation carry the current state (including a rate-limit rejection). Authentication failures need not include these headers:\n\n<br />\n\n- `X-RateLimit-Limit` - this key's maximum requests per window\n- `X-RateLimit-Remaining` - requests left in the current window\n- `X-RateLimit-Reset` - Unix timestamp (seconds) when the window resets\n\n<br />\n\nA key may also carry an **IP allowlist**. When it is set, a request from any other address is refused with `403 IP_NOT_WHITELISTED`. An empty allowlist means any address is accepted.\n\n<br /><br />\n\n---\n\n<br />\n\n<h2>Contact Identity</h2>\n\nAlmaTalk keeps **two** stores of people, and they are not the same identity. Nothing merges them automatically, and you should not merge them on a phone number alone.\n\n<br />\n\n| | `GET /contacts` (this API) | Caller profiles |\n|---|---|---|\n| Table | `leads` | `caller_profiles` |\n| Created by | You, through this API, or by lead capture | The phone system, the first time a number reaches one of your agents |\n| Identifier | `id`, a lead id. This is the id `/contacts/{id}` takes | `id`, a caller-profile id. Not interchangeable with a lead id |\n| Fields | `phone`, `firstName`, `lastName`, `email`, `company`, `tags`, `customFields`, `stage`, `leadScore`, `aiSummary`, `sentiment` | `phone_number`, `caller_name`, `caller_email`, `caller_company`, plus what the agent learned on the call |\n| Written by | `POST /contacts`, `PUT /contacts/{id}`, `POST /contacts/bulk-import` | The dashboard's manual-contact and caller-profile routes, and the agent after a call |\n\n<br />\n\n**Mapping between them, when you need one:** the only shared field is the phone number, compared on the **last 10 digits** after every non-digit is stripped, which is how the dashboard's own manual-contact route matches. That is a heuristic, not a key: two people sharing a line, or an extension, will collide. Keep your own external id in `customFields` on the lead if you need a stable join, and do not assume a lead id and a caller-profile id ever refer to the same row.\n\n<br />\n\n**Campaign contacts are a third thing.** `POST /campaigns/{id}/contacts` writes rows in a campaign's own contact list, keyed to that campaign, not to `leads`.\n\n<br /><br />\n\n---\n\n<br />\n\n<h2>Response Format</h2>\n\n<br />\n\n<h3>Success Response</h3>\n\n```json\n{\n  \"success\": true,\n  \"data\": { ... },\n  \"meta\": {\n    \"requestId\": \"uuid\",\n    \"timestamp\": \"2024-01-01T00:00:00.000Z\"\n  }\n}\n```\n\n<br />\n\n<h3>Error Response</h3>\n\n```json\n{\n  \"success\": false,\n  \"error\": {\n    \"code\": \"ERROR_CODE\",\n    \"message\": \"Human readable message\",\n    \"details\": { ... }\n  },\n  \"meta\": { ... }\n}\n```\n\n<br /><br />\n\n---\n\n<br />\n\n<h2>Common Error Codes</h2>\n\n<br />\n\n| Code | HTTP Status | Description |\n|------|-------------|-------------|\n| `VALIDATION_ERROR` | 400 | Invalid request parameters |\n| `UNAUTHORIZED` | 401 | Missing or invalid API key |\n| `FORBIDDEN` | 403 | Insufficient permissions |\n| `NOT_FOUND` | 404 | Resource not found |\n| `INSUFFICIENT_CREDITS` | 402 | Not enough credits |\n| `RATE_LIMIT_EXCEEDED` | 429 | Too many requests |\n\n<br />\n\n\n<h2>Which authentication applies?</h2>\n\nThe primary integration API is `/api/v1`. Use an API key owned by the account and holding the scope shown on each operation. All records are account-scoped. A scope enables a route; it does not bypass available credits, trial restrictions, agent ownership, number ownership, or connected-service configuration. New keys default to `calls:read`, `calls:write`, `campaigns:read`, and `contacts:read` if scopes are omitted.\n\nThe ALMA CRM section uses `/api/plugins/crm-bridge`, with its own documented response shapes. Some connected CRM scopes are provisioned by the ALMA CRM connection and are not selectable in the ordinary API-key form. The key-management section requires an account-owner dashboard session. Existing dashboard actions are explicitly marked as session-only and use `/api`; an API key cannot authenticate those actions. Team permissions and feature availability still apply. Session APIs are for the signed-in application, not unattended API-key integrations.\n\nKnowledge scopes offered by the key form do not currently have a standalone `/api/v1` resource. Agent read and flow import/export are supported; creating or updating an agent prompt through an API key is not a published operation. Internal administration endpoints are not customer APIs.\n\n<h2>Pagination and safe retries</h2>\n\nREST list endpoints use `page` and `pageSize`, with pagination in `meta.pagination`; check each operation for its actual defaults and limits. CRM exports use opaque cursors and `has_more`. Keep a cursor unchanged between requests and stop when there is no next page. Incremental CRM call exports overlap by 24 hours so updated call results can be included; deduplicate by call id. Do not treat call ids as a UUID-only format.\n\nRead requests may be retried after a temporary error. Calls, messages, purchases, invitations and campaign starts can have side effects. Unless an operation explicitly describes idempotency, a retry after a timeout may duplicate the action. A successful submission does not prove a call was answered or a message delivered. Use the returned status, later reads and supported webhooks to reconcile outcomes. The reference examples do not execute requests; the interactive explorer does execute requests when you submit them.\n"},{"name":"Calls","description":"<h2>Voice Call Management</h2>\n\nThe Calls API allows you to trigger outbound calls, monitor active calls, and retrieve call history with transcripts and recordings.\n\n**Common Use Cases:**\n- Trigger individual calls to leads\n- Check call status and duration\n- Retrieve transcripts and AI summaries\n- Hang up active calls\n\n**Credit Usage:** Each call consumes credits for the seconds it is answered. On the standard model tier that is 1 credit a second, so 60 a minute; a higher model tier costs more per second. See **Credits and Metering** in the introduction.\n"},{"name":"Campaigns","description":"<h2>Bulk Calling Campaigns</h2>\n\nCampaigns enable you to call multiple contacts automatically using a single AI agent. Perfect for outreach, reminders, and surveys.\n\n**Campaign Lifecycle:**\n1. Create a campaign (status: `draft`)\n2. Add contacts to the campaign\n3. Start the campaign (status: `running`)\n4. Monitor progress or pause if needed\n5. Campaign completes when all contacts are called\n\n**Features:**\n- Schedule campaigns for specific times\n- Set calling windows (e.g., 9 AM - 6 PM)\n- Configure retry attempts for unanswered calls\n- Limit concurrent calls\n"},{"name":"Agents","description":"<h2>AI Voice Agents</h2>\n\nAgents are your AI-powered conversational assistants. They handle voice interactions using advanced conversation flows.\n\n**Agent Types:**\n\n| Type | Description |\n|------|-------------|\n| `flow` | Visual conversation builder with decision trees and LLM-powered responses |\n| `incoming` | Handles inbound calls on purchased phone numbers |\n\n**Note:** Agents must be active (`isActive: true`) before they can be used in calls or campaigns.\n"},{"name":"Contacts","description":"<h2>Lead Records</h2>\n\nManage your lead records with full CRUD operations. Leads can be enriched with AI-generated summaries and sentiment analysis after calls.\n\n**These are lead records, not caller profiles.** Every `id` on this tag is a lead id from the `leads` table. The phone system keeps a separate store of caller profiles, with its own ids, and the two are only ever matched on the last 10 digits of a phone number. Read **Contact identity** in the introduction before you build a sync.\n\n**Features:**\n- Store custom fields for personalization\n- Tag contacts for segmentation\n- Track lead stages through your funnel\n- Bulk import up to 10,000 leads at once\n\n**AI Enrichment:** After a call, lead records are updated with:\n- Conversation summary\n- Sentiment analysis\n- Lead score adjustments\n"},{"name":"Credits","description":"<h2>Credit Balance and Usage</h2>\n\nMonitor your credit balance and usage history. Credits are metered per second of answered conversation: on the standard model tier, 1 credit a second, so 60 a minute. A higher model tier costs more per second.\n\n**Understanding Credits:**\n- Credits are deducted in real time during calls, by the second, with no rounding up to a whole minute\n- The rate depends on the AI model tier the agent runs; your dashboard's model picker shows the exact credits per minute for each tier\n- Campaigns pause automatically when credits run low\n- `GET /credits/usage` reports `minutes` as a copy of `credits`, not as measured call duration. Use `credits`, or read measured duration from `GET /analytics/calls`\n"},{"name":"Analytics","description":"<h2>Call and Campaign Analytics</h2>\n\nAccess aggregated statistics and insights about your calling activity. Use this data to optimize campaigns and measure ROI.\n\n**Available Metrics:**\n- Total calls and minutes\n- Answer rates and outcomes\n- Average call duration\n- Campaign performance comparisons\n- Daily/weekly/monthly trends\n"},{"name":"Webhooks","description":"<h2>Event Notifications</h2>\n\nWebhooks deliver notifications to your server when events occur. Use them to sync data, trigger workflows, or build integrations.\n\n<br />\n\n<h3>Supported events</h3>\n\nThis is the complete list `POST /webhooks` and `PUT /webhooks/{id}` accept. Anything else is refused with `400 VALIDATION_ERROR` and the response lists these names back to you. `GET /webhooks/events` returns the same list at runtime.\n\n<br />\n\n| Event | Meaning | Emitted today |\n|-------|---------|---------------|\n| `call.started` | Triggered when a call begins | yes |\n| `call.ringing` | Triggered when an outbound destination is ringing | yes |\n| `call.answered` | Triggered when an outbound call is answered | yes |\n| `call.completed` | Triggered when a call ends successfully | yes |\n| `call.failed` | Triggered when a call fails | yes |\n| `call.transferred` | Triggered when a call is transferred | yes |\n| `call.no_answer` | Triggered when an outbound call is not answered | yes |\n| `call.busy` | Triggered when an outbound destination is busy | yes |\n| `call.voicemail` | Triggered when an outbound call reaches voicemail | yes |\n| `inbound_call.received` | Triggered when an inbound call reaches the platform | yes |\n| `inbound_call.answered` | Triggered when an inbound call is answered | yes |\n| `inbound_call.completed` | Triggered when an answered inbound call completes | yes |\n| `inbound_call.missed` | Triggered when an inbound call is missed | yes |\n| `campaign.started` | Triggered when a campaign starts | yes |\n| `campaign.completed` | Triggered when a campaign finishes | yes |\n| `campaign.paused` | Triggered when a campaign is paused | yes |\n| `campaign.resumed` | Triggered when a paused campaign resumes | yes |\n| `campaign.failed` | Triggered when a campaign fails | yes |\n| `campaign.cancelled` | Triggered when a campaign is cancelled | yes |\n| `flow.started` | Triggered when a compiled call flow starts | yes |\n| `flow.completed` | Triggered when a compiled call flow completes | yes |\n| `flow.failed` | Triggered when a compiled call flow fails | yes |\n| `appointment.booked` | Triggered when an appointment is booked | yes |\n| `appointment.confirmed` | Triggered when an appointment is confirmed | yes |\n| `appointment.cancelled` | Triggered when an appointment is cancelled | yes |\n| `appointment.rescheduled` | Triggered when an appointment is rescheduled | yes |\n| `appointment.completed` | Triggered when an appointment is marked complete | yes |\n| `appointment.no_show` | Triggered when an appointment is marked as a no-show | yes |\n| `form.submitted` | Triggered when a voice flow saves a form submission | yes |\n| `contact.created` | Reserved for contact creation | **no** |\n| `contact.updated` | Reserved for contact updates | **no** |\n| `credits.low` | Reserved for a low credit balance | **no** |\n| `credits.depleted` | Reserved for an exhausted credit balance | **no** |\n\n<br />\n\n**Read the last column.** The four marked **no** are accepted on a subscription and are fired by nothing in this deployment, so a subscriber waiting on one waits for ever. They are listed because the API accepts them, not because they arrive. `GET /webhooks/events` carries the same flag as `emitted`.\n\n<br /><br />\n\n---\n\n<br />\n\n<h3>Signature verification</h3>\n\nEvery delivery is signed with **HMAC-SHA256 over the exact request body bytes**, using the subscription secret returned once when the webhook was created, and the digest is lowercase hexadecimal.\n\n<br />\n\nTwo senders reach your endpoint, and their headers differ. Both are listed exactly as they go out:\n\n<br />\n\n| | Real events | The test ping from `POST /webhooks/{id}/test` |\n|---|---|---|\n| Signature header | `X-Webhook-Signature: sha256=<hex>` | `X-Webhook-Signature: <hex>` and `X-AlmaTalk-Signature: <hex>`, same value under both names |\n| Prefixed | yes, `sha256=` | no, bare hex |\n| Event header | `X-Webhook-Event: <event name>` | `X-AlmaTalk-Event: test.ping` |\n| Delivery id | `X-Webhook-Delivery: <uuid>` | none |\n| User agent | `Platform-Webhook/1.0` | default |\n| Timeout | 30 seconds | 10 seconds |\n| Retries | up to 3 attempts, at 0s, 60s and 300s | none, a single attempt |\n\n<br />\n\nWrite one verifier that **strips an optional `sha256=` prefix** and it handles both. Compare in constant time, and hash the raw body, not a re-serialized object:\n\n<br />\n\n```js\nimport crypto from \"crypto\";\n\nfunction verify(secret, rawBody, header) {\n  const received = String(header || \"\").trim().replace(/^sha256=/i, \"\");\n  if (!/^[0-9a-f]{64}$/i.test(received)) return false;\n  const expected = crypto.createHmac(\"sha256\", secret).update(rawBody).digest(\"hex\");\n  const a = Buffer.from(expected, \"hex\");\n  const b = Buffer.from(received.toLowerCase(), \"hex\");\n  return a.length === b.length && crypto.timingSafeEqual(a, b);\n}\n\n// Express: capture the raw body, then\n//   verify(secret, req.rawBody, req.get(\"X-Webhook-Signature\"))\n```\n\n<br />\n\n<h3>Delivery behaviour</h3>\n\n- `https` is strongly recommended. `http` is accepted; a destination that resolves to a loopback, private, link-local or cloud-metadata address is refused before anything is sent.\n- Redirects are not followed on a real event delivery. Point the subscription at the final URL.\n- Answer `2xx` within the timeout above. Retries for real events are held in memory, so a platform restart ends them.\n- There is no replay endpoint. Store the delivery you received.\n"},{"name":"Appointments","description":"<h2>Booking system</h2>\n\nCreate, read, update, and cancel appointments through the API. Each appointment belongs to the authenticated user (scoped by API key). Working-hours validation runs automatically against the user's `appointment_settings`.\n\n**Canonical path: `/appointments`.** `/booking` is an alias of the same router and answers identically on every operation below; it exists because the routes were mounted there first. New integrations should use `/appointments`. Nothing that already calls `/booking` needs to change.\n\n**Two meeting types:**\n- `virtual` - a video meeting room is auto-created when the agent or user has `auto_create_meeting_room=true` (or you pass `auto_create_meeting_room: true` in the request). The response includes `meeting_link` and `meeting_passcode`.\n- `in_person` - no virtual room is created; the confirmation surfaces the office address instead.\n\n**Auto-sync to Google Calendar:** if the user has connected Google Calendar, a cron job runs every 15 minutes pushing any new appointment to their primary calendar. The `google_calendar_event_id` field gets populated after the push succeeds.\n\n**Required scopes:**\n- `appointments:read` - list / get / availability\n- `appointments:write` - create / update / cancel\n"},{"name":"Campaign Types","description":"<h2>Campaign types (dashboard endpoint)</h2>\n\n**These are not API-key endpoints.** They are mounted under `/api`, not `/api/v1`,\nand authenticate with a dashboard session token. An API key is refused. They are\ndocumented here because integrators ask about them.\n"},{"name":"Follow-Ups","description":"<h2>Follow-ups (dashboard endpoints)</h2>\n\n**These are not API-key endpoints.** They are mounted under `/api/plugins/follow-ups`\nwith a dashboard session token, and an API key is refused. They are documented here\nbecause integrators ask about them.\n\nFollow-up contacts are addressed by **phone number**, not by a lead id or a\ncaller-profile id. See **Contact Identity** in the introduction for why those are\nthree different things.\n"},{"name":"ALMA CRM","description":"Account-scoped integration routes under `/api/plugins/crm-bridge`, separate from `/api/v1`. Use an account API key with the displayed scope. Connected messaging, email, meetings, numbers and webphone functions require their corresponding account configuration and capabilities. The ordinary API-key form does not offer every connected CRM scope; use the supported ALMA CRM connection for those capabilities. Browser CORS is enabled for `https://almacrm.ca`; general integrations should run on their own server and keep keys private.\n\nCRM responses are endpoint-specific and do not uniformly use the REST `success/data/meta` envelope. Authentication and rate-limit failures use the common API-key error envelope; handler errors may be `{error: \"message\"}`. Number routes relay the account number-service response. Do not assume that an HTTP success confirms final delivery or an answered call.\n\nCRM webhooks are configured separately from REST webhooks. `PUT /webhook-config` returns the tenant signing secret and supports `sms.inbound` and `call.completed`. Validate `X-Alma-Signature` as `sha256=` followed by HMAC-SHA256 of the exact raw body with that secret, using a timing-safe comparison. Do not apply the bare-digest REST signature convention to this CRM header. Store secrets securely and deduplicate event processing.\n"},{"name":"Account API keys","description":"These dashboard endpoints require the signed-in account owner session. API keys and team-member\nsessions cannot manage keys. Use Settings > API and webhooks for the same controls. Store a new or regenerated\nkey immediately: the complete secret is returned only at creation or rotation. Regenerating or deleting invalidates\nexisting integrations using that secret. The admin super-scope cannot be granted through these endpoints."},{"name":"Dashboard views","description":"Configure the dashboard in [Settings: Dashboard layout](/app/settings?tab=dashboard). These session-only\noperations control quick actions, cards and shortcuts.\n\n\nTo give members different views: list active members, read the selected member view, then save its full prefs\nobject. Individual overrides are optional. A member without an override follows their current role default.\nDELETE the member override to restore that inheritance. Updating a role default does not replace existing individual\noverrides.\n\n\nThese are dashboard content preferences, not an arbitrary landing-page assignment. Feature permissions still\ndetermine what a member can access. Account-owner authority manages individual views; team-management create\nor update permission is sufficient for role defaults, not individual member overrides."},{"name":"Navigation layout","description":"Configure navigation in [Settings: Menu](/app/settings?tab=menu). Menu preferences control visibility,\nitem order and group order for the owner or a team role. A menu preferences PUT merges supplied arrays, while\nmenu-config PUT replaces group names and custom links.\n\n\nDashboard overrides and navigation layouts are separate. A member-specific dashboard does not create a member-specific\nmenu. Resetting menu preferences does not delete custom links or group names, and showing a menu entry does\nnot grant access to it."},{"name":"Workspace team directory","description":"Read account member and role identifiers for workspace configuration. These session-only directory\noperations do not create members, modify permissions or send invitations."},{"name":"AI follow-up drafts","description":"Generate a draft from one currently visible completed call. Draft-only never sends. Generate-and-send requires confirmed: true and current create/update permissions, but schedule, approval, recipient and plan gates still apply. Save the request UUID before submitting. If a result is unknown or the connection is lost, read the same generation; never submit a new UUID automatically. A queue or sent status is not delivery proof."},{"name":"Task calendar and bulk work","description":"Session-only work views use current account timezone and current member permissions. Bulk operations require preview then human confirmation, check each current task revision, and report partial results per item. They change workflow state only and do not send messages or create calendar events."},{"name":"Task evidence review","description":"Evidence coverage can be unavailable or unknown. A call ending, an API success or an AI suggestion does not prove customer delivery or completion. Confirming links evidence, or completes an eligible human task, without sending anything."},{"name":"Calendar sync","description":"Calendar sync is opt-in. Owners manage office connections; members manage their own eligible connections, subject to current calendar/follow-up/booking permissions. Enabled destinations create private generic work reminders with no attendees, no reminders and free availability. Existing calendar events are preserved when sync is disabled. Review unknown outcomes before another action; reconciliation never retries event creation."},{"name":"Manual follow-ups","description":"Use the authenticated account or member session, not an integration API key. Current follow-up read/create/update permissions and task visibility apply. Preview before creating. Approval and scheduling gates may hold a task; completing a workflow row is not proof of a message being delivered. Requested callbacks remain controlled by their separate workflow."},{"name":"Caller profiles","description":"Profile fields belong to the authenticated account. Conversation and call reads also respect their current visibility rules. Translation returns display text without rewriting the source. Notes and human tasks may notify mentioned teammates; marking a conversation read does not send a message."},{"name":"Task assignment rules","description":"Only the account owner can manage assignment rules; team and delegated sessions are refused. Rules route human work to currently eligible members. Saving a rule does not send a message. Backfill requires a fresh preview fingerprint and is limited to the newest 200 eligible tasks."},{"name":"Follow-up tools","description":"Automation rules, templates and sequences are owned by the account. Owners can write; permitted members with View All can read. Rule preview is also available to members with follow-up read permission, without private sample data. Tests, task execution, staff job messages and sequence enrollment can cause real sends or future actions. Use them only after the intended person confirms."}],"security":[{"ApiKeyAuth":[]},{"BearerAuth":[]}],"paths":{"/health":{"get":{"summary":"Health Check","description":"Verify the API is operational. This endpoint does not require authentication and is useful for monitoring and uptime checks.\n\n**Use Case:** Add this endpoint to your monitoring tools to detect API outages.\n","operationId":"healthCheck","tags":["Introduction"],"security":[],"responses":{"200":{"description":"API is healthy and ready to accept requests","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"}}}}}}},"/calls":{"get":{"summary":"List Calls","description":"Retrieve a paginated list of all calls made from your account. Results include calls from all telephony engines (AlmaTalk Voice, AlmaTalk Global).\n\n**Tip:** Use the `page` and `pageSize` parameters to navigate through large result sets efficiently.\n\n**Required Scope:** `calls:read`\n","operationId":"listCalls","tags":["Calls"],"parameters":[{"$ref":"#/components/parameters/PageParam"},{"$ref":"#/components/parameters/PageSizeParam"}],"responses":{"200":{"description":"List of calls with pagination metadata","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CallListResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}},"x-required-scopes":["calls:read"]},"post":{"summary":"Trigger Call","description":"Initiate an outbound call using a specified AI agent. The call will be placed immediately unless scheduled for a future time.\n\n<br />\n\n**Prerequisites:**\n- An active AI agent (flow or incoming type)\n- Sufficient credits in your account\n- An active phone number (or provide `fromNumber`)\n\n<br />\n\n**Telephony Engines:**\n- `almatalk-voice`: AlmaTalk Voice engine, 29 languages\n- `alma-realtime`: Alma realtime voice engine\n\n<br />\n\n**Required Scope:** `calls:write`\n\n\nThis action places a call immediately. Trial accounts can be refused with `403 DEMO_OUTBOUND_DISABLED`. Sufficient credits, an owned agent and an active owned phone number are required. `success: true` records request processing; inspect `data.status` for a failed attempt and do not equate submission with an answered call.","operationId":"triggerCall","tags":["Calls"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TriggerCallRequest"},"examples":{"basic":{"summary":"Basic call","value":{"agentId":"550e8400-e29b-41d4-a716-446655440000","toNumber":"+14155551234"}},"withEngine":{"summary":"Specify engine","value":{"agentId":"550e8400-e29b-41d4-a716-446655440000","toNumber":"+14155551234","engine":"alma-realtime","fromNumber":"+14155559999"}}}}}},"responses":{"201":{"description":"Call initiated successfully. Returns call ID and initial status.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TriggerCallResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/InsufficientCredits"},"404":{"$ref":"#/components/responses/NotFound"}},"x-required-scopes":["calls:write"]}},"/calls/{id}":{"get":{"summary":"Get Call Details","description":"Retrieve detailed information about a specific call including:\n- Call status and duration\n- Full conversation transcript\n- AI-generated summary\n- Sentiment analysis\n- Recording URL (if available)\n\n<br />\n\n**Tip:** Poll this endpoint to track call progress. Status will transition from `queued` → `ringing` → `in-progress` → `completed`.\n\n<br />\n\n**Required Scope:** `calls:read`\n","operationId":"getCall","tags":["Calls"],"parameters":[{"$ref":"#/components/parameters/CallIdParam"}],"responses":{"200":{"description":"Complete call details with transcript and analytics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CallDetailResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"x-required-scopes":["calls:read"]}},"/calls/{id}/hangup":{"post":{"summary":"Compatibility hangup acknowledgment (no call control)","deprecated":true,"description":"This compatibility endpoint returns an acknowledgment only. It does not look up the call, check its status, or terminate it.\n\nDo not use the success response or `hangup_requested` value as evidence that a call ended. Active call termination is not supported through this operation.\n\n**Required Scope:** `calls:write`\n","operationId":"hangupCall","tags":["Calls"],"parameters":[{"$ref":"#/components/parameters/CallIdParam"}],"responses":{"200":{"description":"Compatibility acknowledgment only. No call termination is performed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HangupResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"}},"x-required-scopes":["calls:write"]}},"/campaigns":{"get":{"summary":"List Campaigns","description":"Retrieve all campaigns with their current status and progress metrics.\n\n<br />\n\n**Campaign Statuses:**\n- `draft` - Created but not started\n- `scheduled` - Waiting for scheduled start time\n- `running` - Actively making calls\n- `paused` - Temporarily stopped\n- `completed` - All contacts processed\n- `cancelled` - Permanently stopped\n\n<br />\n\n**Required Scope:** `campaigns:read`\n","operationId":"listCampaigns","tags":["Campaigns"],"parameters":[{"$ref":"#/components/parameters/PageParam"},{"$ref":"#/components/parameters/PageSizeParam"}],"responses":{"200":{"description":"List of campaigns with progress metrics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignListResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"}},"x-required-scopes":["campaigns:read"]},"post":{"summary":"Create Campaign","description":"Create a new bulk calling campaign with optional contacts CSV upload. The campaign starts in `draft` status and won't execute until you start it.\n\n<br />\n\n**Simplified Workflow:**\n1. Create campaign with contacts CSV → 2. Start campaign\n\n<br />\n\n**Request Format:**\nThis endpoint accepts `multipart/form-data` to allow simultaneous campaign creation and contact import.\n\n<br />\n\n**Campaign Data Options:**\n- Send as JSON string in `data` field, OR\n- Send as individual form fields (name, agentId, etc.)\n\n<br />\n\n**CSV Upload (Optional):**\nInclude a `contacts` field with your CSV file. Recognized columns:\n- `phone` or `phone_number` - Required\n- `firstName`, `lastName`, `name`, `email`\n- Any other columns become custom fields\n\n<br />\n\n**Configuration Options:**\n- **Calling Windows:** Restrict calls to business hours\n- **Concurrent Calls:** Control call volume (1-100)\n- **Retry Logic:** Automatically retry unanswered calls\n- **Scheduling:** Start immediately or at a future time\n\n<br />\n\n**Required Scope:** `campaigns:write`\n","operationId":"createCampaign","tags":["Campaigns"],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["name","agentId"],"properties":{"data":{"type":"string","description":"Campaign data as JSON string (alternative to individual fields)","example":"{\"name\": \"Q1 Outreach\", \"agentId\": \"550e8400-e29b-41d4-a716-446655440000\"}"},"name":{"type":"string","description":"Campaign name (use either this or data field)","example":"Q1 Lead Outreach"},"agentId":{"type":"string","format":"uuid","description":"Agent to use for calls"},"phoneNumberId":{"type":"string","format":"uuid","description":"Phone number to call from"},"engine":{"type":"string","enum":["almatalk-voice","alma-realtime"],"description":"Telephony engine. almatalk-voice: AlmaTalk Voice engine. alma-realtime: Alma realtime\nvoice engine."},"scheduledStartTime":{"type":"string","format":"date-time","description":"When to start the campaign"},"timezone":{"type":"string","example":"America/New_York"},"callWindowStart":{"type":"string","pattern":"^\\d{2}:\\d{2}$","example":"09:00"},"callWindowEnd":{"type":"string","pattern":"^\\d{2}:\\d{2}$","example":"18:00"},"maxConcurrentCalls":{"type":"integer","minimum":1,"maximum":100,"example":10},"contacts":{"type":"string","format":"binary","description":"Optional CSV file with contacts"}}}},"application/json":{"schema":{"$ref":"#/components/schemas/CreateCampaignRequest"},"examples":{"basic":{"summary":"Basic campaign (JSON)","value":{"name":"Q1 Lead Outreach","agentId":"550e8400-e29b-41d4-a716-446655440000"}},"scheduled":{"summary":"Scheduled campaign","value":{"name":"Appointment Reminders","agentId":"550e8400-e29b-41d4-a716-446655440000","scheduledStartTime":"2024-01-15T09:00:00Z","timezone":"America/New_York","callWindowStart":"09:00","callWindowEnd":"18:00","maxConcurrentCalls":10}}}}}},"responses":{"201":{"description":"Campaign created with optional contact import results","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/CampaignResponse"},{"type":"object","properties":{"data":{"type":"object","properties":{"contacts":{"type":"object","description":"Present only if CSV was uploaded","properties":{"fileName":{"type":"string"},"totalRows":{"type":"integer"},"contactsAdded":{"type":"integer"},"contactsSkipped":{"type":"integer"},"invalidRows":{"type":"integer"}}}}}}}]},"example":{"success":true,"data":{"id":"550e8400-e29b-41d4-a716-446655440000","name":"Q1 Lead Outreach","status":"draft","agentId":"550e8400-e29b-41d4-a716-446655440001","contacts":{"fileName":"leads.csv","totalRows":150,"contactsAdded":145,"contactsSkipped":3,"invalidRows":2}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"x-required-scopes":["campaigns:write"]}},"/campaigns/{id}":{"get":{"summary":"Get Campaign Details","description":"Retrieve detailed information about a campaign including:\n- Current status and progress\n- Contact counts (total, called, remaining)\n- Schedule and timing information\n- Configuration settings\n\n<br />\n\n**Required Scope:** `campaigns:read`\n","operationId":"getCampaign","tags":["Campaigns"],"parameters":[{"$ref":"#/components/parameters/IdParam"}],"responses":{"200":{"description":"Campaign details with progress metrics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"x-required-scopes":["campaigns:read"]}},"/campaigns/{id}/contacts":{"post":{"summary":"Add Campaign Contacts","description":"Add contacts to a campaign's call list. You can add up to 10,000 contacts per request.\n\n<br />\n\n**Important:** Contacts can only be added when the campaign status is `draft` or `paused`. Running campaigns will reject new contacts.\n\n<br />\n\n**Contact Fields:**\n- `phoneNumber` (required) - Phone number in E.164 format\n- `firstName`, `lastName`, `email` - Optional contact info\n- `customFields` - Key-value pairs for personalization in agent scripts\n\n<br />\n\n**Tip:** Use `customFields` to pass data like appointment times or account numbers that your agent can reference during the call.\n\n<br />\n\n**Required Scope:** `campaigns:write`\n","operationId":"addCampaignContacts","tags":["Campaigns"],"parameters":[{"$ref":"#/components/parameters/IdParam"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddCampaignContactsRequest"},"examples":{"simple":{"summary":"Basic contacts","value":{"contacts":[{"phoneNumber":"+14155551234","firstName":"John","lastName":"Doe"},{"phoneNumber":"+14155555678","firstName":"Jane","lastName":"Smith"}]}},"withCustomFields":{"summary":"Contacts with custom fields","value":{"contacts":[{"phoneNumber":"+14155551234","firstName":"John","customFields":{"appointmentTime":"2:00 PM","doctorName":"Dr. Smith"}}]}}}}}},"responses":{"201":{"description":"Contacts added with success/skip counts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddContactsResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}},"x-required-scopes":["campaigns:write"]}},"/campaigns/{id}/contacts-upload":{"post":{"summary":"Upload CSV Contacts","description":"Upload a CSV file to add contacts to a campaign. This is the recommended method for bulk contact imports.\n\n<br />\n\n**CSV Format:**\nThe CSV must include a header row. Recognized columns:\n- `phone` or `phone_number` - Required, contact phone number\n- `firstName` or `first_name` - First name\n- `lastName` or `last_name` - Last name\n- `name` - Full name (splits into first/last automatically)\n- `email` - Email address\n- Any other columns become custom fields\n\n<br />\n\n**AlmaTalk Voice Format Support:**\nColumns prefixed with `dynamic_data.` are automatically converted to custom fields.\n\n<br />\n\n**Example CSV:**\n```\nphone,firstName,lastName,appointmentTime\n+14155551234,John,Doe,2:00 PM\n+14155555678,Jane,Smith,3:30 PM\n```\n\n<br />\n\n**Limits:**\n- Maximum file size: 10MB\n- Maximum contacts: 10,000 per upload\n\n<br />\n\n**Required Scope:** `campaigns:write`\n","operationId":"uploadCampaignContacts","tags":["Campaigns"],"parameters":[{"$ref":"#/components/parameters/IdParam"}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary","description":"CSV file containing contacts"}}}}}},"responses":{"201":{"description":"CSV processed successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"campaignId":{"type":"string","format":"uuid"},"fileName":{"type":"string","example":"contacts.csv"},"totalRows":{"type":"integer","description":"Total rows parsed from CSV","example":150},"contactsAdded":{"type":"integer","description":"New contacts added","example":145},"contactsSkipped":{"type":"integer","description":"Duplicate contacts skipped","example":3},"invalidRows":{"type":"integer","description":"Rows with invalid phone numbers","example":2}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}},"x-required-scopes":["campaigns:write"]}},"/campaigns/{id}/start":{"post":{"summary":"Start Campaign","description":"Begin executing a campaign. The system will start placing calls to contacts according to your configuration.\n\n<br />\n\n**Prerequisites:**\n- Campaign must have at least one contact\n- Sufficient credits for estimated calls\n- Associated agent must be active\n\n<br />\n\n**Behavior:**\n- Calls are placed respecting `maxConcurrentCalls` limit\n- Calling windows are honored (no calls outside configured hours)\n- Failed calls are retried based on `retryAttempts` setting\n\n<br />\n\n**Required Scope:** `campaigns:write`\n","operationId":"startCampaign","tags":["Campaigns"],"parameters":[{"$ref":"#/components/parameters/IdParam"}],"responses":{"200":{"description":"Campaign started successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignActionResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/InsufficientCredits"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}},"x-required-scopes":["campaigns:write"]}},"/campaigns/{id}/pause":{"post":{"summary":"Pause Campaign","description":"Temporarily pause a running campaign. Active calls will complete, but no new calls will be initiated.\n\n<br />\n\n**Resume:** Use the Start Campaign endpoint to resume a paused campaign.\n\n<br />\n\n**Use Cases:**\n- Credit running low\n- Need to add more contacts\n- Business hours ended\n\n<br />\n\n**Required Scope:** `campaigns:write`\n","operationId":"pauseCampaign","tags":["Campaigns"],"parameters":[{"$ref":"#/components/parameters/IdParam"}],"responses":{"200":{"description":"Campaign paused. Active calls will complete.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignActionResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}},"x-required-scopes":["campaigns:write"]}},"/agents":{"get":{"summary":"List Agents","description":"Retrieve all AI agents in your account. Each agent represents a configured voice assistant with its own personality, language, and behavior.\n\n<br />\n\n**Agent Status:**\n- `isActive: true` - Agent is ready for calls\n- `isActive: false` - Agent is disabled\n\n<br />\n\n**Required Scope:** `agents:read`\n","operationId":"listAgents","tags":["Agents"],"parameters":[{"$ref":"#/components/parameters/PageParam"},{"$ref":"#/components/parameters/PageSizeParam"}],"responses":{"200":{"description":"List of agents with basic information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentListResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"}},"x-required-scopes":["agents:read"]}},"/agents/{id}":{"get":{"summary":"Get Agent Details","description":"Retrieve complete configuration for an agent including:\n- System prompt and first message\n- Voice and LLM settings\n- Transfer configuration\n- Language and personality settings\n\n<br />\n\n**Use Case:** Inspect agent settings before using in campaigns or calls.\n\n<br />\n\n**Required Scope:** `agents:read`\n","operationId":"getAgent","tags":["Agents"],"parameters":[{"$ref":"#/components/parameters/IdParam"}],"responses":{"200":{"description":"Complete agent configuration","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentDetailResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"x-required-scopes":["agents:read"]}},"/agents/{id}/flow":{"get":{"summary":"Export Agent Flow","description":"Export the visual conversation flow for a Flow-type agent. Returns the flow nodes and edges, including captured-variable configuration on individual steps.\n\n<br />\n\n**Use Cases:**\n- Backup agent configurations\n- Clone flows to other agents\n- Version control flow designs\n- Share flows between accounts\n\n<br />\n\n**Note:** Only works for agents with `type: flow`. Incoming agents don't have exportable flows.\n\n<br />\n\n**Required Scope:** `agents:read`\n","operationId":"exportAgentFlow","tags":["Agents"],"parameters":[{"$ref":"#/components/parameters/IdParam"}],"responses":{"200":{"description":"Complete flow definition with nodes and edges","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowExportResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"x-required-scopes":["agents:read"]},"put":{"summary":"Import Agent Flow","description":"Save a validated flow definition for an owned agent. New flows are inactive drafts. Review and publish the result in Flow Builder to update the connected agent.\n\n<br />\n\n**Warning:** This replaces the existing flow entirely. Export the current flow first if you want to preserve it.\n\n<br />\n\n**Flow Structure:**\n- `nodes` - Array of flow nodes (message, question, condition, etc.)\n- `edges` - Connections between nodes\n- Capture variables inside question and form node configuration. Top-level variables are not supported.\n\n<br />\n\n**Required Scope:** `agents:write`\n","operationId":"importAgentFlow","tags":["Agents"],"parameters":[{"$ref":"#/components/parameters/IdParam"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowImportRequest"}}}},"responses":{"200":{"description":"Flow definition saved; publish in Flow Builder to update the connected agent","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowImportResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"x-required-scopes":["agents:write"]}},"/contacts":{"get":{"summary":"List Contacts","description":"Retrieve all contacts from your CRM. Contacts are enriched with AI-generated data after calls.\n\n<br />\n\n**Contact Data Includes:**\n- Basic info (name, phone, email, company)\n- Custom fields for personalization\n- Tags for segmentation\n- Lead stage and score\n- AI summary and sentiment (post-call)\n\n<br />\n\n**Required Scope:** `contacts:read`\n","operationId":"listContacts","tags":["Contacts"],"parameters":[{"$ref":"#/components/parameters/PageParam"},{"$ref":"#/components/parameters/PageSize50Param"}],"responses":{"200":{"description":"List of contacts with enriched data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactListResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"}},"x-required-scopes":["contacts:read"]},"post":{"summary":"Create Contact","description":"Add a new contact to your CRM. The phone number is required; all other fields are optional.\n\n<br />\n\n**Best Practices:**\n- Use E.164 format for phone numbers (+1234567890)\n- Add custom fields that your agents can reference\n- Use tags for easy filtering and segmentation\n\n<br />\n\n**Required Scope:** `contacts:write`\n","operationId":"createContact","tags":["Contacts"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateContactRequest"},"examples":{"basic":{"summary":"Basic contact","value":{"phone":"+14155551234","firstName":"John","lastName":"Doe","email":"john@example.com"}},"withCustomFields":{"summary":"Contact with custom fields","value":{"phone":"+14155551234","firstName":"John","company":"Acme Corp","tags":["lead","enterprise"],"customFields":{"accountId":"ACC-12345","preferredTime":"morning"}}}}}}},"responses":{"201":{"description":"Contact created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"409":{"$ref":"#/components/responses/Conflict"}},"x-required-scopes":["contacts:write"]}},"/contacts/{id}":{"get":{"summary":"Get Contact Details","description":"Retrieve complete information about a contact including call history and AI enrichment.\n\n<br />\n\n**AI Enrichment (after calls):**\n- `aiSummary` - AI-generated summary of conversations\n- `sentiment` - Detected sentiment (positive, neutral, negative)\n- `leadScore` - Automatically calculated lead score\n\n<br />\n\n**Required Scope:** `contacts:read`\n","operationId":"getContact","tags":["Contacts"],"parameters":[{"$ref":"#/components/parameters/IdParam"}],"responses":{"200":{"description":"Complete contact details with AI enrichment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"x-required-scopes":["contacts:read"]},"put":{"summary":"Update Contact","description":"Update contact information. Only include fields you want to change.\n\n<br />\n\n**Tip:** Update the `stage` field to move contacts through your sales funnel.\n\n<br />\n\n**Required Scope:** `contacts:write`\n","operationId":"updateContact","tags":["Contacts"],"parameters":[{"$ref":"#/components/parameters/IdParam"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateContactRequest"}}}},"responses":{"200":{"description":"Contact updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"x-required-scopes":["contacts:write"]},"delete":{"summary":"Delete Contact","description":"Permanently delete a contact and all associated data.\n\n<br />\n\n**Warning:** This action cannot be undone. Call history remains but will no longer be linked to this contact.\n\n<br />\n\n**Required Scope:** `contacts:write`\n","operationId":"deleteContact","tags":["Contacts"],"parameters":[{"$ref":"#/components/parameters/IdParam"}],"responses":{"200":{"description":"Contact permanently deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"x-required-scopes":["contacts:write"]}},"/contacts/bulk-import":{"post":{"summary":"Bulk Import Contacts","description":"Import up to 10,000 contacts in a single request. Ideal for syncing from external CRMs or uploading lists.\n\n<br />\n\n**Behavior:**\n- Duplicate phone numbers are skipped\n- Invalid records are counted in `failed` response field\n- Import is atomic: all succeed or detailed errors returned\n\n<br />\n\n**Performance Tip:** For very large imports, batch into multiple requests of 5,000 contacts each.\n\n<br />\n\n**Required Scope:** `contacts:write`\n","operationId":"bulkImportContacts","tags":["Contacts"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkImportRequest"}}}},"responses":{"201":{"description":"Import completed with success/failure counts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkImportResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"}},"x-required-scopes":["contacts:write"]}},"/credits/balance":{"get":{"summary":"Get Credit Balance","description":"Check your current credit balance. Use this to verify you have sufficient credits before starting campaigns.\n\n<br />\n\n**Credit System:**\n- Credits are metered by the second of answered conversation, with no rounding up to a whole minute\n- On the standard model tier that is 1 credit a second, so 60 a minute; a higher model tier costs more per second\n- Balance updates in real time during calls\n- `available` and `total` are the same number today, and `reserved` is always `0`. Nothing is held back for a running campaign, so do not treat `available` as a commitment.\n\n<br />\n\n**Required Scope:** `credits:read`\n","operationId":"getCreditBalance","tags":["Credits"],"responses":{"200":{"description":"Current credit balance","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreditBalanceResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"}},"x-required-scopes":["credits:read"]}},"/credits/usage":{"get":{"summary":"Get Credit Usage","description":"Retrieve credit usage history for budgeting and analysis. Shows daily usage breakdown.\n\n<br />\n\n**Use Cases:**\n- Track spending over time\n- Identify high-usage periods\n- Plan credit purchases\n- Generate billing reports\n\n<br />\n\n**`minutes` is a copy of `credits`, not measured call duration.** Each day's row sums the deduction amounts, and the same sum is reported under both names. Read `credits` and convert with the rate in **Credits and Metering**, or read measured duration from `GET /analytics/calls`.\n\n<br />\n\n**`calls` counts credit deductions, not calls.** A call billed in more than one deduction counts more than once.\n\n<br />\n\nAt most 1,000 transactions are read per request, newest first, so a very busy account over a long window can under-report the oldest days.\n\n<br />\n\n**Required Scope:** `credits:read`\n","operationId":"getCreditUsage","tags":["Credits"],"parameters":[{"name":"days","in":"query","description":"Number of days to include in the report. Defaults to 30. A non-numeric value falls back to\n30.","schema":{"type":"integer","default":30,"minimum":1}}],"responses":{"200":{"description":"Daily credit usage breakdown","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreditUsageResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"}},"x-required-scopes":["credits:read"]}},"/analytics/calls":{"get":{"summary":"Get Call Analytics","description":"Retrieve aggregated call statistics. Useful for dashboards and performance monitoring.\n\n<br />\n\n**Metrics Included:**\n- Total, completed and failed call counts\n- Total duration in minutes and average duration in seconds\n- Credits used\n- Start and end of the aggregate reporting period\n\n<br />\n\n**Required Scope:** `analytics:read`\n","operationId":"getCallAnalytics","tags":["Analytics"],"parameters":[{"name":"days","in":"query","description":"Number of days to analyze (default 30). No upper limit is enforced by this endpoint.","schema":{"type":"integer","default":30,"minimum":1}}],"responses":{"200":{"description":"Call analytics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CallAnalyticsResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"}},"x-required-scopes":["analytics:read"]}},"/analytics/campaigns":{"get":{"summary":"Get Campaign Analytics","description":"Retrieve performance analytics for all campaigns. Compare effectiveness across different campaigns.\n\n<br />\n\n**Metrics Per Campaign:**\n- Campaign name, status and total contacts\n- Completed, successful, failed and pending counts\n- Success rate, calculated against total contacts\n- Start, completion and creation timestamps\n- Pagination metadata\n\n<br />\n\n**Required Scope:** `analytics:read`\n","operationId":"getCampaignAnalytics","tags":["Analytics"],"parameters":[{"$ref":"#/components/parameters/PageParam"},{"$ref":"#/components/parameters/PageSize50Param"}],"responses":{"200":{"description":"Performance metrics for all campaigns","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignAnalyticsResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"}},"x-required-scopes":["analytics:read"]}},"/analytics/summary":{"get":{"summary":"Get Analytics Summary","description":"Get a high-level summary of all activity. Perfect for executive dashboards and quick status checks.\n\n<br />\n\n**Summary Includes:**\n- Selected reporting period\n- Total and completed calls within that period\n- Total, running and completed campaigns across the account\n\n<br />\n\n**Required Scope:** `analytics:read`\n","operationId":"getAnalyticsSummary","tags":["Analytics"],"parameters":[{"name":"days","in":"query","description":"Time period to summarize (default 30 days)","schema":{"type":"integer","default":30}}],"responses":{"200":{"description":"High-level analytics summary","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnalyticsSummaryResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"}},"x-required-scopes":["analytics:read"]}},"/webhooks":{"get":{"summary":"List Webhooks","description":"Retrieve all webhook subscriptions. Each webhook listens for specific events and delivers payloads to your endpoint.\n\n<br />\n\n**Reading the state of a subscription.** There is no single `status` field. Each row carries:\n- `isActive` - `true` while the subscription receives events, `false` while it is paused. Set it with `PUT /webhooks/{id}`.\n- `lastDeliveryAt` and `lastDeliveryStatus` - when the last delivery was attempted and how it went.\n\nA subscription is never disabled automatically by failed deliveries. If deliveries are failing, `lastDeliveryStatus` says so and `isActive` stays as you left it.\n\n<br />\n\nThe signing secret is not returned here. It is shown once, in the create response.\n\n<br />\n\n**Required Scope:** `webhooks:read`\n","operationId":"listWebhooks","tags":["Webhooks"],"responses":{"200":{"description":"List of webhook subscriptions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookListResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"}},"x-required-scopes":["webhooks:read"]},"post":{"summary":"Create Webhook","description":"Subscribe to events with a new webhook. Your endpoint will receive HTTP POST requests when events occur.\n\n<br />\n\n**Setup Requirements:**\n- A publicly reachable endpoint. `https` is strongly recommended; `http` is accepted. A destination resolving to a loopback, private, link-local or cloud-metadata address is refused before anything is sent.\n- Respond `2xx` within 30 seconds on a real event, within 10 seconds on the test ping.\n- A failed real-event delivery is retried up to 3 times in total, at 0s, 60s and 300s. Those timers live in memory, so a platform restart ends them. The test ping is a single attempt and is never retried.\n\n<br />\n\n**Signature Verification:**\nThe payload is signed with HMAC-SHA256 over the exact body bytes. Real events arrive as `X-Webhook-Signature: sha256=<hex>`; the test ping arrives as `X-Webhook-Signature: <hex>` and `X-AlmaTalk-Signature: <hex>`, the same value under both names and with no prefix. Strip an optional `sha256=` prefix and one verifier handles both. The full table and a working verifier are in the **Webhooks** section above.\n\n<br />\n\n**The secret is shown once,** in this response, and is not retrievable afterwards. Store it before you close the connection.\n\n<br />\n\n**Required Scope:** `webhooks:write`\n","operationId":"createWebhook","tags":["Webhooks"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWebhookRequest"},"examples":{"callEvents":{"summary":"Subscribe to call events","value":{"url":"https://your-server.com/webhooks/almatalk","events":["call.started","call.completed","call.failed"]}},"allEvents":{"summary":"Subscribe to all events","value":{"url":"https://your-server.com/webhooks/almatalk","events":["call.started","call.completed","call.failed","campaign.started","campaign.completed"]}}}}}},"responses":{"201":{"description":"Webhook created with signing secret","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"}},"x-required-scopes":["webhooks:write"]}},"/webhooks/events":{"get":{"summary":"List Supported Events","description":"Get a list of all event types you can subscribe to. Use these event names when creating webhooks. This endpoint and the table in the **Webhooks** section above are generated from the same list in code, so they cannot disagree.\n\n<br />\n\n**Event Categories:**\n- `call.*` - call lifecycle events\n- `campaign.*` - campaign lifecycle events\n- `contact.*` - reserved for contact changes, accepted but not emitted yet\n- `credits.*` - reserved for balance thresholds, accepted but not emitted yet\n\n<br />\n\nThere is no `subscription.*` family. Earlier versions of this reference listed one; the API has never accepted it.\n\n<br />\n\nEach row carries `emitted`: `false` means the name can be subscribed to and nothing in this deployment fires it.\n\n<br />\n\n**Required Scope:** `webhooks:read`\n","operationId":"listWebhookEvents","tags":["Webhooks"],"responses":{"200":{"description":"List of available event types","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEventsResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"}},"x-required-scopes":["webhooks:read"]}},"/webhooks/{id}":{"put":{"summary":"Update Webhook","description":"Modify a webhook's configuration. You can change the URL, events, or active status.\n\n<br />\n\n**Tip:** Set `active: false` to temporarily pause a webhook without deleting it.\n\n<br />\n\n**Required Scope:** `webhooks:write`\n","operationId":"updateWebhook","tags":["Webhooks"],"parameters":[{"$ref":"#/components/parameters/IdParam"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateWebhookRequest"}}}},"responses":{"200":{"description":"Webhook configuration updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"x-required-scopes":["webhooks:write"]},"delete":{"summary":"Delete Webhook","description":"Permanently delete a webhook subscription. No further events will be delivered to this endpoint.\n\n**Required Scope:** `webhooks:write`\n","operationId":"deleteWebhook","tags":["Webhooks"],"parameters":[{"$ref":"#/components/parameters/IdParam"}],"responses":{"200":{"description":"Webhook deleted successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"x-required-scopes":["webhooks:write"]}},"/webhooks/{id}/test":{"post":{"summary":"Test Webhook","description":"Send a test payload to verify your webhook endpoint is configured correctly. The test payload mimics a real event.\n\n<br />\n\n**Test Process:**\n1. AlmaTalk sends a `test.ping` payload to your URL, signed with your subscription secret\n2. Your server should return a 2xx status\n3. The response tells you whether it was delivered and with what status code\n\n<br />\n\n**The test ping is not byte-identical to a real event.** It carries `X-AlmaTalk-Event: test.ping`, it signs with `X-Webhook-Signature: <hex>` and `X-AlmaTalk-Signature: <hex>` with no `sha256=` prefix (a real event prefixes it), it has no `X-Webhook-Delivery` header, it times out at 10 seconds rather than 30, and it is never retried. Build your verifier to strip an optional `sha256=` prefix and both deliveries verify.\n\n<br />\n\n**Troubleshooting:**\n- Ensure your endpoint is publicly accessible\n- Respond within 10 seconds, or this call answers `504 TIMEOUT`\n- Verify the TLS certificate is valid\n\n<br />\n\n**Required Scope:** `webhooks:write`\n","operationId":"testWebhook","tags":["Webhooks"],"parameters":[{"$ref":"#/components/parameters/IdParam"}],"responses":{"200":{"description":"Test results with timing and response info","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookTestResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"x-required-scopes":["webhooks:write"]}},"/campaign-types":{"servers":[{"url":"/api","description":"Dashboard API. Session token, not an API key."}],"get":{"tags":["Campaign Types"],"summary":"List campaign types","description":"Returns global (admin-created) + user's own custom campaign types.\n\nDashboard session only. This operation does not accept API keys; account or team permissions and feature availability apply.","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Array of campaign types"}}},"post":{"tags":["Campaign Types"],"summary":"Create custom campaign type","description":"Create a user-scoped custom campaign type.\n\nDashboard session only. This operation does not accept API keys; account or team permissions and feature availability apply.","security":[{"SessionAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","example":"Reactivation Campaign"}}}}}},"responses":{"200":{"description":"Created type"}}}},"/campaign-types/{id}":{"servers":[{"url":"/api","description":"Dashboard API. Session token, not an API key."}],"delete":{"tags":["Campaign Types"],"summary":"Delete custom campaign type","description":"Only custom types owned by the user can be deleted.\n\nDashboard session only. This operation does not accept API keys; account or team permissions and feature availability apply.","security":[{"SessionAuth":[]}],"parameters":[{"$ref":"#/components/parameters/IntegerIdParam"}],"responses":{"200":{"description":"Deleted"}}}},"/contacts/manual":{"servers":[{"url":"/api","description":"Dashboard API. Session token, not an API key."}],"post":{"tags":["Contacts"],"summary":"Add contact manually","description":"Add a contact either to a campaign (with campaignId) or standalone (to caller_profiles).\n\nDashboard session only. This operation does not accept API keys; account or team permissions and feature availability apply.","security":[{"SessionAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["phoneNumber"],"properties":{"campaignId":{"type":"string","description":"Optional campaign to add to"},"phoneNumber":{"type":"string","example":"+15145550142"},"firstName":{"type":"string"},"lastName":{"type":"string"},"email":{"type":"string","format":"email"},"company":{"type":"string"}}}}}},"responses":{"201":{"description":"Contact created","content":{"application/json":{"schema":{"type":"object","required":["success","contact"],"properties":{"success":{"type":"boolean"},"contact":{"type":"object","nullable":true,"additionalProperties":true}}}}}}}}},"/plugins/follow-ups/rules":{"servers":[{"url":"/api","description":"Dashboard API. Session token, not an API key."}],"get":{"tags":["Follow-Ups"],"summary":"List follow-up rules","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"List of rules"}},"description":"\n\nDashboard session only. This operation does not accept API keys; account or team permissions and feature availability apply."},"post":{"tags":["Follow-Ups"],"summary":"Create follow-up rule","security":[{"SessionAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","trigger_event","action_type"],"properties":{"name":{"type":"string"},"trigger_event":{"type":"string","enum":["call.completed","call.no_answer","appointment.booked","appointment.completed","appointment.no_show","appointment.reminder","meeting.reminder"]},"action_type":{"type":"string","enum":["send_email","send_sms","send_whatsapp","schedule_callback","ai_suggest"]},"delay_minutes":{"type":"integer","description":"For \"after event\" triggers, delay after event. For \"reminder\" triggers, time before\nthe appointment."},"template_id":{"type":"integer"}}}}}},"responses":{"201":{"description":"Rule created","content":{"application/json":{"schema":{"type":"object","required":["success","rule"],"properties":{"success":{"type":"boolean"},"rule":{"type":"object","nullable":true,"additionalProperties":true}}}}}}},"description":"\n\nDashboard session only. This operation does not accept API keys; account or team permissions and feature availability apply."}},"/plugins/follow-ups/queue":{"servers":[{"url":"/api","description":"Dashboard API. Session token, not an API key."}],"get":{"tags":["Follow-Ups"],"summary":"List follow-up queue items","security":[{"SessionAuth":[]}],"parameters":[{"name":"status","in":"query","schema":{"type":"string","enum":["pending","completed","failed","cancelled","all"]}},{"name":"type","in":"query","schema":{"type":"string","enum":["send_email","send_sms","send_whatsapp","schedule_callback"]}}],"responses":{"200":{"description":"Queue items with reason + editable message/prompt"}},"description":"\n\nDashboard session only. This operation does not accept API keys; account or team permissions and feature availability apply."},"post":{"tags":["Manual follow-ups"],"summary":"Create a manual follow-up (alias)","description":"Use the same requestId for readback after a lost response. The version 1 manual policy path is idempotent for identical input. Automatic approval requires update permission. Scheduling, quiet hours, plan, recipient and expiry gates can hold the task. Human task mentions may notify teammates. This response does not prove delivery.","operationId":"client_post_plugins_follow_ups_queue","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Existing identical request returned without creating another task.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"created":{"type":"boolean"},"item":{"$ref":"#/components/schemas/ClientFollowupItem"}}}}}},"201":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"created":{"type":"boolean"},"item":{"$ref":"#/components/schemas/ClientFollowupItem"}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientManualFollowup"}}}}}},"/plugins/follow-ups/queue/{id}":{"servers":[{"url":"/api","description":"Dashboard API. Session token, not an API key."}],"put":{"tags":["Follow-Ups"],"summary":"Update a queue item (message, prompt, or action)","security":[{"SessionAuth":[]}],"parameters":[{"$ref":"#/components/parameters/IntegerIdParam"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"customMessage":{"type":"string"},"customPrompt":{"type":"string"},"actionType":{"type":"string"}}}}}},"responses":{"200":{"description":"Updated"}},"description":"\n\nDashboard session only. This operation does not accept API keys; account or team permissions and feature availability apply."},"delete":{"tags":["Follow-Ups"],"summary":"Cancel a queue item","security":[{"SessionAuth":[]}],"parameters":[{"$ref":"#/components/parameters/IntegerIdParam"}],"responses":{"200":{"description":"Cancelled"}},"description":"\n\nDashboard session only. This operation does not accept API keys; account or team permissions and feature availability apply."},"get":{"tags":["Manual follow-ups"],"summary":"Read a follow-up task","description":"Requires current read access and current task visibility. Read this after an uncertain create or execution result before taking another action.","operationId":"client_get_plugins_follow_ups_queue_id","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"item":{"$ref":"#/components/schemas/ClientFollowupItem"}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Account-owned resource identifier."}]}},"/plugins/follow-ups/queue/{id}/preview":{"servers":[{"url":"/api","description":"Dashboard API. Session token, not an API key."}],"get":{"tags":["Follow-Ups"],"summary":"Preview the stored queue message and prompt","description":"Returns the reason for the follow-up and the stored messagePreview and promptPreview strings. This read does not generate a new AI message.\n\nDashboard session only. This operation does not accept API keys; account or team permissions and feature availability apply.","security":[{"SessionAuth":[]}],"parameters":[{"$ref":"#/components/parameters/IntegerIdParam"}],"responses":{"200":{"description":"Preview with reason, messagePreview, promptPreview","content":{"application/json":{"schema":{"type":"object","required":["success","item"],"properties":{"success":{"type":"boolean"},"item":{"type":"object","additionalProperties":true,"properties":{"reason":{"type":"string","nullable":true},"messagePreview":{"type":"string"},"promptPreview":{"type":"string"}}}}}}}}}}},"/plugins/follow-ups/contacts/{phone}":{"servers":[{"url":"/api","description":"Dashboard API. Session token, not an API key."}],"get":{"tags":["Follow-Ups"],"summary":"Get contact profile","security":[{"SessionAuth":[]}],"parameters":[{"name":"phone","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Profile with name, email, company, total_calls, sentiment, timezone, city"}},"description":"\n\nDashboard session only. This operation does not accept API keys; account or team permissions and feature availability apply."},"put":{"tags":["Caller profiles"],"summary":"Update an owned caller profile","description":"Supply at least one profile field; null clears a field. Optional profileId selects the owned profile. Legacy caller_name, caller_email, caller_company, caller_website, caller_address, whatsapp_phone and whatsapp_id aliases are accepted. Updates profile identity and linked profile views without rewriting a call transcript or sending a message.","operationId":"client_put_plugins_follow_ups_contacts_phone","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"profile":{"type":"object"}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"parameters":[{"name":"phone","in":"path","required":true,"schema":{"type":"string"},"description":"URL-encoded caller phone number."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","nullable":true,"maxLength":1000},"email":{"type":"string","nullable":true,"maxLength":1000},"company":{"type":"string","nullable":true,"maxLength":1000},"website":{"type":"string","nullable":true,"maxLength":1000},"address":{"type":"string","nullable":true,"maxLength":1000},"whatsappPhone":{"type":"string","nullable":true,"maxLength":1000},"whatsappId":{"type":"string","nullable":true,"maxLength":1000},"profileId":{"type":"integer","minimum":1}},"minProperties":1}}}}}},"/plugins/follow-ups/contacts/{phone}/timeline":{"servers":[{"url":"/api","description":"Dashboard API. Session token, not an API key."}],"get":{"tags":["Follow-Ups"],"summary":"Get contact timeline","description":"Returns calls, SMS, WhatsApp, appointments, follow-ups, and notes for this contact.\n\nDashboard session only. This operation does not accept API keys; account or team permissions and feature availability apply.","security":[{"SessionAuth":[]}],"parameters":[{"name":"phone","in":"path","required":true,"schema":{"type":"string"}},{"name":"type","in":"query","schema":{"type":"string","enum":["call","sms","appointment","follow_up","note"]}}],"responses":{"200":{"description":"Timeline items merged and sorted by date"}}}},"/appointments":{"get":{"tags":["Appointments"],"summary":"List appointments","description":"List appointments scoped to the API key's user. Supports filtering by status, date range, contact\nphone, and upcoming-only.","security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"query","name":"page","schema":{"type":"integer","default":1,"minimum":1}},{"in":"query","name":"pageSize","schema":{"type":"integer","default":50,"minimum":1,"maximum":200}},{"in":"query","name":"status","schema":{"type":"string","enum":["scheduled","confirmed","completed","cancelled","no_show"]}},{"in":"query","name":"from","description":"Start date (inclusive) in YYYY-MM-DD format.","schema":{"type":"string","example":"2026-04-25"}},{"in":"query","name":"to","description":"End date (inclusive) in YYYY-MM-DD format.","schema":{"type":"string","example":"2026-05-25"}},{"in":"query","name":"phone","description":"Filter by exact contact phone (E.164).","schema":{"type":"string","example":"+15145550142"}},{"in":"query","name":"upcoming","description":"When `true`, only returns appointments at or after the current time.","schema":{"type":"boolean","default":false}}],"responses":{"200":{"description":"Paged list of appointments","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/Appointment"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}},"x-required-scopes":["appointments:read"]},"post":{"tags":["Appointments"],"summary":"Create appointment","description":"Creates an appointment for a caller. Working-hours validation runs against the user's `appointment_settings`; a 409 is returned if the requested time is outside hours or already taken.\n\nFor `meeting_type=virtual` (default), a meeting room is auto-created when the agent or user has `auto_create_meeting_room=true`, OR when the caller passes `auto_create_meeting_room: true` in the request body. The response includes `meeting_link` and `meeting_passcode`.\n\nFor `meeting_type=in_person`, no meeting room is created; the response will have `meeting_link: null`.\n","security":[{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["contact_name","contact_phone","appointment_date","appointment_time"],"properties":{"contact_name":{"type":"string","example":"Jordan Taylor"},"contact_phone":{"type":"string","description":"E.164 format preferred.","example":"+15145550142"},"contact_email":{"type":"string","format":"email","example":"jordan.taylor@example.com"},"appointment_date":{"type":"string","description":"YYYY-MM-DD","example":"2026-04-30"},"appointment_time":{"type":"string","description":"HH:MM (24h)","example":"10:00"},"duration":{"type":"integer","description":"Minutes (5–480). Default 30.","example":30},"service_name":{"type":"string","example":"Will consultation"},"notes":{"type":"string","example":"Repeat client; bring photo ID + previous will."},"meeting_type":{"type":"string","enum":["virtual","in_person"],"default":"virtual"},"agent_id":{"type":"string","description":"(optional) link the appointment to one of your agents"},"auto_create_meeting_room":{"type":"boolean","description":"Override the agent/user default for room creation. Only applies when `meeting_type=virtual`."}}}}}},"responses":{"201":{"description":"Appointment created","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/Appointment"},"meta":{"$ref":"#/components/schemas/Meta"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"description":"Slot conflict or outside working hours","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"x-required-scopes":["appointments:write"]}},"/appointments/{id}":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"get":{"tags":["Appointments"],"summary":"Get one appointment","security":[{"ApiKeyAuth":[]}],"responses":{"200":{"description":"Appointment","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/Appointment"}}}}}},"404":{"$ref":"#/components/responses/NotFound"}},"x-required-scopes":["appointments:read"]},"patch":{"tags":["Appointments"],"summary":"Update appointment","description":"Reschedule, change status, edit notes, or change meeting type.","security":[{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"contact_name":{"type":"string"},"contact_phone":{"type":"string"},"contact_email":{"type":"string","format":"email"},"appointment_date":{"type":"string","example":"2026-05-02"},"appointment_time":{"type":"string","example":"14:30"},"duration":{"type":"integer"},"service_name":{"type":"string"},"notes":{"type":"string"},"status":{"type":"string","enum":["scheduled","confirmed","completed","cancelled","no_show"]},"meeting_type":{"type":"string","enum":["virtual","in_person"]}}}}}},"responses":{"200":{"description":"Updated appointment","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/Appointment"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"}},"x-required-scopes":["appointments:write"]},"delete":{"tags":["Appointments"],"summary":"Cancel appointment","description":"Marks status as `cancelled`; does not hard-delete the row.","security":[{"ApiKeyAuth":[]}],"responses":{"200":{"description":"Cancelled","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","example":"cancelled"}}}}}}}},"404":{"$ref":"#/components/responses/NotFound"}},"x-required-scopes":["appointments:write"]}},"/appointments/availability/check":{"get":{"tags":["Appointments"],"summary":"Check available slots for a date","description":"Returns the list of free slots (in `duration` minute increments) within the user's working hours\nfor the requested date, excluding any already-scheduled or confirmed appointments.","security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"query","name":"date","required":true,"schema":{"type":"string","example":"2026-04-30"}},{"in":"query","name":"duration","schema":{"type":"integer","default":30,"minimum":5,"maximum":480}}],"responses":{"200":{"description":"Availability","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"date":{"type":"string","example":"2026-04-30"},"working":{"type":"boolean","description":"false if the day is closed in working_hours"},"working_hours":{"type":"object","properties":{"start":{"type":"string","example":"09:00"},"end":{"type":"string","example":"17:00"}}},"duration":{"type":"integer","example":30},"slots":{"type":"array","items":{"type":"string","example":"10:00"}}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"}},"x-required-scopes":["appointments:read"]}},"/booking":{"get":{"tags":["Appointments"],"summary":"List appointments (alias of /appointments)","description":"Alias of `GET /appointments`. Identical behaviour, parameters and response. Use `/appointments`\nin new integrations.","deprecated":true,"security":[{"ApiKeyAuth":[]}],"responses":{"200":{"description":"Paged list of appointments","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/Appointment"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}},"x-required-scopes":["appointments:read"]},"post":{"tags":["Appointments"],"summary":"Create appointment (alias of /appointments)","description":"Alias of `POST /appointments`. Identical behaviour, request body and response. Use `/appointments`\nin new integrations.","deprecated":true,"security":[{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["contact_name","contact_phone","appointment_date","appointment_time"],"properties":{"contact_name":{"type":"string"},"contact_phone":{"type":"string"},"contact_email":{"type":"string","format":"email"},"appointment_date":{"type":"string"},"appointment_time":{"type":"string"},"duration":{"type":"integer"},"service_name":{"type":"string"},"notes":{"type":"string"},"meeting_type":{"type":"string","enum":["virtual","in_person"]},"agent_id":{"type":"string"},"auto_create_meeting_room":{"type":"boolean"}}}}}},"responses":{"201":{"description":"Appointment created","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/Appointment"},"meta":{"$ref":"#/components/schemas/Meta"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"}},"x-required-scopes":["appointments:write"]}},"/booking/{id}":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"get":{"tags":["Appointments"],"summary":"Get one appointment (alias of /appointments/{id})","description":"Alias of `GET /appointments/{id}`.","deprecated":true,"security":[{"ApiKeyAuth":[]}],"responses":{"200":{"description":"Appointment","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/Appointment"}}}}}},"404":{"$ref":"#/components/responses/NotFound"}},"x-required-scopes":["appointments:read"]},"patch":{"tags":["Appointments"],"summary":"Update appointment (alias of /appointments/{id})","description":"Alias of `PATCH /appointments/{id}`.","deprecated":true,"security":[{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"appointment_date":{"type":"string"},"appointment_time":{"type":"string"},"status":{"type":"string","enum":["scheduled","confirmed","completed","cancelled","no_show"]}}}}}},"responses":{"200":{"description":"Updated appointment","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/Appointment"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"}},"x-required-scopes":["appointments:write"]},"delete":{"tags":["Appointments"],"summary":"Cancel appointment (alias of /appointments/{id})","description":"Alias of `DELETE /appointments/{id}`. Marks status as `cancelled`; does not hard-delete the row.","deprecated":true,"security":[{"ApiKeyAuth":[]}],"responses":{"200":{"description":"Cancelled","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","example":"cancelled"}}}}}}}},"404":{"$ref":"#/components/responses/NotFound"}},"x-required-scopes":["appointments:write"]}},"/booking/availability/check":{"get":{"tags":["Appointments"],"summary":"Check available slots (alias of /appointments/availability/check)","description":"Alias of `GET /appointments/availability/check`.","deprecated":true,"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"query","name":"date","required":true,"schema":{"type":"string","example":"2026-04-30"}},{"in":"query","name":"duration","schema":{"type":"integer","default":30,"minimum":5,"maximum":480}}],"responses":{"200":{"description":"Availability","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"date":{"type":"string"},"working":{"type":"boolean"},"duration":{"type":"integer"},"slots":{"type":"array","items":{"type":"string"}}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"}},"x-required-scopes":["appointments:read"]}},"/":{"servers":[{"url":"/api/v1"}],"get":{"tags":["System"],"summary":"Discover the API","operationId":"get","description":"Public directory of the v1 resources and documentation URL.","security":[],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"name":{"type":"string"},"version":{"type":"string"},"documentation":{"type":"string"},"playground":{"type":"string"},"openapi":{"type":"string"},"endpoints":{"type":"object"},"aliases":{"type":"object"},"authentication":{"type":"object"}}}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"oneOf":[{"type":"string"},{"type":"object"}]}}}}}},"401":{"description":"Missing, invalid or expired credentials","content":{"application/json":{"schema":{"type":"object"}}}},"403":{"description":"Missing scope, ownership or entitlement","content":{"application/json":{"schema":{"type":"object"}}}},"500":{"description":"Request could not be completed","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/credits/calls":{"servers":[{"url":"/api/v1"}],"get":{"tags":["Credits"],"summary":"Read call totals for a recent period","operationId":"get__credits_calls","description":"Summarizes calls for this account over the requested number of days. Use a positive integer for\ndays. Duration totals are rounded to minutes; averages are seconds.","security":[{"ApiKeyAuth":[]},{"BearerAuth":[]}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"totalCalls":{"type":"integer"},"completedCalls":{"type":"integer"},"failedCalls":{"type":"integer"},"totalDurationMinutes":{"type":"number"},"averageDurationSeconds":{"type":"number"},"creditsUsed":{"type":"number"},"period":{"type":"object","properties":{"start":{"type":"string"},"end":{"type":"string"}}}}},"meta":{"type":"object"}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"oneOf":[{"type":"string"},{"type":"object"}]}}}}}},"401":{"description":"Missing, invalid or expired credentials","content":{"application/json":{"schema":{"type":"object"}}}},"403":{"description":"Missing scope, ownership or entitlement","content":{"application/json":{"schema":{"type":"object"}}}},"500":{"description":"Request could not be completed","content":{"application/json":{"schema":{"type":"object"}}}}},"x-required-scopes":["analytics:read"],"parameters":[{"name":"days","in":"query","required":false,"description":"Lookback in days","schema":{"type":"integer","default":30,"minimum":1}}]}},"/credits/campaigns":{"servers":[{"url":"/api/v1"}],"get":{"tags":["Credits"],"summary":"Read campaign progress estimates","operationId":"get__credits_campaigns","description":"Lists campaign contact counts. `connected` currently mirrors the called count and `failed` is\na placeholder zero; these are progress estimates, not verified connection or failure outcomes. Use call\nrecords for actual outcomes.","security":[{"ApiKeyAuth":[]},{"BearerAuth":[]}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"type":"object","properties":{"campaignId":{"type":"string"},"name":{"type":"string"},"status":{"type":"string"},"totalContacts":{"type":"integer"},"called":{"type":"integer"},"connected":{"type":"integer"},"completed":{"type":"integer"},"failed":{"type":"integer"},"pending":{"type":"integer"},"successRate":{"type":"number"}}}},"meta":{"type":"object"}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"oneOf":[{"type":"string"},{"type":"object"}]}}}}}},"401":{"description":"Missing, invalid or expired credentials","content":{"application/json":{"schema":{"type":"object"}}}},"403":{"description":"Missing scope, ownership or entitlement","content":{"application/json":{"schema":{"type":"object"}}}},"500":{"description":"Request could not be completed","content":{"application/json":{"schema":{"type":"object"}}}}},"x-required-scopes":["analytics:read"],"parameters":[{"name":"page","in":"query","required":false,"description":"Page number","schema":{"type":"integer","default":1}},{"name":"pageSize","in":"query","required":false,"description":"Maximum 100","schema":{"type":"integer","default":50,"maximum":100}}]}},"/api/plugins/crm-bridge/credits":{"servers":[{"url":"/","description":"Account integration API"}],"get":{"tags":["ALMA CRM"],"summary":"Read connected CRM credit balance","operationId":"get__api_plugins_crm_bridge_credits","description":"","security":[{"ApiKeyAuth":[]},{"BearerAuth":[]}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"balance":{"type":"number"},"reserved":{"type":"number"},"total":{"type":"number"},"currency":{"type":"string"},"top_up_url":{"type":"string"}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"oneOf":[{"type":"string"},{"type":"object"}]}}}}}},"401":{"description":"Missing, invalid or expired credentials","content":{"application/json":{"schema":{"type":"object"}}}},"403":{"description":"Missing scope, ownership or entitlement","content":{"application/json":{"schema":{"type":"object"}}}},"500":{"description":"Request could not be completed","content":{"application/json":{"schema":{"type":"object"}}}}},"x-required-scopes":["credits:read"]}},"/api/plugins/crm-bridge/messaging-stats":{"servers":[{"url":"/","description":"Account integration API"}],"get":{"tags":["ALMA CRM"],"summary":"Read sent-message counts","operationId":"get__api_plugins_crm_bridge_messaging_stats","description":"Counts records marked sent for email, SMS and WhatsApp. These counts are not delivery or engagement\nconfirmation.","security":[{"ApiKeyAuth":[]},{"BearerAuth":[]}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"emails":{"type":"integer"},"sms":{"type":"integer"},"whatsapp":{"type":"integer"},"from":{"type":"string","nullable":true},"to":{"type":"string","nullable":true}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"oneOf":[{"type":"string"},{"type":"object"}]}}}}}},"401":{"description":"Missing, invalid or expired credentials","content":{"application/json":{"schema":{"type":"object"}}}},"403":{"description":"Missing scope, ownership or entitlement","content":{"application/json":{"schema":{"type":"object"}}}},"500":{"description":"Request could not be completed","content":{"application/json":{"schema":{"type":"object"}}}}},"x-required-scopes":["analytics:read"],"parameters":[{"name":"from","in":"query","required":false,"description":"Optional ISO timestamp","schema":{"type":"string"}},{"name":"to","in":"query","required":false,"description":"Optional ISO timestamp","schema":{"type":"string"}}]}},"/api/plugins/crm-bridge/sms/send":{"servers":[{"url":"/","description":"Account integration API"}],"post":{"tags":["ALMA CRM"],"summary":"Send an SMS","operationId":"post__api_plugins_crm_bridge_sms_send","description":"Sends a real message and may consume account credits. An active texting-capable owned sender\nis required. If `from` is omitted the account sender is chosen. A returned sent status confirms submission,\nnot handset delivery.","security":[{"ApiKeyAuth":[]},{"BearerAuth":[]}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message_id":{"type":"string"},"status":{"type":"string"}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"oneOf":[{"type":"string"},{"type":"object"}]}}}}}},"401":{"description":"Missing, invalid or expired credentials","content":{"application/json":{"schema":{"type":"object"}}}},"403":{"description":"Missing scope, ownership or entitlement","content":{"application/json":{"schema":{"type":"object"}}}},"500":{"description":"Request could not be completed","content":{"application/json":{"schema":{"type":"object"}}}}},"x-required-scopes":["sms:write"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"to":{"type":"string"},"body":{"type":"string"},"from":{"type":"string"}},"required":["to","body"]}}}}}},"/api/plugins/crm-bridge/numbers/search":{"servers":[{"url":"/","description":"Account integration API"}],"get":{"tags":["ALMA CRM"],"summary":"Search available account phone numbers","operationId":"get__api_plugins_crm_bridge_numbers_search","description":"Search only; this does not buy a number. Accepted aliases: area_code, postal_code, pattern for\ncontains, and type for numberType. Availability and pricing can change.","security":[{"ApiKeyAuth":[]},{"BearerAuth":[]}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","description":"Account number-search response, including available numbers and applicable purchase\ndetails."}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"oneOf":[{"type":"string"},{"type":"object"}]}}}}}},"401":{"description":"Missing, invalid or expired credentials","content":{"application/json":{"schema":{"type":"object"}}}},"403":{"description":"Missing scope, ownership or entitlement","content":{"application/json":{"schema":{"type":"object"}}}},"500":{"description":"Request could not be completed","content":{"application/json":{"schema":{"type":"object"}}}}},"x-required-scopes":["phone-numbers:read"],"parameters":[{"name":"country","in":"query","required":true,"description":"ISO country code, for example CA","schema":{"type":"string"}},{"name":"areaCode","in":"query","required":false,"description":"","schema":{"type":"string"}},{"name":"region","in":"query","required":false,"description":"","schema":{"type":"string"}},{"name":"postalCode","in":"query","required":false,"description":"","schema":{"type":"string"}},{"name":"locality","in":"query","required":false,"description":"","schema":{"type":"string"}},{"name":"contains","in":"query","required":false,"description":"","schema":{"type":"string"}},{"name":"numberType","in":"query","required":false,"description":"","schema":{"type":"string"}}]}},"/api/plugins/crm-bridge/numbers/buy":{"servers":[{"url":"/","description":"Account integration API"}],"post":{"tags":["ALMA CRM"],"summary":"Purchase a phone number","operationId":"post__api_plugins_crm_bridge_numbers_buy","description":"Purchases a number for the account and can incur charges. Number availability, account eligibility\nand billing checks apply. Accepts `phoneNumber` as an alias of `number` and `type` as an alias of `numberType`.\nThis operation has no documented idempotency key; reconcile the number inventory before retrying after a\ntimeout.","security":[{"ApiKeyAuth":[]},{"BearerAuth":[]}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","description":"Account number-purchase response; failures retain the account service status and response."}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"oneOf":[{"type":"string"},{"type":"object"}]}}}}}},"401":{"description":"Missing, invalid or expired credentials","content":{"application/json":{"schema":{"type":"object"}}}},"403":{"description":"Missing scope, ownership or entitlement","content":{"application/json":{"schema":{"type":"object"}}}},"500":{"description":"Request could not be completed","content":{"application/json":{"schema":{"type":"object"}}}}},"x-required-scopes":["phone-numbers:write"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"number":{"type":"string"},"country":{"type":"string"},"numberType":{"type":"string"}},"required":["number","country"]}}}}}},"/api/plugins/crm-bridge/numbers":{"servers":[{"url":"/","description":"Account integration API"}],"get":{"tags":["ALMA CRM"],"summary":"List account phone numbers","operationId":"get__api_plugins_crm_bridge_numbers","description":"","security":[{"ApiKeyAuth":[]},{"BearerAuth":[]}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","description":"Account number inventory response. Only numbers belonging to this account are returned."}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"oneOf":[{"type":"string"},{"type":"object"}]}}}}}},"401":{"description":"Missing, invalid or expired credentials","content":{"application/json":{"schema":{"type":"object"}}}},"403":{"description":"Missing scope, ownership or entitlement","content":{"application/json":{"schema":{"type":"object"}}}},"500":{"description":"Request could not be completed","content":{"application/json":{"schema":{"type":"object"}}}}},"x-required-scopes":["phone-numbers:read"]}},"/api/plugins/crm-bridge/contacts":{"servers":[{"url":"/","description":"Account integration API"}],"get":{"tags":["ALMA CRM"],"summary":"Export contacts with a stable cursor","operationId":"get__api_plugins_crm_bridge_contacts","description":"Ordered by creation time and id. Reuse the opaque next_cursor while has_more is true. This cursor\nis for this export endpoint and is not interchangeable with sync cursors.","security":[{"ApiKeyAuth":[]},{"BearerAuth":[]}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"contacts":{"type":"array","items":{"$ref":"#/components/schemas/Contact"}},"next_cursor":{"type":"string","nullable":true},"has_more":{"type":"boolean"},"limit":{"type":"integer"}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"oneOf":[{"type":"string"},{"type":"object"}]}}}}}},"401":{"description":"Missing, invalid or expired credentials","content":{"application/json":{"schema":{"type":"object"}}}},"403":{"description":"Missing scope, ownership or entitlement","content":{"application/json":{"schema":{"type":"object"}}}},"500":{"description":"Request could not be completed","content":{"application/json":{"schema":{"type":"object"}}}}},"x-required-scopes":["contacts:read"],"parameters":[{"name":"cursor","in":"query","required":false,"description":"Opaque cursor from the preceding page","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Page size","schema":{"type":"integer","default":100,"maximum":500}}]}},"/api/plugins/crm-bridge/webhook-config":{"servers":[{"url":"/","description":"Account integration API"}],"put":{"tags":["ALMA CRM"],"summary":"Configure connected CRM webhooks","operationId":"put__api_plugins_crm_bridge_webhook_config","description":"Sets the HTTPS delivery destination. An empty crm_webhook_url disables it. A secret is generated\nif absent; regenerate_secret rotates it. Save the returned secret securely. Events: sms.inbound and call.completed.\nSignature: X-Alma-Signature with sha256= followed by the raw-body HMAC-SHA256 hex digest.","security":[{"ApiKeyAuth":[]},{"BearerAuth":[]}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"crm_webhook_url":{"type":"string","nullable":true},"signing_secret":{"type":"string"},"events":{"type":"array","items":{"type":"string"}},"signature_header":{"type":"string"}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"oneOf":[{"type":"string"},{"type":"object"}]}}}}}},"401":{"description":"Missing, invalid or expired credentials","content":{"application/json":{"schema":{"type":"object"}}}},"403":{"description":"Missing scope, ownership or entitlement","content":{"application/json":{"schema":{"type":"object"}}}},"500":{"description":"Request could not be completed","content":{"application/json":{"schema":{"type":"object"}}}}},"x-required-scopes":["calls:read"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"crm_webhook_url":{"type":"string"},"regenerate_secret":{"type":"boolean"}}}}}}}},"/api/plugins/crm-bridge/embed-token":{"servers":[{"url":"/","description":"Account integration API"}],"post":{"tags":["ALMA CRM"],"summary":"Create a connected webphone embed token","operationId":"post__api_plugins_crm_bridge_embed_token","description":"For the supported ALMA CRM webphone integration. Issues a single-use token valid for 900 seconds.\nTreat the token and returned URL as credentials: do not log or share them. Exchanging it creates an account\nuser session; do not treat it as a call-read-only token.","security":[{"ApiKeyAuth":[]},{"BearerAuth":[]}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"token":{"type":"string"},"url":{"type":"string"},"expires_in":{"type":"integer"}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"oneOf":[{"type":"string"},{"type":"object"}]}}}}}},"401":{"description":"Missing, invalid or expired credentials","content":{"application/json":{"schema":{"type":"object"}}}},"403":{"description":"Missing scope, ownership or entitlement","content":{"application/json":{"schema":{"type":"object"}}}},"500":{"description":"Request could not be completed","content":{"application/json":{"schema":{"type":"object"}}}}},"x-required-scopes":["calls:read"]}},"/api/plugins/crm-bridge/embed-session":{"servers":[{"url":"/","description":"Account integration API"}],"post":{"tags":["ALMA CRM"],"summary":"Exchange a single-use webphone embed credential","operationId":"post__api_plugins_crm_bridge_embed_session","description":"Used by the supported ALMA CRM webphone. Send the token as JSON embt; the legacy query parameter\nis also accepted. Rejects an expired, wrong-audience or replayed token. Returns a 900-second account access\ntoken and sets a refresh cookie. This creates a user session, not a scope-limited API key. Keep the session\nprivate.","security":[{"EmbedToken":[]}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"token":{"type":"string"},"expiresIn":{"type":"integer"}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"oneOf":[{"type":"string"},{"type":"object"}]}}}}}},"401":{"description":"Missing, invalid or expired credentials","content":{"application/json":{"schema":{"type":"object"}}}},"403":{"description":"Missing scope, ownership or entitlement","content":{"application/json":{"schema":{"type":"object"}}}},"500":{"description":"Request could not be completed","content":{"application/json":{"schema":{"type":"object"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"embt":{"type":"string"}},"required":["embt"]}}}}}},"/api/plugins/crm-bridge/email/send":{"servers":[{"url":"/","description":"Account integration API"}],"post":{"tags":["ALMA CRM"],"summary":"Send an email","operationId":"post__api_plugins_crm_bridge_email_send","description":"Sends a real email using the account integration. A success/messageId confirms submission, not\ninbox delivery.","security":[{"ApiKeyAuth":[]},{"BearerAuth":[]}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"messageId":{"type":"string","nullable":true}}}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"oneOf":[{"type":"string"},{"type":"object"}]}}}}}},"401":{"description":"Missing, invalid or expired credentials","content":{"application/json":{"schema":{"type":"object"}}}},"403":{"description":"Missing scope, ownership or entitlement","content":{"application/json":{"schema":{"type":"object"}}}},"500":{"description":"Request could not be completed","content":{"application/json":{"schema":{"type":"object"}}}}},"x-required-scopes":["email:send"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"to":{"type":"string"},"subject":{"type":"string"},"body_html":{"type":"string"},"reply_to":{"type":"string"}},"required":["to","subject","body_html"]}}}}}},"/api/plugins/crm-bridge/meetings/create":{"servers":[{"url":"/","description":"Account integration API"}],"post":{"tags":["ALMA CRM"],"summary":"Create a meeting link","operationId":"post__api_plugins_crm_bridge_meetings_create","description":"Creates a meeting room. If auto_send_link is true and contact_email is provided, it also sends\nan email invitation. Leave auto_send_link false when only a link is required. Account meeting and email\nconfiguration must be available.","security":[{"ApiKeyAuth":[]},{"BearerAuth":[]}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"meeting_id":{"type":"string"},"meeting_url":{"type":"string"},"passcode":{"type":"string"},"emailed":{"type":"boolean"}}}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"oneOf":[{"type":"string"},{"type":"object"}]}}}}}},"401":{"description":"Missing, invalid or expired credentials","content":{"application/json":{"schema":{"type":"object"}}}},"403":{"description":"Missing scope, ownership or entitlement","content":{"application/json":{"schema":{"type":"object"}}}},"500":{"description":"Request could not be completed","content":{"application/json":{"schema":{"type":"object"}}}}},"x-required-scopes":["meetings:create"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"display_name":{"type":"string","maxLength":120,"default":"Meeting"},"auto_send_link":{"type":"boolean","default":false},"contact_email":{"type":"string"}}}}}}}},"/api/plugins/crm-bridge/contacts/call-summary":{"servers":[{"url":"/","description":"Account integration API"}],"get":{"tags":["ALMA CRM"],"summary":"Read a contact call summary","operationId":"get__api_plugins_crm_bridge_contacts_call_summary","description":"Matches a contact phone against the account call history. Returns the latest 100 combined call\nrecords. Aggregate values are calculated from the bounded source samples, not guaranteed lifetime totals.","security":[{"ApiKeyAuth":[]},{"BearerAuth":[]}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"contact":{"type":"object","properties":{"phone":{"type":"string"}}},"days":{"type":"integer"},"aggregate":{"type":"object","properties":{"total_calls":{"type":"integer"},"connected":{"type":"integer"},"missed":{"type":"integer"}}},"calls":{"type":"array","items":{"type":"object"}}}}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"oneOf":[{"type":"string"},{"type":"object"}]}}}}}},"401":{"description":"Missing, invalid or expired credentials","content":{"application/json":{"schema":{"type":"object"}}}},"403":{"description":"Missing scope, ownership or entitlement","content":{"application/json":{"schema":{"type":"object"}}}},"500":{"description":"Request could not be completed","content":{"application/json":{"schema":{"type":"object"}}}}},"x-required-scopes":["calls:read"],"parameters":[{"name":"contact_phone","in":"query","required":true,"description":"Contact phone number","schema":{"type":"string"}},{"name":"days","in":"query","required":false,"description":"Lookback in days","schema":{"type":"integer","default":90,"minimum":1,"maximum":365}}]}},"/api/plugins/crm-bridge/calls/day-report":{"servers":[{"url":"/","description":"Account integration API"}],"get":{"tags":["ALMA CRM"],"summary":"Read daily account call totals","operationId":"get__api_plugins_crm_bridge_calls_day_report","description":"Uses America/Toronto calendar dates, defaulting to today. from/to specify an inclusive range;\ndate specifies one day. Reports account credits and customer-facing engine labels.","security":[{"ApiKeyAuth":[]},{"BearerAuth":[]}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"total_calls":{"type":"integer"},"connected":{"type":"integer"},"missed":{"type":"integer"},"sentiment":{"type":"object"},"total_credits":{"type":"number"},"avg_credits_per_call":{"type":"number"},"avg_duration_sec":{"type":"number"},"by_engine":{"type":"object"},"period":{"type":"string"}}}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"oneOf":[{"type":"string"},{"type":"object"}]}}}}}},"401":{"description":"Missing, invalid or expired credentials","content":{"application/json":{"schema":{"type":"object"}}}},"403":{"description":"Missing scope, ownership or entitlement","content":{"application/json":{"schema":{"type":"object"}}}},"500":{"description":"Request could not be completed","content":{"application/json":{"schema":{"type":"object"}}}}},"x-required-scopes":["calls:read"],"parameters":[{"name":"date","in":"query","required":false,"description":"YYYY-MM-DD","schema":{"type":"string","format":"date"}},{"name":"from","in":"query","required":false,"description":"YYYY-MM-DD","schema":{"type":"string","format":"date"}},{"name":"to","in":"query","required":false,"description":"YYYY-MM-DD","schema":{"type":"string","format":"date"}}]}},"/api/plugins/crm-bridge/sync/contacts":{"servers":[{"url":"/","description":"Account integration API"}],"get":{"tags":["ALMA CRM"],"summary":"Synchronize contacts","operationId":"get__api_plugins_crm_bridge_sync_contacts","description":"Stable cursor export. since must be an ISO timestamp with an explicit timezone. Reuse next_cursor\nunchanged. Calls apply a 24-hour lookback for updates; deduplicate by id. Messages include a stable dedupeKey.\nStart a new incremental pass without a cursor after finishing the current pass.","security":[{"ApiKeyAuth":[]},{"BearerAuth":[]}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Contact"}},"next_cursor":{"type":"string","nullable":true},"has_more":{"type":"boolean"}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"oneOf":[{"type":"string"},{"type":"object"}]}}}}}},"401":{"description":"Missing, invalid or expired credentials","content":{"application/json":{"schema":{"type":"object"}}}},"403":{"description":"Missing scope, ownership or entitlement","content":{"application/json":{"schema":{"type":"object"}}}},"500":{"description":"Request could not be completed","content":{"application/json":{"schema":{"type":"object"}}}}},"x-required-scopes":["contacts:read"],"parameters":[{"name":"cursor","in":"query","required":false,"description":"Opaque cursor from this resource","schema":{"type":"string"}},{"name":"since","in":"query","required":false,"description":"Incremental start timestamp","schema":{"type":"string","format":"date-time"}},{"name":"limit","in":"query","required":false,"description":"Page size","schema":{"type":"integer","default":100,"maximum":100}}]},"post":{"tags":["ALMA CRM"],"summary":"Create a contact with a stable external id","operationId":"post__api_plugins_crm_bridge_sync_contacts","description":"Use a stable UUID (versions 1 through 5) as externalId and a nonempty phone in fields. A replay\nof that externalId for the same account returns the existing contact with created false (200); a new contact\nreturns created true (201). Keep the externalId unchanged when safely retrying this operation.","security":[{"ApiKeyAuth":[]},{"BearerAuth":[]}],"responses":{"200":{"description":"Existing contact for this externalId","content":{"application/json":{"schema":{"type":"object","properties":{"created":{"type":"boolean"},"contact":{"$ref":"#/components/schemas/Contact"}}}}}},"201":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"created":{"type":"boolean"},"contact":{"$ref":"#/components/schemas/Contact"}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"oneOf":[{"type":"string"},{"type":"object"}]}}}}}},"401":{"description":"Missing, invalid or expired credentials","content":{"application/json":{"schema":{"type":"object"}}}},"403":{"description":"Missing scope, ownership or entitlement","content":{"application/json":{"schema":{"type":"object"}}}},"500":{"description":"Request could not be completed","content":{"application/json":{"schema":{"type":"object"}}}}},"x-required-scopes":["contacts:write"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"externalId":{"type":"string","format":"uuid"},"fields":{"type":"object","properties":{"name":{"type":"string","nullable":true},"firstName":{"type":"string","nullable":true},"lastName":{"type":"string","nullable":true},"email":{"type":"string","nullable":true},"phone":{"type":"string","nullable":true},"company":{"type":"string","nullable":true},"stage":{"type":"string","nullable":true}},"required":["phone"]}},"required":["externalId","fields"]}}}}}},"/api/plugins/crm-bridge/sync/calls":{"servers":[{"url":"/","description":"Account integration API"}],"get":{"tags":["ALMA CRM"],"summary":"Synchronize calls","operationId":"get__api_plugins_crm_bridge_sync_calls","description":"Stable cursor export. since must be an ISO timestamp with an explicit timezone. Reuse next_cursor\nunchanged. Calls apply a 24-hour lookback for updates; deduplicate by id. Messages include a stable dedupeKey.\nStart a new incremental pass without a cursor after finishing the current pass.","security":[{"ApiKeyAuth":[]},{"BearerAuth":[]}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object"}},"next_cursor":{"type":"string","nullable":true},"has_more":{"type":"boolean"}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"oneOf":[{"type":"string"},{"type":"object"}]}}}}}},"401":{"description":"Missing, invalid or expired credentials","content":{"application/json":{"schema":{"type":"object"}}}},"403":{"description":"Missing scope, ownership or entitlement","content":{"application/json":{"schema":{"type":"object"}}}},"500":{"description":"Request could not be completed","content":{"application/json":{"schema":{"type":"object"}}}}},"x-required-scopes":["calls:read"],"parameters":[{"name":"cursor","in":"query","required":false,"description":"Opaque cursor from this resource","schema":{"type":"string"}},{"name":"since","in":"query","required":false,"description":"Incremental start timestamp","schema":{"type":"string","format":"date-time"}},{"name":"limit","in":"query","required":false,"description":"Page size","schema":{"type":"integer","default":100,"maximum":100}}]}},"/api/plugins/crm-bridge/sync/messages":{"servers":[{"url":"/","description":"Account integration API"}],"get":{"tags":["ALMA CRM"],"summary":"Synchronize messages","operationId":"get__api_plugins_crm_bridge_sync_messages","description":"Stable cursor export. since must be an ISO timestamp with an explicit timezone. Reuse next_cursor\nunchanged. Calls apply a 24-hour lookback for updates; deduplicate by id. Messages include a stable dedupeKey.\nStart a new incremental pass without a cursor after finishing the current pass.","security":[{"ApiKeyAuth":[]},{"BearerAuth":[]}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object"}},"next_cursor":{"type":"string","nullable":true},"has_more":{"type":"boolean"}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"oneOf":[{"type":"string"},{"type":"object"}]}}}}}},"401":{"description":"Missing, invalid or expired credentials","content":{"application/json":{"schema":{"type":"object"}}}},"403":{"description":"Missing scope, ownership or entitlement","content":{"application/json":{"schema":{"type":"object"}}}},"500":{"description":"Request could not be completed","content":{"application/json":{"schema":{"type":"object"}}}}},"x-required-scopes":["messages:read"],"parameters":[{"name":"cursor","in":"query","required":false,"description":"Opaque cursor from this resource","schema":{"type":"string"}},{"name":"since","in":"query","required":false,"description":"Incremental start timestamp","schema":{"type":"string","format":"date-time"}},{"name":"limit","in":"query","required":false,"description":"Page size","schema":{"type":"integer","default":100,"maximum":100}}]}},"/api/plugins/crm-bridge/sync/contacts/{id}":{"servers":[{"url":"/","description":"Account integration API"}],"get":{"tags":["ALMA CRM"],"summary":"Read a synchronized contact","operationId":"get__api_plugins_crm_bridge_sync_contacts__id","description":"","security":[{"ApiKeyAuth":[]},{"BearerAuth":[]}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"contact":{"$ref":"#/components/schemas/Contact"}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"oneOf":[{"type":"string"},{"type":"object"}]}}}}}},"401":{"description":"Missing, invalid or expired credentials","content":{"application/json":{"schema":{"type":"object"}}}},"403":{"description":"Missing scope, ownership or entitlement","content":{"application/json":{"schema":{"type":"object"}}}},"500":{"description":"Request could not be completed","content":{"application/json":{"schema":{"type":"object"}}}}},"x-required-scopes":["contacts:read"],"parameters":[{"name":"id","in":"path","required":true,"description":"Contact id","schema":{"type":"string"}}]},"patch":{"tags":["ALMA CRM"],"summary":"Update a contact with conflict protection","operationId":"patch__api_plugins_crm_bridge_sync_contacts__id","description":"Send the exact updatedAt from the latest read as expectedUpdatedAt. At least one supported change\nis required. Phone cannot be cleared. A 409 conflict returns the current contact; read it and reconcile\nbefore retrying. name is split into firstName/lastName only when those fields are absent.","security":[{"ApiKeyAuth":[]},{"BearerAuth":[]}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"contact":{"$ref":"#/components/schemas/Contact"}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"oneOf":[{"type":"string"},{"type":"object"}]}}}}}},"401":{"description":"Missing, invalid or expired credentials","content":{"application/json":{"schema":{"type":"object"}}}},"403":{"description":"Missing scope, ownership or entitlement","content":{"application/json":{"schema":{"type":"object"}}}},"409":{"description":"Contact changed since expectedUpdatedAt","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"contact":{"$ref":"#/components/schemas/Contact"}}}}}},"500":{"description":"Request could not be completed","content":{"application/json":{"schema":{"type":"object"}}}}},"x-required-scopes":["contacts:write"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"expectedUpdatedAt":{"type":"string","format":"date-time"},"changes":{"type":"object","properties":{"name":{"type":"string","nullable":true},"firstName":{"type":"string","nullable":true},"lastName":{"type":"string","nullable":true},"email":{"type":"string","nullable":true},"phone":{"type":"string","nullable":true},"company":{"type":"string","nullable":true},"stage":{"type":"string","nullable":true}}}},"required":["expectedUpdatedAt","changes"]}}}},"parameters":[{"name":"id","in":"path","required":true,"description":"Contact id","schema":{"type":"string"}}]}},"/api/user/api-keys":{"servers":[{"url":"/","description":"Account integration API"}],"get":{"tags":["Account API keys"],"summary":"List account API keys","operationId":"get__api_user_api_keys","description":"","security":[{"OwnerSession":[]}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"type":"object","description":"Key metadata only; never the complete secret."}},"meta":{"type":"object"}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"oneOf":[{"type":"string"},{"type":"object"}]}}}}}},"401":{"description":"Missing, invalid or expired credentials","content":{"application/json":{"schema":{"type":"object"}}}},"403":{"description":"Missing scope, ownership or entitlement","content":{"application/json":{"schema":{"type":"object"}}}},"500":{"description":"Request could not be completed","content":{"application/json":{"schema":{"type":"object"}}}}},"parameters":[{"name":"page","in":"query","required":false,"description":"Page number","schema":{"type":"integer","default":1}},{"name":"pageSize","in":"query","required":false,"description":"Maximum 100","schema":{"type":"integer","default":50,"maximum":100}}]},"post":{"tags":["Account API keys"],"summary":"Create an account API key","operationId":"post__api_user_api_keys","description":"The full key appears once in data.key. Omitted scopes use calls:read, calls:write, campaigns:read\nand contacts:read. Explicit scopes must be supported and cannot include admin. IP entries must be valid\nIP addresses; an empty list accepts any source address.","security":[{"OwnerSession":[]}],"responses":{"201":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object"},"meta":{"type":"object"}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"oneOf":[{"type":"string"},{"type":"object"}]}}}}}},"401":{"description":"Missing, invalid or expired credentials","content":{"application/json":{"schema":{"type":"object"}}}},"403":{"description":"Missing scope, ownership or entitlement","content":{"application/json":{"schema":{"type":"object"}}}},"500":{"description":"Request could not be completed","content":{"application/json":{"schema":{"type":"object"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100},"scopes":{"type":"array","items":{"type":"string"}},"rateLimit":{"type":"integer","minimum":10,"maximum":10000,"default":100},"ipWhitelist":{"type":"array","items":{"type":"string"}},"description":{"type":"string","maxLength":500},"expiresAt":{"type":"string","format":"date-time"}},"required":["name"]}}}}}},"/api/user/api-keys/{id}":{"servers":[{"url":"/","description":"Account integration API"}],"put":{"tags":["Account API keys"],"summary":"Update account API key settings","operationId":"put__api_user_api_keys__id","description":"Updates key metadata, scopes, activity and request ceiling. The secret and expiry are not changed\nby this operation.","security":[{"OwnerSession":[]}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object"},"meta":{"type":"object"}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"oneOf":[{"type":"string"},{"type":"object"}]}}}}}},"401":{"description":"Missing, invalid or expired credentials","content":{"application/json":{"schema":{"type":"object"}}}},"403":{"description":"Missing scope, ownership or entitlement","content":{"application/json":{"schema":{"type":"object"}}}},"500":{"description":"Request could not be completed","content":{"application/json":{"schema":{"type":"object"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100},"scopes":{"type":"array","items":{"type":"string"}},"rateLimit":{"type":"integer","minimum":10,"maximum":10000,"default":100},"ipWhitelist":{"type":"array","items":{"type":"string"}},"description":{"type":"string","maxLength":500},"isActive":{"type":"boolean"}}}}}},"parameters":[{"name":"id","in":"path","required":true,"description":"Key id","schema":{"type":"string"}}]},"delete":{"tags":["Account API keys"],"summary":"Delete an account API key","operationId":"delete__api_user_api_keys__id","description":"Revokes the key immediately.","security":[{"OwnerSession":[]}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"deleted":{"type":"boolean"}}}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"oneOf":[{"type":"string"},{"type":"object"}]}}}}}},"401":{"description":"Missing, invalid or expired credentials","content":{"application/json":{"schema":{"type":"object"}}}},"403":{"description":"Missing scope, ownership or entitlement","content":{"application/json":{"schema":{"type":"object"}}}},"500":{"description":"Request could not be completed","content":{"application/json":{"schema":{"type":"object"}}}}},"parameters":[{"name":"id","in":"path","required":true,"description":"Key id","schema":{"type":"string"}}]}},"/api/user/api-keys/{id}/regenerate":{"servers":[{"url":"/","description":"Account integration API"}],"post":{"tags":["Account API keys"],"summary":"Regenerate an account API key","operationId":"post__api_user_api_keys__id__regenerate","description":"Invalidates the old secret immediately. Save data.key from this response and update the integration\nsecurely.","security":[{"OwnerSession":[]}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object"},"meta":{"type":"object"}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"oneOf":[{"type":"string"},{"type":"object"}]}}}}}},"401":{"description":"Missing, invalid or expired credentials","content":{"application/json":{"schema":{"type":"object"}}}},"403":{"description":"Missing scope, ownership or entitlement","content":{"application/json":{"schema":{"type":"object"}}}},"500":{"description":"Request could not be completed","content":{"application/json":{"schema":{"type":"object"}}}}},"parameters":[{"name":"id","in":"path","required":true,"description":"Key id","schema":{"type":"string"}}]}},"/api/user/api-keys/scopes":{"servers":[{"url":"/","description":"Account integration API"}],"get":{"tags":["Account API keys"],"summary":"List recognized API-key scope names","operationId":"get__api_user_api_keys_scopes","description":"Returns the recognized scope catalogue. A listed scope does not imply a public route exists.\nadmin may appear in the catalogue but cannot be granted by self-service owners; connected CRM scopes have\ntheir own provisioning.","security":[{"OwnerSession":[]}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"type":"object"}}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"oneOf":[{"type":"string"},{"type":"object"}]}}}}}},"401":{"description":"Missing, invalid or expired credentials","content":{"application/json":{"schema":{"type":"object"}}}},"403":{"description":"Missing scope, ownership or entitlement","content":{"application/json":{"schema":{"type":"object"}}}},"500":{"description":"Request could not be completed","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/api/user/api-keys/{id}/audit-logs":{"servers":[{"url":"/","description":"Account integration API"}],"get":{"tags":["Account API keys"],"summary":"Read account API key audit logs","operationId":"get__api_user_api_keys__id__audit_logs","description":"","security":[{"OwnerSession":[]}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"type":"object"}},"meta":{"type":"object"}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"oneOf":[{"type":"string"},{"type":"object"}]}}}}}},"401":{"description":"Missing, invalid or expired credentials","content":{"application/json":{"schema":{"type":"object"}}}},"403":{"description":"Missing scope, ownership or entitlement","content":{"application/json":{"schema":{"type":"object"}}}},"500":{"description":"Request could not be completed","content":{"application/json":{"schema":{"type":"object"}}}}},"parameters":[{"name":"id","in":"path","required":true,"description":"Key id","schema":{"type":"string"}},{"name":"page","in":"query","required":false,"description":"Page number","schema":{"type":"integer","default":1}},{"name":"pageSize","in":"query","required":false,"description":"Maximum 100","schema":{"type":"integer","default":50,"maximum":100}}]}},"/plugins/dashboard-prefs":{"servers":[{"url":"/api","description":"Dashboard application API. Use a signed-in session."}],"get":{"tags":["Dashboard views"],"summary":"Read the effective dashboard view","operationId":"getDashboardView","description":"An owner receives the owner view. An ordinary team member receives their individual override when\none exists, otherwise their current role default. With no saved role default, the normal enabled dashboard\nis returned. Dashboard session only; API keys are not accepted. Layout changes never grant feature or data\naccess.","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Current saved or effective workspace data.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DashboardViewResponse"}}}},"401":{"description":"A valid signed-in session is required.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}},"403":{"description":"The session does not have the required layout authority.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}},"503":{"description":"Workspace settings are temporarily unavailable.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}}}},"put":{"tags":["Dashboard views"],"summary":"Save the owner dashboard view","operationId":"saveOwnerDashboardView","description":"Requires account-owner authority. Ordinary team members, including members with team-management\npermission, cannot manage individual views. Saves a complete normalized view. This is replacement, not a partial\nmerge: omitted actions and cards return to enabled defaults, and omitted shortcuts are cleared. To reset the\nowner view, send {\"prefs\":{}}. Dashboard session only; API keys are not accepted. Layout changes never grant\nfeature or data access.","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Current saved or effective workspace data.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DashboardSaveResponse"}}}},"401":{"description":"A valid signed-in session is required.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}},"403":{"description":"The session does not have the required layout authority.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}},"503":{"description":"Workspace settings are temporarily unavailable.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"prefs":{"$ref":"#/components/schemas/DashboardPreferencesInput"}},"required":["prefs"],"example":{"prefs":{"builtins":{"analytics":{"enabled":true,"order":0}},"cards":{"card-workspace":{"enabled":true},"card-campaigns":{"enabled":false}},"shortcuts":[{"id":"calls","name":"Recent calls","icon":"Phone","url":"/app/calls","enabled":true,"order":0}]}}}}}}}},"/plugins/dashboard-prefs/members":{"servers":[{"url":"/api","description":"Dashboard application API. Use a signed-in session."}],"get":{"tags":["Dashboard views"],"summary":"List members for individual dashboard views","operationId":"listDashboardMembers","description":"Requires account-owner authority. Ordinary team members, including members with team-management\npermission, cannot manage individual views. Returns active members of this account with their current role\nlabel and whether an override exists. Dashboard session only; API keys are not accepted. Layout changes never\ngrant feature or data access.","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Current saved or effective workspace data.","content":{"application/json":{"schema":{"type":"object","properties":{"members":{"type":"array","items":{"$ref":"#/components/schemas/DashboardMember"}}},"required":["members"]}}}},"401":{"description":"A valid signed-in session is required.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}},"403":{"description":"The session does not have the required layout authority.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}},"503":{"description":"Workspace settings are temporarily unavailable.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}}}}},"/plugins/dashboard-prefs/members/{memberId}":{"servers":[{"url":"/api","description":"Dashboard application API. Use a signed-in session."}],"get":{"tags":["Dashboard views"],"summary":"Read a member dashboard view","operationId":"getMemberDashboardView","description":"Requires account-owner authority. Ordinary team members, including members with team-management\npermission, cannot manage individual views. Returns the member override or current role default. inherited\nis true when there is no override. Dashboard session only; API keys are not accepted. Layout changes never\ngrant feature or data access.","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Current saved or effective workspace data.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MemberDashboardViewResponse"}}}},"400":{"description":"Invalid layout identifier or missing member preferences.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}},"401":{"description":"A valid signed-in session is required.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}},"403":{"description":"The session does not have the required layout authority.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}},"404":{"description":"The member, role or team was not found in this account.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}},"503":{"description":"Workspace settings are temporarily unavailable.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}}},"parameters":[{"name":"memberId","in":"path","required":true,"description":"An identifier from this account, as returned by the related member or role list.","schema":{"type":"string","format":"uuid"}}]},"put":{"tags":["Dashboard views"],"summary":"Set an individual member dashboard view","operationId":"saveMemberDashboardView","description":"Requires account-owner authority. Ordinary team members, including members with team-management\npermission, cannot manage individual views. The active member must belong to this account. Saves a complete\nnormalized view. This is replacement, not a partial merge: omitted actions and cards return to enabled defaults,\nand omitted shortcuts are cleared. Saving an empty prefs object creates an explicit default-looking override;\nuse DELETE to inherit the role again. Dashboard session only; API keys are not accepted. Layout changes never\ngrant feature or data access.","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Current saved or effective workspace data.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MemberDashboardSaveResponse"}}}},"400":{"description":"Invalid layout identifier or missing member preferences.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}},"401":{"description":"A valid signed-in session is required.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}},"403":{"description":"The session does not have the required layout authority.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}},"404":{"description":"The member, role or team was not found in this account.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}},"503":{"description":"Workspace settings are temporarily unavailable.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"prefs":{"$ref":"#/components/schemas/DashboardPreferencesInput"}},"required":["prefs"],"example":{"prefs":{"builtins":{"analytics":{"enabled":true,"order":0}},"cards":{"card-workspace":{"enabled":true},"card-campaigns":{"enabled":false}},"shortcuts":[{"id":"calls","name":"Recent calls","icon":"Phone","url":"/app/calls","enabled":true,"order":0}]}}}}}},"parameters":[{"name":"memberId","in":"path","required":true,"description":"An identifier from this account, as returned by the related member or role list.","schema":{"type":"string","format":"uuid"}}]},"delete":{"tags":["Dashboard views"],"summary":"Restore a member current role dashboard","operationId":"resetMemberDashboardView","description":"Requires account-owner authority. Ordinary team members, including members with team-management\npermission, cannot manage individual views. Deletes only this member override and returns their current role\ndefault with inherited=true. Other members, role defaults and the owner view are unchanged. Dashboard session\nonly; API keys are not accepted. Layout changes never grant feature or data access.","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Current saved or effective workspace data.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MemberDashboardResetResponse"}}}},"400":{"description":"Invalid layout identifier or missing member preferences.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}},"401":{"description":"A valid signed-in session is required.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}},"403":{"description":"The session does not have the required layout authority.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}},"404":{"description":"The member, role or team was not found in this account.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}},"503":{"description":"Workspace settings are temporarily unavailable.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}}},"parameters":[{"name":"memberId","in":"path","required":true,"description":"An identifier from this account, as returned by the related member or role list.","schema":{"type":"string","format":"uuid"}}]}},"/plugins/dashboard-prefs/role/{roleId}":{"servers":[{"url":"/api","description":"Dashboard application API. Use a signed-in session."}],"get":{"tags":["Dashboard views"],"summary":"Read a role dashboard default","operationId":"getRoleDashboardView","description":"Requires the account owner or a team role with team-management create or update permission. The\nrole must belong to this account. Returns a normalized default view even when the role has no saved preferences.\nDashboard session only; API keys are not accepted. Layout changes never grant feature or data access.","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Current saved or effective workspace data.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DashboardViewResponse"}}}},"400":{"description":"Invalid layout identifier or missing member preferences.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}},"401":{"description":"A valid signed-in session is required.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}},"403":{"description":"The session does not have the required layout authority.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}},"404":{"description":"The member, role or team was not found in this account.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}},"503":{"description":"Workspace settings are temporarily unavailable.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}}},"parameters":[{"name":"roleId","in":"path","required":true,"description":"An identifier from this account, as returned by the related member or role list.","schema":{"type":"string","format":"uuid"}}]},"put":{"tags":["Dashboard views"],"summary":"Save a role dashboard default","operationId":"saveRoleDashboardView","description":"Requires the account owner or a team role with team-management create or update permission. The\nrole must belong to this account. Saves a complete normalized view. This is replacement, not a partial merge:\nomitted actions and cards return to enabled defaults, and omitted shortcuts are cleared. Members without individual\noverrides inherit this view; existing member overrides remain in place. Dashboard session only; API keys are\nnot accepted. Layout changes never grant feature or data access.","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Current saved or effective workspace data.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DashboardSaveResponse"}}}},"400":{"description":"Invalid layout identifier or missing member preferences.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}},"401":{"description":"A valid signed-in session is required.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}},"403":{"description":"The session does not have the required layout authority.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}},"404":{"description":"The member, role or team was not found in this account.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}},"503":{"description":"Workspace settings are temporarily unavailable.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"prefs":{"$ref":"#/components/schemas/DashboardPreferencesInput"}},"required":["prefs"],"example":{"prefs":{"builtins":{"analytics":{"enabled":true,"order":0}},"cards":{"card-workspace":{"enabled":true},"card-campaigns":{"enabled":false}},"shortcuts":[{"id":"calls","name":"Recent calls","icon":"Phone","url":"/app/calls","enabled":true,"order":0}]}}}}}},"parameters":[{"name":"roleId","in":"path","required":true,"description":"An identifier from this account, as returned by the related member or role list.","schema":{"type":"string","format":"uuid"}}]},"delete":{"tags":["Dashboard views"],"summary":"Reset a role dashboard default","operationId":"resetRoleDashboardView","description":"Requires the account owner or a team role with team-management create or update permission. The\nrole must belong to this account. Removes the saved role view. Members without an individual override return\nto the normal dashboard. Existing member overrides remain in place. Dashboard session only; API keys are not\naccepted. Layout changes never grant feature or data access.","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Current saved or effective workspace data.","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]}},"required":["ok"]}}}},"400":{"description":"Invalid layout identifier or missing member preferences.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}},"401":{"description":"A valid signed-in session is required.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}},"403":{"description":"The session does not have the required layout authority.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}},"404":{"description":"The member, role or team was not found in this account.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}},"503":{"description":"Workspace settings are temporarily unavailable.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}}},"parameters":[{"name":"roleId","in":"path","required":true,"description":"An identifier from this account, as returned by the related member or role list.","schema":{"type":"string","format":"uuid"}}]}},"/plugins/menu-preferences":{"servers":[{"url":"/api","description":"Dashboard application API. Use a signed-in session."}],"get":{"tags":["Navigation layout"],"summary":"Read the effective menu layout","operationId":"getMenuLayout","description":"Returns the owner saved menu, or the current role menu for an ordinary team member. data=null means\nno saved preferences exist. Dashboard session only; API keys are not accepted. Layout changes never grant\nfeature or data access.","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Current saved or effective workspace data.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MenuPreferencesResponse"}}}},"401":{"description":"A valid signed-in session is required.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}},"403":{"description":"The session does not have the required layout authority.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}},"500":{"description":"The workspace operation could not be completed.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}}}},"put":{"tags":["Navigation layout"],"summary":"Save owner menu visibility and order","operationId":"saveOwnerMenuLayout","description":"Requires account-owner authority. Ordinary team members inherit their role menu and cannot save\nor reset the owner menu. Only supplied array fields are merged. Omitted fields retain their values; [] clears\none field. hidden and order accept up to 50 string paths; sectionOrder accepts up to 20 group identifiers.\nDashboard session only; API keys are not accepted. Layout changes never grant feature or data access.","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Current saved or effective workspace data.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]}},"required":["success"]}}}},"401":{"description":"A valid signed-in session is required.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}},"403":{"description":"The session does not have the required layout authority.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}},"500":{"description":"The workspace operation could not be completed.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MenuPreferences"}}}}},"delete":{"tags":["Navigation layout"],"summary":"Reset owner menu visibility and order","operationId":"resetOwnerMenuLayout","description":"Requires account-owner authority. Ordinary team members inherit their role menu and cannot save\nor reset the owner menu. Deletes the owner saved preferences. Menu group names and custom links in menu-config\nare separate and are not reset. Dashboard session only; API keys are not accepted. Layout changes never grant\nfeature or data access.","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Current saved or effective workspace data.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]}},"required":["success"]}}}},"401":{"description":"A valid signed-in session is required.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}},"403":{"description":"The session does not have the required layout authority.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}},"500":{"description":"The workspace operation could not be completed.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}}}}},"/plugins/menu-preferences/role/{roleId}":{"servers":[{"url":"/api","description":"Dashboard application API. Use a signed-in session."}],"get":{"tags":["Navigation layout"],"summary":"Read a role menu layout","operationId":"getRoleMenuLayout","description":"Requires the account owner or a team role with team-management create or update permission. The\nrole must belong to this account. data=null means no saved role menu exists. Dashboard session only; API keys\nare not accepted. Layout changes never grant feature or data access.","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Current saved or effective workspace data.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MenuPreferencesResponse"}}}},"401":{"description":"A valid signed-in session is required.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}},"403":{"description":"The session does not have the required layout authority.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}},"404":{"description":"The member, role or team was not found in this account.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}},"500":{"description":"The workspace operation could not be completed.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}}},"parameters":[{"name":"roleId","in":"path","required":true,"description":"An identifier from this account, as returned by the related member or role list.","schema":{"type":"string","format":"uuid"}}]},"put":{"tags":["Navigation layout"],"summary":"Save a role menu layout","operationId":"saveRoleMenuLayout","description":"Requires the account owner or a team role with team-management create or update permission. The\nrole must belong to this account. Only supplied array fields are merged. Omitted fields retain their values;\n[] clears one field. hidden and order accept up to 50 string paths; sectionOrder accepts up to 20 group identifiers.\nOrdinary members of this role inherit the layout; there is no per-member menu override endpoint. Dashboard\nsession only; API keys are not accepted. Layout changes never grant feature or data access.","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Current saved or effective workspace data.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MenuPreferencesResponse"}}}},"401":{"description":"A valid signed-in session is required.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}},"403":{"description":"The session does not have the required layout authority.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}},"404":{"description":"The member, role or team was not found in this account.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}},"500":{"description":"The workspace operation could not be completed.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MenuPreferences"}}}},"parameters":[{"name":"roleId","in":"path","required":true,"description":"An identifier from this account, as returned by the related member or role list.","schema":{"type":"string","format":"uuid"}}]},"delete":{"tags":["Navigation layout"],"summary":"Reset a role menu layout","operationId":"resetRoleMenuLayout","description":"Requires the account owner or a team role with team-management create or update permission. The\nrole must belong to this account. Deletes this role saved menu layout. It does not change dashboard preferences,\nmenu group names or custom links. Dashboard session only; API keys are not accepted. Layout changes never\ngrant feature or data access.","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Current saved or effective workspace data.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]}},"required":["success"]}}}},"401":{"description":"A valid signed-in session is required.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}},"403":{"description":"The session does not have the required layout authority.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}},"404":{"description":"The member, role or team was not found in this account.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}},"500":{"description":"The workspace operation could not be completed.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}}},"parameters":[{"name":"roleId","in":"path","required":true,"description":"An identifier from this account, as returned by the related member or role list.","schema":{"type":"string","format":"uuid"}}]}},"/plugins/menu-preferences/whats-new":{"servers":[{"url":"/api","description":"Dashboard application API. Use a signed-in session."}],"get":{"tags":["Navigation layout"],"summary":"Read release updates availability","operationId":"getWorkspaceUpdatesAvailability","description":"Returns whether the What's New menu entry is available in the current workspace. It combines account\navailability with the current role menu. This operation only reads availability. Dashboard session only; API\nkeys are not accepted. Layout changes never grant feature or data access.","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Current saved or effective workspace data.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"enabled":{"type":"boolean"}},"required":["success","enabled"]}}}},"401":{"description":"A valid signed-in session is required.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}},"403":{"description":"The session does not have the required layout authority.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}},"503":{"description":"Availability could not be read; the entry is unavailable until a successful read.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"enabled":{"type":"boolean","enum":[false]}},"required":["success","enabled"]}}}}}}},"/plugins/menu-config":{"servers":[{"url":"/api","description":"Dashboard application API. Use a signed-in session."}],"get":{"tags":["Navigation layout"],"summary":"Read menu group names and custom links","operationId":"getMenuConfiguration","description":"Returns navigation labels and links for the current signed-in user context. This configuration\nis separate from the owner or role visibility/order preferences. Dashboard session only; API keys are not\naccepted. Layout changes never grant feature or data access.","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Current saved or effective workspace data.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MenuConfigResponse"}}}},"401":{"description":"A valid signed-in session is required.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}},"500":{"description":"The workspace operation could not be completed.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}}}},"put":{"tags":["Navigation layout"],"summary":"Replace menu group names and custom links","operationId":"saveMenuConfiguration","description":"Replaces both categoryNames and customItems for the current signed-in user context. Omitted collections\nbecome empty. Use {} to clear both. Supports the eight documented groups and up to 30 custom links. This does\nnot change hidden/order/sectionOrder or assign a member-specific menu. Dashboard session only; API keys are\nnot accepted. Layout changes never grant feature or data access.","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Current saved or effective workspace data.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MenuConfigResponse"}}}},"401":{"description":"A valid signed-in session is required.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}},"500":{"description":"The workspace operation could not be completed.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/MenuConfigInput"}],"example":{"categoryNames":{"Monitor":"Activity"},"customItems":[{"label":"API documentation","url":"/api/docs","group":"Help"}]}}}}}}},"/team/members":{"servers":[{"url":"/api","description":"Dashboard application API. Use a signed-in session."}],"get":{"tags":["Workspace team directory"],"summary":"List account team members","operationId":"listWorkspaceTeamMembers","description":"Returns members of the signed-in account team, including member and role identifiers. For active\nmembers eligible for dashboard overrides, prefer GET /plugins/dashboard-prefs/members. This is a read operation;\nit does not grant layout-management permission. Dashboard session only; API keys are not accepted. Layout\nchanges never grant feature or data access.","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Current saved or effective workspace data.","content":{"application/json":{"schema":{"type":"object","properties":{"members":{"type":"array","items":{"$ref":"#/components/schemas/WorkspaceTeamMember"}}},"required":["members"]}}}},"401":{"description":"A valid signed-in session is required.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}},"404":{"description":"The member, role or team was not found in this account.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}},"500":{"description":"The workspace operation could not be completed.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}}}}},"/team/roles":{"servers":[{"url":"/api","description":"Dashboard application API. Use a signed-in session."}],"get":{"tags":["Workspace team directory"],"summary":"List account team roles","operationId":"listWorkspaceTeamRoles","description":"Returns roles of the signed-in account team. Use the returned role IDs in dashboard and menu role-layout\nendpoints. Those endpoints enforce their own management permissions. Dashboard session only; API keys are\nnot accepted. Layout changes never grant feature or data access.","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Current saved or effective workspace data.","content":{"application/json":{"schema":{"type":"object","properties":{"roles":{"type":"array","items":{"$ref":"#/components/schemas/WorkspaceTeamRole"}}},"required":["roles"]}}}},"401":{"description":"A valid signed-in session is required.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}},"404":{"description":"The member, role or team was not found in this account.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}},"500":{"description":"The workspace operation could not be completed.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Readable explanation of the refusal or temporary failure."}}}}}}}}},"/plugins/follow-ups/manual/call-sources":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"get":{"tags":["AI follow-up drafts"],"summary":"List visible call-source metadata","description":"Requires current follow-up create access, call and transcript visibility, and account transcript retention. Returns at most 20 currently visible call metadata records with status and hasTranscript; incomplete calls or records without a usable transcript may be included. Private and assignment visibility depend on the current owner or member permissions. This lookup does not establish generation eligibility, return transcript text or send anything. The generation operation separately requires a completed call and a full usable transcript.","operationId":"client_get_plugins_follow_ups_manual_call_sources","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"occurredAt":{"type":"string"},"status":{"type":"string"},"contactPhone":{"type":"string"},"contactName":{"type":"string"},"contactEmail":{"type":"string"},"hasTranscript":{"type":"boolean"}}}},"noSend":{"type":"boolean","enum":[true]}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"parameters":[{"name":"sourceCallId","in":"query","required":false,"schema":{"type":"string"},"description":"Look up one exact visible call."},{"name":"search","in":"query","required":false,"schema":{"type":"string"},"description":"Caller phone search."}]}},"/plugins/follow-ups/manual/generate":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"post":{"tags":["AI follow-up drafts"],"summary":"Generate an AI follow-up","description":"Requires current follow-up read/create access and a completed visible call with a retained full transcript (40 to 24,000 characters). The recipient and optional contact identity must match the current source. Only the listed input fields are accepted; do not submit message text, attachments or a replacement transcript. Drafts expire after 10 minutes. Identical requestId/input reads the durable result; changed input or actor is refused. generate_and_send additionally requires confirmed: true and update permission; generated content is saved under exact-content approval and existing send gates. An unknown result must be read back by UUID, never automatically retried with a new UUID.","operationId":"client_post_plugins_follow_ups_manual_generate","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientAIGenerationResult"}}}},"409":{"description":"Request identity, source revision, permission or outcome changed. Read the existing generation.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"}}}}}},"503":{"description":"Generation or outcome unavailable. It may be unknown; read by UUID before acting.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientAIGenerationInput"}}}}}},"/plugins/follow-ups/manual/generations/{id}":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"get":{"tags":["AI follow-up drafts"],"summary":"Read an AI generation","description":"Use the original request UUID and actor. Current source/permission checks still apply. A deleted queue task is reported unavailable rather than claiming a send. This read does not dispatch.","operationId":"client_get_plugins_follow_ups_manual_generations_id","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientAIGenerationResult"}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Account-owned resource identifier."}]}},"/plugins/follow-ups/suggest":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"post":{"tags":["AI follow-up drafts"],"summary":"Suggest a draft without sending","description":"Compatibility route for the same generation contract. The server forces draft_only even if another mode was supplied. Current source, UUID, recipient and permission checks still apply.","operationId":"client_post_plugins_follow_ups_suggest","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientAIGenerationResult"}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientAIGenerationInput"}}}}}},"/plugins/follow-ups/manual/options":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"get":{"tags":["Manual follow-ups"],"summary":"Read manual follow-up options","description":"Returns the current account timezone, eligible channels, templates and execution permission. Callback creation is unavailable through this manual composer.","operationId":"client_get_plugins_follow_ups_manual_options","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"timezone":{"type":"string"},"canExecute":{"type":"boolean"},"channels":{"type":"object"},"templates":{"type":"array","items":{"type":"object"}}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}}}},"/plugins/follow-ups/manual/preview":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"post":{"tags":["Manual follow-ups"],"summary":"Preview a manual follow-up","description":"Validates the proposed task and account-local schedule without sending or creating a task. Read/create permission and owned contact, source and attachments are checked. Human tasks use handledBy: human; mode and approval must match the selected action.","operationId":"client_post_plugins_follow_ups_manual_preview","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"noSend":{"type":"boolean","enum":[true]},"item":{"$ref":"#/components/schemas/ClientFollowupItem"}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"requestId":{"type":"string","format":"uuid"},"handledBy":{"type":"string","enum":["human","automated"]},"actionType":{"type":"string","enum":["send_email","send_sms","send_whatsapp","human_task"]},"contactPhone":{"type":"string","example":"+15555550123"},"contactEmail":{"type":"string","example":"client@example.test"},"contactName":{"type":"string"},"sourceCallId":{"type":"string"},"appointmentId":{"type":"string"},"scheduledLocal":{"type":"string","example":"2026-12-01T10:30","description":"Future local account time, at most 365 days ahead. Ambiguous or nonexistent daylight-saving times are refused."},"manualPolicy":{"$ref":"#/components/schemas/ClientManualPolicy"},"message":{"type":"string"},"subject":{"type":"string"},"templateId":{"type":"integer","minimum":1},"aiGuidance":{"type":"string"},"customMessage":{"type":"string"},"visibility":{"type":"string","enum":["shared","internal"]},"context":{"type":"object","properties":{"contactId":{"type":"string"},"attachments":{"type":"array","items":{"$ref":"#/components/schemas/ClientTaskAttachment"},"maxItems":20},"title":{"type":"string"},"category":{"type":"string","enum":["task","call","sms","email","file","other"]},"deliveryMethod":{"type":"string","enum":["none","sms","email","whatsapp","call","in_person"]}}}},"required":["scheduledLocal","manualPolicy"]}}}}}},"/plugins/follow-ups/queue/manual":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"post":{"tags":["Manual follow-ups"],"summary":"Create a manual follow-up","description":"Use the same requestId for readback after a lost response. The version 1 manual policy path is idempotent for identical input. Automatic approval requires update permission. Scheduling, quiet hours, plan, recipient and expiry gates can hold the task. Human task mentions may notify teammates. This response does not prove delivery.","operationId":"client_post_plugins_follow_ups_queue_manual","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Existing identical request returned without creating another task.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"created":{"type":"boolean"},"item":{"$ref":"#/components/schemas/ClientFollowupItem"}}}}}},"201":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"created":{"type":"boolean"},"item":{"$ref":"#/components/schemas/ClientFollowupItem"}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientManualFollowup"}}}}}},"/plugins/follow-ups/work/context":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"get":{"tags":["Task calendar and bulk work"],"summary":"Read work permissions and timezone","description":"Fresh owner/member context for the work view. It does not grant permissions; later operations recheck them.","operationId":"client_get_plugins_follow_ups_work_context","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"timezone":{"type":"string"},"actorKey":{"type":"string"},"canUpdate":{"type":"boolean"},"canAssign":{"type":"boolean"},"followups":{"type":"boolean"},"bookings":{"type":"boolean"}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}}}},"/plugins/follow-ups/calendar":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"get":{"tags":["Task calendar and bulk work"],"summary":"Read the task and booking calendar","description":"Inclusive account-local dates, at most 62 days. Returns at most 200 events per page. Pass nextOffset for the next page; unscheduled=true selects unscheduled open tasks instead of dated events or bookings. Current follow-up and booking visibility apply independently. This is a read-only view.","operationId":"client_get_plugins_follow_ups_calendar","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"timezone":{"type":"string"},"from":{"type":"string"},"to":{"type":"string"},"events":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"kind":{"type":"string","enum":["followup","booking"]},"source_id":{"type":"string"},"title":{"type":"string"},"status":{"type":"string"},"action_type":{"type":"string"},"starts_at":{"type":"string"},"ends_at":{"type":"string"},"local_date":{"type":"string"},"end_local_date":{"type":"string"},"local_time":{"type":"string"},"member_id":{"type":"string","nullable":true},"revision":{"type":"string"}}},"maxItems":200},"hasMore":{"type":"boolean"},"nextOffset":{"type":"integer","nullable":true},"permissions":{"type":"object"},"unscheduled":{"type":"boolean"},"readOnly":{"type":"boolean","enum":[true]}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"parameters":[{"name":"from","in":"query","required":true,"schema":{"type":"string","format":"date"},"description":"First local date."},{"name":"to","in":"query","required":true,"schema":{"type":"string","format":"date"},"description":"Last local date."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"maximum":100000,"default":0},"description":"Pagination offset."},{"name":"kinds","in":"query","required":false,"schema":{"type":"string"},"description":"Comma-separated followup,booking."},{"name":"unscheduled","in":"query","required":false,"schema":{"type":"boolean"},"description":"Include unscheduled tasks."}]}},"/plugins/follow-ups/work/bulk/preview":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"post":{"tags":["Task calendar and bulk work"],"summary":"Preview a bulk work change","description":"Up to 100 distinct task IDs. Reschedule requires scheduledLocal and timezone; assign requires memberId (or null to unassign) and assignment permission. Complete is limited to eligible human tasks; requested callbacks allow cancellation only. Preview does not mutate tasks and expires in 10 minutes.","operationId":"client_post_plugins_follow_ups_work_bulk_preview","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"operationId":{"type":"string","format":"uuid"},"action":{"type":"string"},"parameters":{"type":"object"},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer","minimum":1},"revision":{"type":"string"},"eligible":{"type":"boolean"},"reason":{"type":"string","nullable":true}}}},"expiresAt":{"type":"string"},"noSend":{"type":"boolean","enum":[true]}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientBulkPreviewInput"}}}}}},"/plugins/follow-ups/work/bulk/commit":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"post":{"tags":["Task calendar and bulk work"],"summary":"Confirm a bulk work change","description":"A person must confirm the preview. Current access, task revisions and action eligibility are checked per item. Results can be partial; inspect every item. No message, notification or calendar event is sent.","operationId":"client_post_plugins_follow_ups_work_bulk_commit","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientBulkResult"}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"operationId":{"type":"string","format":"uuid"},"confirmed":{"type":"boolean","enum":[true]}},"required":["operationId","confirmed"]}}}}}},"/plugins/follow-ups/work/bulk/{id}":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"get":{"tags":["Task calendar and bulk work"],"summary":"Read a bulk result","description":"Read the original operation UUID with the same actor after interruption; this does not retry or apply unfinished items.","operationId":"client_get_plugins_follow_ups_work_bulk_id","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientBulkResult"}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Account-owned resource identifier."}]}},"/plugins/follow-ups/work/evidence/task/{id}":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"get":{"tags":["Task evidence review"],"summary":"Read evidence for a task","description":"Reads evidence visible to the current actor, including only permitted call transcripts, conversations and integrations. The default evidence range is 30 days. Unavailable coverage stays unknown. Evidence does not establish delivery or human completion.","operationId":"client_get_plugins_follow_ups_work_evidence_task_id","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientTaskEvidence"}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Account-owned resource identifier."}]}},"/plugins/follow-ups/work/evidence/analyze":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"post":{"tags":["Task evidence review"],"summary":"Analyze task evidence","description":"Requires a durable request UUID and a visible task. Creates a 10-minute actor-bound review, not a completion or send. A repeated or uncertain result must be read using its original review ID.","operationId":"client_post_plugins_follow_ups_work_evidence_analyze","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientEvidenceReview"}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"requestId":{"type":"string","format":"uuid"},"taskId":{"type":"integer","minimum":1},"language":{"type":"string","enum":["en","fr","pt"]}},"required":["requestId","taskId","language"]}}}}}},"/plugins/follow-ups/work/evidence/review/{id}":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"get":{"tags":["Task evidence review"],"summary":"Read an evidence review","description":"Reads the actor-bound review or its confirmed result. It does not confirm a suggestion or send anything.","operationId":"client_get_plugins_follow_ups_work_evidence_review_id","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientEvidenceReview"}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Account-owned resource identifier."}]}},"/plugins/follow-ups/work/evidence/review/{id}/confirm":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"post":{"tags":["Task evidence review"],"summary":"Confirm an evidence decision","description":"Requires current read/update permission, unexpired review and unchanged task/evidence revisions. link records the citations; complete_human additionally requires an eligible open human task. This is workflow-only, with deliveryClaim: false.","operationId":"client_post_plugins_follow_ups_work_evidence_review_id_confirm","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientEvidenceReview"}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Account-owned resource identifier."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"confirmed":{"type":"boolean","enum":[true]},"action":{"type":"string","enum":["link","complete_human"]}},"required":["confirmed","action"]}}}}}},"/plugins/calendar-integrations/work-export":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"get":{"tags":["Calendar sync"],"summary":"Read calendar sync settings","description":"Current session and work/calendar read access required. Owners see office settings; members see their own personal settings and eligible connections. No events are created.","operationId":"client_get_plugins_calendar_integrations_work_export","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientWorkExportSettings"}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}}},"post":{"tags":["Calendar sync"],"summary":"Confirm calendar sync destinations","description":"A person must explicitly opt in. Send the current revision, confirmed: true and preserveExisting: true. At most one destination per booking/followup kind; omitted kinds are disabled. Current own-member/office connection and write permission are rechecked. Sync creates generic private events without attendees, reminders or busy blocking; bookings start after consent, and eligible tasks cover the next 62 days. Disabling preserves existing events. If an outcome is unresolved, read the request and reconcile before another change; never blindly retry a create.","operationId":"client_post_plugins_calendar_integrations_work_export","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientWorkExportSettings"}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"requestId":{"type":"string","format":"uuid"},"confirmed":{"type":"boolean","enum":[true]},"preserveExisting":{"type":"boolean","enum":[true]},"revision":{"type":"string"},"locale":{"type":"string","enum":["en","fr","pt"]},"destinations":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string","enum":["booking","followup"]},"enabled":{"type":"boolean"},"integrationId":{"type":"integer","minimum":1},"calendarId":{"type":"string","minLength":1,"maxLength":2048}},"required":["kind","enabled","integrationId","calendarId"]},"maxItems":2}},"required":["requestId","confirmed","preserveExisting","revision","destinations","locale"]}}}}}},"/plugins/calendar-integrations/work-export/calendars/{id}":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"get":{"tags":["Calendar sync"],"summary":"List writable calendars","description":"The connection must currently belong to this owner or member. Returns writable calendar IDs and names; reading may refresh connection authorization but does not create events.","operationId":"client_get_plugins_calendar_integrations_work_export_calendars_id","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"calendars":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}}}}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Account-owned resource identifier."}]}},"/plugins/calendar-integrations/work-export/requests/{id}":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"get":{"tags":["Calendar sync"],"summary":"Read a calendar settings request","description":"Read the original actor-bound request UUID after interruption. Does not create or retry calendar events.","operationId":"client_get_plugins_calendar_integrations_work_export_requests_id","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"result":{"type":"object"},"settings":{"$ref":"#/components/schemas/ClientWorkExportSettings"}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Account-owned resource identifier."}]}},"/plugins/calendar-integrations/work-export/events":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"get":{"tags":["Calendar sync"],"summary":"List calendar outcomes needing review","description":"Returns at most 100 unresolved event ledger entries for the current owner/member scope. This list is not a complete calendar export.","operationId":"client_get_plugins_calendar_integrations_work_export_events","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"events":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"kind":{"type":"string"},"state":{"type":"string"},"updated_at":{"type":"string"}}},"maxItems":100},"limitedTo":{"type":"integer","enum":[100]}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}}}},"/plugins/calendar-integrations/work-export/events/{id}/reconcile":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"post":{"tags":["Calendar sync"],"summary":"Reconcile one calendar outcome","description":"Requires confirmed: true and current access. Reads the connected calendar to resolve the ledger; never repeats a creation or update. An event with an unknown identifier remains held for review.","operationId":"client_post_plugins_calendar_integrations_work_export_events_id_reconcile","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"state":{"type":"string"},"readOnlyReconciliation":{"type":"boolean"}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Account-owned resource identifier."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"confirmed":{"type":"boolean","enum":[true]}},"required":["confirmed"]}}}}}},"/plugins/follow-ups/contacts/{phone}/translate":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"post":{"tags":["Caller profiles"],"summary":"Translate profile display text","description":"Accepts 1 to 20 nonempty texts with at most 12,000 total characters. Returns translations in the same order; source text is not changed. Only one request per actor can be in flight.","operationId":"client_post_plugins_follow_ups_contacts_phone_translate","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"translations":{"type":"array","items":{"type":"string"}}}}}}},"429":{"description":"Another translation is in flight.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"}}}}}},"502":{"description":"Translation unavailable; original text is unchanged.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"parameters":[{"name":"phone","in":"path","required":true,"schema":{"type":"string"},"description":"URL-encoded caller phone number."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"language":{"type":"string","enum":["en","fr","pt","es"]},"texts":{"type":"array","items":{"type":"string","minLength":1},"minItems":1,"maxItems":20}},"required":["language","texts"]}}}}}},"/plugins/follow-ups/contacts/{phone}/conversations":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"get":{"tags":["Caller profiles"],"summary":"Read visible contact conversations","description":"Reads the owned contact timeline subject to current channel, mailbox and private-conversation visibility.","operationId":"client_get_plugins_follow_ups_contacts_phone_conversations","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"conversations":{"type":"object","properties":{"sms":{"type":"array","items":{"type":"object"}},"whatsapp":{"type":"array","items":{"type":"object"}},"email":{"type":"array","items":{"type":"object"}}}}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"parameters":[{"name":"phone","in":"path","required":true,"schema":{"type":"string"},"description":"URL-encoded caller phone number."}]}},"/plugins/follow-ups/contacts/{phone}/calls":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"get":{"tags":["Caller profiles"],"summary":"Read contact call summaries","description":"Returns currently visible calls for this phone. The date filter uses Toronto dates; q searches summaries and transcripts. This operation returns summary excerpts, not full transcripts or audio.","operationId":"client_get_plugins_follow_ups_contacts_phone_calls","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"calls":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"created_at":{"type":"string"},"duration":{"type":"integer"},"call_direction":{"type":"string"},"summary":{"type":"string","maxLength":140}}}}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"parameters":[{"name":"phone","in":"path","required":true,"schema":{"type":"string"},"description":"URL-encoded caller phone number."},{"name":"date","in":"query","required":false,"schema":{"type":"string","format":"date"},"description":"Toronto calendar date."},{"name":"q","in":"query","required":false,"schema":{"type":"string","maxLength":80},"description":"Search summaries and transcripts; results contain summary excerpts only."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":50,"default":30},"description":"Maximum rows."}]}},"/plugins/follow-ups/contacts/{phone}/conversations/read":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"post":{"tags":["Caller profiles"],"summary":"Mark owned conversation records read","description":"Marks at most 200 selected visible records in one channel as read. Does not send a reply.","operationId":"client_post_plugins_follow_ups_contacts_phone_conversations_read","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"updated":{"type":"integer"}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"parameters":[{"name":"phone","in":"path","required":true,"schema":{"type":"string"},"description":"URL-encoded caller phone number."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"channel":{"type":"string","enum":["sms","whatsapp","email"]},"ids":{"type":"array","items":{"type":"string"},"maxItems":200}},"required":["channel","ids"]}}}}}},"/plugins/follow-ups/contacts/{phone}/notes":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"get":{"tags":["Caller profiles"],"summary":"Read contact notes","description":"Returns account-owned notes and the current author identity used by the editor.","operationId":"client_get_plugins_follow_ups_contacts_phone_notes","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"notes":{"type":"array","items":{"type":"object"}},"meId":{"type":"string"},"isOwner":{"type":"boolean"}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"parameters":[{"name":"phone","in":"path","required":true,"schema":{"type":"string"},"description":"URL-encoded caller phone number."}]},"post":{"tags":["Caller profiles"],"summary":"Add a contact note","description":"Requires nonempty content. noteType (or note_type) defaults to manual. Mentioned teammates may receive a notification; this is not a customer message.","operationId":"client_post_plugins_follow_ups_contacts_phone_notes","security":[{"SessionAuth":[]}],"responses":{"201":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"note":{"type":"object"}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"parameters":[{"name":"phone","in":"path","required":true,"schema":{"type":"string"},"description":"URL-encoded caller phone number."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"content":{"type":"string","minLength":1},"noteType":{"type":"string","default":"manual"}},"required":["content"]}}}}}},"/plugins/follow-ups/contacts/notes/{id}":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"patch":{"tags":["Caller profiles"],"summary":"Edit your own contact note","description":"Only the original author can edit the owned note. Previous content is retained in its revision history.","operationId":"client_patch_plugins_follow_ups_contacts_notes_id","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"note":{"type":"object"}}}}}},"403":{"description":"The current actor is not the note author.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"}}}}}},"404":{"description":"Note not found.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Account-owned resource identifier."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"content":{"type":"string","minLength":1}},"required":["content"]}}}}}},"/plugins/follow-ups/task-rules":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"get":{"tags":["Task assignment rules"],"summary":"Read assignment rules and current health","description":"Account owner only. Returns rules, default, eligible people, agents, plans and account hours for Settings. Health reflects current membership, permission and plan eligibility, not a guarantee a future assignment will apply.","operationId":"client_get_plugins_follow_ups_task_rules","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"rules":{"type":"array","items":{"type":"object"}},"default":{"type":"object","nullable":true},"people":{"type":"object"},"agents":{"type":"array","items":{"type":"object"}},"plan":{"type":"object","properties":{"teamAllowed":{"type":"boolean"},"teamMax":{"type":"integer"},"followupsAllowed":{"type":"boolean"}}},"upsell":{"type":"boolean"},"alerts":{"type":"array","items":{"type":"object"}},"openUnassigned":{"type":"integer"},"activeMembers":{"type":"integer"},"hours":{"type":"object","properties":{"tz":{"type":"string"},"set":{"type":"boolean"}}},"maxRules":{"type":"integer","enum":[25]}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}}},"post":{"tags":["Task assignment rules"],"summary":"Create an assignment rule","description":"Account owner only. At most 25 rules. Name is unique within the account. Agents and active members must belong to this account and the team plan must allow assignment. Eligibility is rechecked when work is assigned.","operationId":"client_post_plugins_follow_ups_task_rules","security":[{"SessionAuth":[]}],"responses":{"201":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"rule":{"type":"object"}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientTaskRuleInput"}}}}}},"/plugins/follow-ups/task-rules/default":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"put":{"tags":["Task assignment rules"],"summary":"Set or remove the default assignee","description":"Account owner only. Use assignee: null to remove the default. Otherwise choose an eligible assignee, optional sources and includeManual. Meeting and manually added work are included only when requested.","operationId":"client_put_plugins_follow_ups_task_rules_default","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"default":{"type":"object","nullable":true},"removed":{"type":"boolean"}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"assignee":{"allOf":[{"$ref":"#/components/schemas/ClientTaskAssignee"}],"nullable":true},"includeManual":{"type":"boolean"},"sources":{"type":"array","items":{"type":"string","enum":["callback_request","property_request","promise_keeper","message_verifier","meeting","follow_up_rule","manual"]}}},"required":["assignee"],"additionalProperties":false}}}}}},"/plugins/follow-ups/task-rules/order":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"put":{"tags":["Task assignment rules"],"summary":"Reorder assignment rules","description":"Account owner only. ids must contain every non-default rule of this account exactly once. Default priority is separate.","operationId":"client_put_plugins_follow_ups_task_rules_order","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"rules":{"type":"array","items":{"type":"object"}}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"ids":{"type":"array","items":{"type":"integer","minimum":1},"uniqueItems":true}},"required":["ids"]}}}}}},"/plugins/follow-ups/task-rules/preview":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"post":{"tags":["Task assignment rules"],"summary":"Preview task assignments","description":"Account owner only. Optional unsaved rules are evaluated in order, up to 25 rules plus a default (26 entries). Omit rules to use saved rules. Nothing is assigned or sent; current membership/plan validation applies.","operationId":"client_post_plugins_follow_ups_task_rules_preview","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"rows":{"type":"array","items":{"type":"object"}}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"rules":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"},"match":{"$ref":"#/components/schemas/ClientTaskRuleMatch"},"assignee":{"$ref":"#/components/schemas/ClientTaskAssignee"},"enabled":{"type":"boolean"},"isDefault":{"type":"boolean"}},"required":["assignee"]},"maxItems":26}}}}}}}},"/plugins/follow-ups/task-rules/draft":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"post":{"tags":["Task assignment rules"],"summary":"Draft an assignment or follow-up rule","description":"Account owner only. AI-assisted drafting only. kind is assignment or follow_up. Returns draft and localized sentence, questions in needs, or blocked reason. It does not save, activate, assign or send. Follow-up suggestions that contact people are drafted off and ask first; save and enable separately after review. Requires the assistant to be available on the account. Up to 20 AI drafting requests per account per hour; a supplied spec skips generation and is validated directly.","operationId":"client_post_plugins_follow_ups_task_rules_draft","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"draft":{"type":"object"},"sentence":{"type":"object"},"needs":{"type":"array","items":{"type":"object"}},"blocked":{"type":"object"}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"kind":{"type":"string","enum":["assignment","follow_up"]},"text":{"type":"string"},"answers":{"type":"object"},"spec":{"type":"object"}},"required":["kind"]}}}}}},"/plugins/follow-ups/task-rules/backfill":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"get":{"tags":["Task assignment rules"],"summary":"Preview assignment backfill","description":"Account owner only. Read the bounded newest-200 selection and selectionDigest before requesting a backfill. This is an assignment preview, not lead creation or a message send.","operationId":"client_get_plugins_follow_ups_task_rules_backfill","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"count":{"type":"integer"},"total":{"type":"integer"},"selectionDigest":{"type":"string"}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}}},"post":{"tags":["Task assignment rules"],"summary":"Apply a confirmed assignment selection","description":"Account owner only. Send the exact selectionDigest from the preview as expectedSelectionDigest. Current eligible selection is recomputed transactionally; stale selection returns 409. Assigns at most the newest 200 eligible tasks without sending messages.","operationId":"client_post_plugins_follow_ups_task_rules_backfill","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"batchId":{"type":"string"},"assigned":{"type":"integer"},"sentence":{"type":"object"}}}}}},"409":{"description":"The preview selection changed; obtain and review a fresh preview.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"expectedSelectionDigest":{"type":"string"}},"required":["expectedSelectionDigest"]}}}}}},"/plugins/follow-ups/task-rules/{id}/enabled":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"put":{"tags":["Task assignment rules"],"summary":"Set assignment rule enabled state","description":"Account owner only. Sets enabled explicitly, never toggles. Enabling starts a new eligibility boundary; older tasks are not automatically backfilled.","operationId":"client_put_plugins_follow_ups_task_rules_id_enabled","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"rule":{"type":"object"}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Account-owned resource identifier."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean"}},"required":["enabled"]}}}}}},"/plugins/follow-ups/task-rules/{id}":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"put":{"tags":["Task assignment rules"],"summary":"Update an assignment rule","description":"Account owner only. Omitted name, match and assignee retain their current values. Use the separate enabled route to change enabled state. Current membership and plan are revalidated.","operationId":"client_put_plugins_follow_ups_task_rules_id","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"rule":{"type":"object"}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Account-owned resource identifier."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":80},"match":{"$ref":"#/components/schemas/ClientTaskRuleMatch"},"assignee":{"$ref":"#/components/schemas/ClientTaskAssignee"}}}}}}},"delete":{"tags":["Task assignment rules"],"summary":"Delete an assignment rule","description":"Account owner only. Deletes only this account rule. Does not send messages or retroactively change all existing assignments.","operationId":"client_delete_plugins_follow_ups_task_rules_id","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"deleted":{"type":"integer","minimum":1}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Account-owned resource identifier."}]}},"/plugins/follow-ups/rules/preview":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"post":{"tags":["Follow-up tools"],"summary":"Preview a follow-up rule","description":"Send ruleId or a draft with triggerEvent/actionType/actionConfig. Renders owned template variables. Members with read permission receive copy without a private call or booking sample. No send or rule write.","operationId":"client_post_plugins_follow_ups_rules_preview","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"preview":{"type":"object","properties":{"channel":{"type":"string","nullable":true},"subject":{"type":"string","nullable":true},"body":{"type":"string","nullable":true},"aiWritten":{"type":"boolean"},"sample":{"type":"object","nullable":true},"testTo":{"type":"string","nullable":true}}}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"ruleId":{"type":"integer","minimum":1},"name":{"type":"string"},"triggerEvent":{"type":"string","description":"One of the trigger events returned by the follow-up configuration."},"actionType":{"type":"string","enum":["send_email","send_sms","send_whatsapp","schedule_callback","ai_suggest","create_task"]},"conditions":{"type":"object"},"delayMinutes":{"type":"integer"},"templateId":{"type":"integer","nullable":true},"agentId":{"type":"string","nullable":true},"priority":{"type":"integer"},"actionConfig":{"type":"object"},"enabled":{"type":"boolean"}}}}}}}},"/plugins/follow-ups/rules/test":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"post":{"tags":["Follow-up tools"],"summary":"Send a test to yourself","description":"Account owner only. Real send to the account owner's configured phone or email only; client/lead recipient fields are rejected. Requires channel plan/readiness, existing send gates and rendered non-AI-written copy. Maximum 10 tests per hour. A 200 response can have sent: false; it is not customer delivery proof.","operationId":"client_post_plugins_follow_ups_rules_test","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"test":{"type":"boolean","enum":[true]},"sent":{"type":"boolean"},"channel":{"type":"string"},"to":{"type":"string"},"reason":{"type":"string"}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"ruleId":{"type":"integer","minimum":1},"name":{"type":"string"},"triggerEvent":{"type":"string","description":"One of the trigger events returned by the follow-up configuration."},"actionType":{"type":"string","enum":["send_email","send_sms","send_whatsapp","schedule_callback","ai_suggest","create_task"]},"conditions":{"type":"object"},"delayMinutes":{"type":"integer"},"templateId":{"type":"integer","nullable":true},"agentId":{"type":"string","nullable":true},"priority":{"type":"integer"},"actionConfig":{"type":"object"},"enabled":{"type":"boolean"}}}}}}}},"/plugins/follow-ups/rules/{id}":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"put":{"tags":["Follow-up tools"],"summary":"Update an automation rule","description":"Account owner only. Current plan must allow follow-ups. Omitted fields retain values; explicitly null templateId or agentId clears it. Owned template/agent references are validated. Snake-case aliases of triggerEvent, actionType, delayMinutes, templateId, agentId and actionConfig are accepted. Changes may affect future automated sends.","operationId":"client_put_plugins_follow_ups_rules_id","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"rule":{"type":"object"}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Account-owned resource identifier."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"ruleId":{"type":"integer","minimum":1},"name":{"type":"string"},"triggerEvent":{"type":"string","description":"One of the trigger events returned by the follow-up configuration."},"actionType":{"type":"string","enum":["send_email","send_sms","send_whatsapp","schedule_callback","ai_suggest","create_task"]},"conditions":{"type":"object"},"delayMinutes":{"type":"integer"},"templateId":{"type":"integer","nullable":true},"agentId":{"type":"string","nullable":true},"priority":{"type":"integer"},"actionConfig":{"type":"object"},"enabled":{"type":"boolean"}}}}}}},"delete":{"tags":["Follow-up tools"],"summary":"Delete an automation rule","description":"Account owner only. Deletes the owned rule. This does not recall messages already sent.","operationId":"client_delete_plugins_follow_ups_rules_id","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"deleted":{"type":"integer","minimum":1}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Account-owned resource identifier."}]}},"/plugins/follow-ups/rules/{id}/toggle":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"post":{"tags":["Follow-up tools"],"summary":"Toggle an automation rule","description":"Account owner only. Flips enabled state. Disabling is allowed; enabling requires the current plan. This can enable future sends. It is not idempotent: read the rule after an uncertain response instead of retrying a toggle.","operationId":"client_post_plugins_follow_ups_rules_id_toggle","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"rule":{"type":"object"}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Account-owned resource identifier."}]}},"/plugins/follow-ups/queue/batch":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"post":{"tags":["Manual follow-ups"],"summary":"Read follow-up badges for calls","description":"Read-only POST. Up to 500 distinct call IDs; current task visibility applies. Returns counts and the two most recent visible items for each call.","operationId":"client_post_plugins_follow_ups_queue_batch","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"map":{"type":"object","additionalProperties":{"type":"object","properties":{"count":{"type":"integer"},"openCount":{"type":"integer"},"items":{"type":"array","items":{"$ref":"#/components/schemas/ClientFollowupItem"},"maxItems":2}}}}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"callIds":{"type":"array","items":{"type":"string"},"maxItems":500,"uniqueItems":true}},"required":["callIds"]}}}}}},"/plugins/follow-ups/queue/attachments/upload-url":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"post":{"tags":["Manual follow-ups"],"summary":"Request a task attachment upload URL","description":"Authenticated session required. taskId defaults to draft. Returns a temporary signed upload destination for the validated file type/name. Uploading does not attach the file to a task or send it. Storage must be configured.","operationId":"client_post_plugins_follow_ups_queue_attachments_upload_url","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string"},"key":{"type":"string"}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"taskId":{"type":"string","default":"draft"},"name":{"type":"string"},"contentType":{"type":"string"}},"required":["name","contentType"]}}}}}},"/plugins/follow-ups/queue/attachments/upload":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"post":{"tags":["Manual follow-ups"],"summary":"Upload a task attachment","description":"Multipart file, up to 25 MiB. taskId defaults to draft; an existing task must be owned by the account. Returns stored attachment metadata; creating/attaching or sending is separate.","operationId":"client_post_plugins_follow_ups_queue_attachments_upload","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"key":{"type":"string"},"name":{"type":"string"},"contentType":{"type":"string"},"size":{"type":"integer"}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary"},"taskId":{"type":"string","default":"draft"}},"required":["file"]}}}}}},"/plugins/follow-ups/queue/{id}/files":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"get":{"tags":["Manual follow-ups"],"summary":"Read an attached file URL","description":"Requires current task read access. key must be in the task prefix or its recorded attachments. Returns a temporary download URL; does not modify or send the file.","operationId":"client_get_plugins_follow_ups_queue_id_files","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","format":"uri"}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Account-owned resource identifier."},{"name":"key","in":"query","required":true,"schema":{"type":"string"},"description":"Exact stored attachment key."}]}},"/plugins/follow-ups/queue/{id}/attachments":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"post":{"tags":["Manual follow-ups"],"summary":"Attach stored file metadata","description":"Requires current task update access. Adds a validated stored key to the task attachment list (at most 30); does not send the file.","operationId":"client_post_plugins_follow_ups_queue_id_attachments","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"attachments":{"type":"array","items":{"$ref":"#/components/schemas/ClientTaskAttachment"},"maxItems":30}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Account-owned resource identifier."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientTaskAttachment"}}}}}},"/plugins/follow-ups/todo":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"get":{"tags":["Manual follow-ups"],"summary":"Read the work queue feed","description":"Returns visible task rows and permitted appointments. Restricted members may receive appointmentsAvailable: false. This is a combined feed, not an external calendar export.","operationId":"client_get_plugins_follow_ups_todo","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"items":{"type":"array","items":{"type":"object"}},"total":{"type":"integer"},"appointmentsAvailable":{"type":"boolean"}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"parameters":[{"name":"sort","in":"query","required":false,"schema":{"type":"string","enum":["newest","oldest"]},"description":"Omit for due order."}]}},"/plugins/follow-ups/queue/{id}/execute":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"post":{"tags":["Manual follow-ups"],"summary":"Execute a follow-up now","description":"Can cause a real send. Requires current update permission, an eligible task and existing approval, recipient, schedule and quiet-hour gates. Atomic claiming prevents competing execution; inspect returned sent/status/held reasons. A lost or unknown response requires readback, never a blind retry.","operationId":"client_post_plugins_follow_ups_queue_id_execute","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"status":{"type":"string"},"sent":{"type":"boolean"},"reason":{"type":"string"}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Account-owned resource identifier."}]}},"/plugins/follow-ups/queue/{id}/reschedule":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"post":{"tags":["Manual follow-ups"],"summary":"Reschedule a task","description":"Requires update permission and a non-running eligible task. Sets pending and clears previous approval; the user must review the new schedule.","operationId":"client_post_plugins_follow_ups_queue_id_reschedule","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"item":{"$ref":"#/components/schemas/ClientFollowupItem"}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Account-owned resource identifier."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"scheduledAt":{"type":"string","format":"date-time"}},"required":["scheduledAt"]}}}}}},"/plugins/follow-ups/queue/{id}/skip":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"post":{"tags":["Manual follow-ups"],"summary":"Skip a task","description":"Requires update permission and a non-running eligible task. Marks skipped and clears approval without sending anything.","operationId":"client_post_plugins_follow_ups_queue_id_skip","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"item":{"$ref":"#/components/schemas/ClientFollowupItem"}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Account-owned resource identifier."}]}},"/plugins/follow-ups/queue/{id}/status":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"post":{"tags":["Manual follow-ups"],"summary":"Set workflow status","description":"Changes an eligible task's workflow status only. Completing a row is not proof a message was sent or delivered. Running tasks and requested-callback actions are guarded.","operationId":"client_post_plugins_follow_ups_queue_id_status","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"item":{"$ref":"#/components/schemas/ClientFollowupItem"}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Account-owned resource identifier."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["pending","in_progress","completed","skipped","cancelled"]}},"required":["status"]}}}}}},"/plugins/follow-ups/queue/{id}/done":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"post":{"tags":["Manual follow-ups"],"summary":"Mark a task completed","description":"Requires current update permission and eligible non-running task. Workflow-only completion; does not send a message and must not be treated as delivery evidence.","operationId":"client_post_plugins_follow_ups_queue_id_done","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"item":{"$ref":"#/components/schemas/ClientFollowupItem"}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Account-owned resource identifier."}]}},"/plugins/follow-ups/queue/{id}/complete":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"post":{"tags":["Manual follow-ups"],"summary":"Mark a task completed (alias)","description":"Requires current update permission and eligible non-running task. Workflow-only completion; does not send a message and must not be treated as delivery evidence.","operationId":"client_post_plugins_follow_ups_queue_id_complete","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"item":{"$ref":"#/components/schemas/ClientFollowupItem"}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Account-owned resource identifier."}]}},"/plugins/follow-ups/queue/{id}/job":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"get":{"tags":["Manual follow-ups"],"summary":"Read a maintenance job brief","description":"Requires task visibility. Maintenance jobs only; other tasks return 404. Returns eligible team members without phone numbers and the current staff-text availability flag.","operationId":"client_get_plugins_follow_ups_queue_id_job","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"brief":{"type":"string"},"photoCount":{"type":"integer"},"staffSmsOn":{"type":"boolean"},"members":{"type":"array","items":{"type":"object"}}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Account-owned resource identifier."}]}},"/plugins/follow-ups/queue/{id}/send-job":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"post":{"tags":["Manual follow-ups"],"summary":"Send a job to selected staff","description":"Real staff text send, only when the existing staff-text feature is on and selected owned members are active and opted in. Requires task update permission and an available sender; platform agent lines are excluded. This endpoint does not enable the feature. Inspect sent/skipped results; do not automatically repeat an uncertain send.","operationId":"client_post_plugins_follow_ups_queue_id_send_job","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"sent":{"type":"integer"},"skipped":{"type":"array","items":{"type":"string"}}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Account-owned resource identifier."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"memberIds":{"type":"array","items":{"type":"string"},"minItems":1}},"required":["memberIds"]}}}}}},"/plugins/follow-ups/queue/{id}/timeline":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"get":{"tags":["Manual follow-ups"],"summary":"Read a task timeline","description":"Current task visibility applies. Entries are returned in ascending order.","operationId":"client_get_plugins_follow_ups_queue_id_timeline","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"timeline":{"type":"array","items":{"type":"object"}}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Account-owned resource identifier."}]},"post":{"tags":["Manual follow-ups"],"summary":"Add to a task timeline","description":"Requires update permission. Adds a human timeline entry of up to 10,000 characters, without sending a customer message.","operationId":"client_post_plugins_follow_ups_queue_id_timeline","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"entry":{"type":"object"}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Account-owned resource identifier."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"body":{"type":"string","minLength":1,"maxLength":10000}},"required":["body"]}}}}}},"/plugins/follow-ups/templates":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"get":{"tags":["Follow-up tools"],"summary":"List follow-up templates","description":"Owner or permitted View All member. Returns owned saved templates, newest first.","operationId":"client_get_plugins_follow_ups_templates","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"templates":{"type":"array","items":{"type":"object"}}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}}},"post":{"tags":["Follow-up tools"],"summary":"Save a follow-up template","description":"Account owner only. Saving copy does not send it. name and body must be nonempty.","operationId":"client_post_plugins_follow_ups_templates","security":[{"SessionAuth":[]}],"responses":{"201":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"template":{"type":"object"}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1},"channel":{"type":"string","enum":["email","sms","whatsapp"]},"subject":{"type":"string"},"body":{"type":"string","minLength":1}},"required":["name","channel","body"]}}}}}},"/plugins/follow-ups/templates/{id}":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"put":{"tags":["Follow-up tools"],"summary":"Update a follow-up template","description":"Account owner only. Updates supplied name/channel/subject/body fields on the owned template. Does not send it.","operationId":"client_put_plugins_follow_ups_templates_id","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"template":{"type":"object"}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Account-owned resource identifier."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1},"channel":{"type":"string","enum":["email","sms","whatsapp"]},"subject":{"type":"string"},"body":{"type":"string","minLength":1}}}}}}},"delete":{"tags":["Follow-up tools"],"summary":"Delete a follow-up template","description":"Account owner only. Deletes only an owned template; previously sent messages are not recalled.","operationId":"client_delete_plugins_follow_ups_templates_id","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"deleted":{"type":"integer","minimum":1}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Account-owned resource identifier."}]}},"/plugins/follow-ups/templates/ai-brand-scan":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"post":{"tags":["Follow-up tools"],"summary":"Read brand information for a draft","description":"Account owner only. Reads the supplied website for a draft. Requires the follow-up plan and shares a 30-per-hour limit with template generation. No template is saved and no message is sent.","operationId":"client_post_plugins_follow_ups_templates_ai_brand_scan","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"brand":{"type":"object"}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"websiteUrl":{"type":"string","format":"uri"}},"required":["websiteUrl"]}}}}}},"/plugins/follow-ups/templates/upload-image":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"post":{"tags":["Follow-up tools"],"summary":"Upload a template image","description":"Account owner only. Multipart image up to 2 MiB, PNG/JPEG/WebP/GIF. The returned URL is for a public template image, not a private task attachment. No message is sent.","operationId":"client_post_plugins_follow_ups_templates_upload_image","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"url":{"type":"string","format":"uri"}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"image":{"type":"string","format":"binary"}},"required":["image"]}}}}}},"/plugins/follow-ups/templates/ai-generate":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"post":{"tags":["Follow-up tools"],"summary":"Draft a follow-up template","description":"Account owner only. Requires the follow-up plan; shares the 30-per-hour brand-scan limit. description is 1 to 2,000 characters. Optional images are public HTTP(S) URLs with placement instructions. Returns a draft and brand information; saving uses POST /templates and sending is separate.","operationId":"client_post_plugins_follow_ups_templates_ai_generate","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"template":{"type":"object"},"brand":{"type":"object"}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"description":{"type":"string","minLength":1,"maxLength":2000},"channel":{"type":"string","enum":["email","sms","whatsapp"]},"websiteUrl":{"type":"string","format":"uri"},"brand":{"type":"object"},"images":{"type":"array","items":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"placement":{"type":"string","maxLength":200}}},"maxItems":6},"language":{"type":"string"}},"required":["description"]}}}}}},"/plugins/follow-ups/stats":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"get":{"tags":["Follow-up tools"],"summary":"Read follow-up statistics","description":"Returns account follow-up queue statistics under the authenticated account context. A completed workflow count is not proof of message delivery.","operationId":"client_get_plugins_follow_ups_stats","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"stats":{"type":"object","properties":{"overdue":{"type":"integer"},"dueToday":{"type":"integer"},"upcoming":{"type":"integer"},"completedThisMonth":{"type":"integer"},"totalRules":{"type":"integer"},"totalTemplates":{"type":"integer"},"unscheduled":{"type":"integer"},"needsApproval":{"type":"integer"},"openTotal":{"type":"integer"},"failed":{"type":"integer"}}}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}}}},"/plugins/follow-ups/sequences":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"get":{"tags":["Follow-up tools"],"summary":"List follow-up sequences","description":"Owner or permitted View All member. Includes step_count and active_enrollments for each owned sequence.","operationId":"client_get_plugins_follow_ups_sequences","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"sequences":{"type":"array","items":{"type":"object"}}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}}},"post":{"tags":["Follow-up tools"],"summary":"Create a follow-up sequence","description":"Account owner only. Can enable future actions if isActive is true. Review trigger, stop and enrollment conditions before activation; this is not a draft-only endpoint.","operationId":"client_post_plugins_follow_ups_sequences","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"sequence":{"type":"object"}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"triggerType":{"type":"string","enum":["manual","no_answer","interested","callback_requested","not_interested","completed"]},"stopConditions":{"type":"object"},"enrollConditions":{"type":"object"},"isActive":{"type":"boolean"},"priority":{"type":"integer"},"maxEnrollments":{"type":"integer","nullable":true}},"required":["name"]}}}}}},"/plugins/follow-ups/sequences/{id}":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"put":{"tags":["Follow-up tools"],"summary":"Update a follow-up sequence","description":"Account owner only. Changes supplied name, description, triggerType, isActive, priority, stopConditions and enrollConditions. Changes can affect active future actions.","operationId":"client_put_plugins_follow_ups_sequences_id","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"sequence":{"type":"object"}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Account-owned resource identifier."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"triggerType":{"type":"string","enum":["manual","no_answer","interested","callback_requested","not_interested","completed"]},"stopConditions":{"type":"object"},"enrollConditions":{"type":"object"},"isActive":{"type":"boolean"},"priority":{"type":"integer"}}}}}}},"delete":{"tags":["Follow-up tools"],"summary":"Delete a follow-up sequence","description":"Account owner only. Deletes this account sequence. Does not recall already completed external actions.","operationId":"client_delete_plugins_follow_ups_sequences_id","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Account-owned resource identifier."}]}},"/plugins/follow-ups/sequences/{id}/steps":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"get":{"tags":["Follow-up tools"],"summary":"Read sequence steps","description":"Owner or permitted View All member; the parent sequence must belong to the account.","operationId":"client_get_plugins_follow_ups_sequences_id_steps","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"steps":{"type":"array","items":{"type":"object"}}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Account-owned resource identifier."}]},"post":{"tags":["Follow-up tools"],"summary":"Add a sequence step","description":"Account owner only. Adds an owned step. A step can cause real actions when the active sequence runs; review actionConfig and conditions before enabling it.","operationId":"client_post_plugins_follow_ups_sequences_id_steps","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"step":{"type":"object"}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Account-owned resource identifier."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"stepNumber":{"type":"integer"},"stepName":{"type":"string"},"delayAmount":{"type":"integer","default":0},"delayUnit":{"type":"string","enum":["minutes","hours","days"]},"actionType":{"type":"string","enum":["call","sms","whatsapp","email","wait","webhook"]},"actionConfig":{"type":"object"},"conditions":{"type":"array","items":{"type":"object"}},"stopIf":{"type":"array","items":{"type":"object"}}}}}}}}},"/plugins/follow-ups/sequences/{id}/steps/{stepId}":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"delete":{"tags":["Follow-up tools"],"summary":"Delete a sequence step","description":"Account owner only. Deletes only a step of this account sequence; no send occurs in this request.","operationId":"client_delete_plugins_follow_ups_sequences_id_steps_stepId","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Account-owned resource identifier."},{"name":"stepId","in":"path","required":true,"schema":{"type":"string"},"description":"Account-owned resource identifier."}]}},"/plugins/follow-ups/sequences/{id}/enrollments":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"get":{"tags":["Follow-up tools"],"summary":"Read sequence enrollments","description":"Owner or permitted View All member. Returns at most the newest 200 owned enrollments.","operationId":"client_get_plugins_follow_ups_sequences_id_enrollments","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"enrollments":{"type":"array","items":{"type":"object"},"maxItems":200}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Account-owned resource identifier."}]}},"/plugins/follow-ups/sequences/{id}/enroll":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"post":{"tags":["Follow-up tools"],"summary":"Enroll a contact in a sequence","description":"Account owner only. Can schedule future sends or calls. Requires an active owned sequence with a first step and available enrollment capacity. Existing phone enrollment is not duplicated. Inspect ok and reason rather than assuming HTTP 200 means enrolled.","operationId":"client_post_plugins_follow_ups_sequences_id_enroll","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"enrollmentId":{"type":"integer"},"reason":{"type":"string"}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Account-owned resource identifier."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"phone":{"type":"string"},"name":{"type":"string"},"email":{"type":"string"}}}}}}}},"/plugins/follow-ups/sequences/enrollments/{enrollmentId}/stop":{"servers":[{"url":"/api","description":"Dashboard API. Use a session token, not an API key."}],"post":{"tags":["Follow-up tools"],"summary":"Stop a sequence enrollment","description":"Account owner only. Marks this account enrollment stopped with manual reason and clears its next step time. Does not recall a completed external action.","operationId":"client_post_plugins_follow_ups_sequences_enrollments_enrollmentId_stop","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Successful response. Inspect the returned state before taking the next action.","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}},"default":{"description":"Request refused or unavailable. Inspect the error and current resource state; do not automatically repeat an action that may have sent or written data.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"success":{"type":"boolean"}}}}}}},"parameters":[{"name":"enrollmentId","in":"path","required":true,"schema":{"type":"string"},"description":"Account-owned resource identifier."}]}}},"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"X-API-Key","description":"Your API key, in the `X-API-Key` header. Scoped: the key can do exactly what its\nscopes allow and is refused with `403 INSUFFICIENT_SCOPES` on anything else.\n"},"BearerAuth":{"type":"http","scheme":"bearer","description":"The same API key, as `Authorization: Bearer <key>`. Equivalent to `X-API-Key`;\nsend one or the other, not both.\n"},"SessionAuth":{"type":"http","scheme":"bearer","description":"A dashboard **session token**, not an API key. Operations marked with this scheme\nbelong to the logged-in web application, live under `/api` rather than `/api/v1`,\nand answer 401 to an API key. They are published here because integrations ask\nabout them; they are not part of the key-authenticated surface.\n"},"EmbedToken":{"type":"apiKey","in":"query","name":"embt","description":"Single-use embed credential from the supported CRM webphone flow. Prefer the embt JSON body field;\nquery fallback is supported but can enter URL logs. This is not an account API key."},"OwnerSession":{"type":"http","scheme":"bearer","description":"Signed-in account owner session token. API keys and team-member sessions are refused."}},"parameters":{"CallIdParam":{"name":"id","in":"path","required":true,"description":"Call identifier exactly as returned by the calls API. Accepts an opaque ALMA call reference or an internal call ID; it is not restricted to UUID format.","schema":{"type":"string"},"example":"AT-0000-0000-0000-0000"},"IntegerIdParam":{"name":"id","in":"path","required":true,"description":"Numeric record identifier returned by this resource.","schema":{"type":"integer","minimum":1}},"PageSize50Param":{"name":"pageSize","in":"query","description":"Items per page (default 50, max 100).","schema":{"type":"integer","default":50,"minimum":1,"maximum":100}},"IdParam":{"name":"id","in":"path","required":true,"description":"Resource UUID","schema":{"type":"string","format":"uuid"}},"PageParam":{"name":"page","in":"query","description":"Page number (1-indexed)","schema":{"type":"integer","default":1,"minimum":1}},"PageSizeParam":{"name":"pageSize","in":"query","description":"Items per page (max 100)","schema":{"type":"integer","default":20,"minimum":1,"maximum":100}}},"responses":{"BadRequest":{"description":"Invalid request parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"Unauthorized":{"description":"Authentication required or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"Forbidden":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"NotFound":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"Conflict":{"description":"Resource conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"InsufficientCredits":{"description":"Insufficient credits","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"schemas":{"Meta":{"type":"object","properties":{"requestId":{"type":"string","format":"uuid"},"timestamp":{"type":"string","format":"date-time"}}},"PaginationMeta":{"allOf":[{"$ref":"#/components/schemas/Meta"},{"type":"object","properties":{"pagination":{"type":"object","properties":{"page":{"type":"integer"},"pageSize":{"type":"integer"},"totalItems":{"type":"integer"},"totalPages":{"type":"integer"},"hasNext":{"type":"boolean"},"hasPrev":{"type":"boolean"}}}}}]},"ErrorResponse":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"object","properties":{"code":{"type":"string","example":"VALIDATION_ERROR"},"message":{"type":"string","example":"Invalid request parameters"},"details":{"type":"object"}}},"meta":{"$ref":"#/components/schemas/Meta"}}},"HealthResponse":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"status":{"type":"string","example":"healthy"},"version":{"type":"string","example":"v1"},"timestamp":{"type":"string","format":"date-time"}}}}},"DeleteResponse":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"deleted":{"type":"boolean","example":true}}},"meta":{"$ref":"#/components/schemas/Meta"}}},"TriggerCallRequest":{"type":"object","required":["agentId","toNumber"],"properties":{"agentId":{"type":"string","format":"uuid","description":"ID of the agent to use for the call"},"toNumber":{"type":"string","description":"Phone number to call (E.164 format recommended)","example":"+14155551234"},"fromNumber":{"type":"string","description":"An active number owned by this account; if omitted the account default is selected. A number\nmust be configured for the chosen agent and route."},"engine":{"type":"string","enum":["almatalk-voice","alma-realtime"],"description":"Telephony engine. almatalk-voice: AlmaTalk Voice engine. alma-realtime: Alma realtime voice\nengine."},"metadata":{"type":"object","additionalProperties":{"type":"string"},"description":"Custom metadata to attach to the call"},"scheduledAt":{"type":"string","format":"date-time","description":"Compatibility field accepted by validation but not used to defer a call. POST /calls starts\nimmediately; do not use this field for scheduling."},"dynamicVariables":{"type":"object","additionalProperties":{"type":"string"},"description":"String variables for the standard AlmaTalk Voice conversation. These override matching metadata\nkeys. They are not applied by the alternate realtime route."}}},"TriggerCallResponse":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"callId":{"type":"string","description":"Opaque call identifier. Preserve the returned value; it is not necessarily a UUID."},"status":{"type":"string","example":"queued"},"agentId":{"type":"string","format":"uuid"},"toNumber":{"type":"string"},"fromNumber":{"type":"string"},"engine":{"type":"string"},"createdAt":{"type":"string","format":"date-time"}}},"meta":{"$ref":"#/components/schemas/Meta"}}},"Appointment":{"type":"object","properties":{"id":{"type":"string","example":"hlZ72Bbi9jKVaorosV9Tc"},"contact_name":{"type":"string","example":"Jordan Taylor"},"contact_phone":{"type":"string","example":"+15145550142"},"contact_email":{"type":"string","format":"email","nullable":true,"example":"jordan.taylor@example.com"},"appointment_date":{"type":"string","example":"2026-04-30"},"appointment_time":{"type":"string","example":"10:00"},"duration":{"type":"integer","example":30},"service_name":{"type":"string","nullable":true,"example":"Will consultation"},"notes":{"type":"string","nullable":true},"status":{"type":"string","enum":["scheduled","confirmed","completed","cancelled","no_show"],"example":"scheduled"},"meeting_type":{"type":"string","enum":["virtual","in_person"],"example":"virtual"},"meeting_link":{"type":"string","nullable":true,"description":"Populated for virtual appointments after a meeting room is created. Null for in-person.","example":"https://almatalk.ca/meet/almatalk-7lKuE-CP1LY6"},"meeting_passcode":{"type":"string","nullable":true,"example":"742193"},"google_calendar_event_id":{"type":"string","nullable":true,"description":"Set after the cron sync pushes this appointment to the user's Google Calendar."},"call_id":{"type":"string","nullable":true,"description":"If the appointment was booked from a voice call, the originating call id."},"flow_id":{"type":"string","nullable":true},"metadata":{"type":"object","nullable":true},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"Call":{"type":"object","properties":{"id":{"type":"string","description":"Opaque call reference. Preserve this value exactly; it is not necessarily a UUID."},"engine":{"type":"string","enum":["almatalk-voice","alma-realtime"],"description":"Telephony engine. almatalk-voice: AlmaTalk Voice engine. alma-realtime: Alma realtime voice\nengine."},"agentId":{"type":"string","format":"uuid"},"toNumber":{"type":"string"},"fromNumber":{"type":"string"},"status":{"type":"string","enum":["queued","ringing","in-progress","completed","failed","no-answer","busy"]},"duration":{"type":"integer","description":"Duration in seconds"},"creditsUsed":{"type":"number"},"transcript":{"type":"string"},"aiSummary":{"type":"string"},"recordingUrl":{"type":"string"},"sentiment":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"endedAt":{"type":"string","format":"date-time"}}},"CallListResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/Call"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}},"CallDetailResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/Call"},"meta":{"$ref":"#/components/schemas/Meta"}}},"HangupResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"callId":{"type":"string"},"status":{"type":"string","example":"hangup_requested"},"message":{"type":"string"}}},"meta":{"$ref":"#/components/schemas/Meta"}}},"CreateCampaignRequest":{"type":"object","required":["name","agentId"],"properties":{"name":{"type":"string","maxLength":255},"agentId":{"type":"string","format":"uuid"},"phoneNumberId":{"type":"string","format":"uuid"},"engine":{"type":"string","enum":["almatalk-voice","alma-realtime"],"description":"Telephony engine. almatalk-voice: AlmaTalk Voice engine. alma-realtime: Alma realtime voice\nengine."},"scheduledStartTime":{"type":"string","format":"date-time"},"timezone":{"type":"string","example":"America/New_York"},"callWindowStart":{"type":"string","pattern":"^\\d{2}:\\d{2}$","example":"09:00"},"callWindowEnd":{"type":"string","pattern":"^\\d{2}:\\d{2}$","example":"18:00"},"maxConcurrentCalls":{"type":"integer","minimum":1,"maximum":100,"default":5},"retryAttempts":{"type":"integer","minimum":0,"maximum":5,"default":2},"retryDelayMinutes":{"type":"integer","minimum":1,"maximum":1440,"default":30}}},"Campaign":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"status":{"type":"string","enum":["draft","scheduled","running","paused","completed","cancelled"]},"agentId":{"type":"string","format":"uuid"},"phoneNumberId":{"type":"string","format":"uuid"},"totalContacts":{"type":"integer"},"calledContacts":{"type":"integer"},"scheduledStartTime":{"type":"string","format":"date-time"},"startedAt":{"type":"string","format":"date-time"},"completedAt":{"type":"string","format":"date-time"},"createdAt":{"type":"string","format":"date-time"}}},"CampaignResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/Campaign"},"meta":{"$ref":"#/components/schemas/Meta"}}},"CampaignListResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/Campaign"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}},"AddCampaignContactsRequest":{"type":"object","required":["contacts"],"properties":{"contacts":{"type":"array","minItems":1,"maxItems":10000,"items":{"type":"object","required":["phoneNumber"],"properties":{"phoneNumber":{"type":"string"},"firstName":{"type":"string"},"lastName":{"type":"string"},"email":{"type":"string","format":"email"},"customFields":{"type":"object","additionalProperties":{"type":"string"}}}}}}},"AddContactsResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"campaignId":{"type":"string"},"contactsAdded":{"type":"integer"},"contactsSkipped":{"type":"integer"}}},"meta":{"$ref":"#/components/schemas/Meta"}}},"CampaignActionResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"campaignId":{"type":"string"},"status":{"type":"string"},"message":{"type":"string"}}},"meta":{"$ref":"#/components/schemas/Meta"}}},"Agent":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"type":{"type":"string","enum":["flow","incoming"]},"telephonyProvider":{"type":"string"},"language":{"type":"string"},"isActive":{"type":"boolean"},"transferEnabled":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"AgentDetail":{"allOf":[{"$ref":"#/components/schemas/Agent"},{"type":"object","properties":{"systemPrompt":{"type":"string"},"firstMessage":{"type":"string"},"llmModel":{"type":"string","description":"AlmaTalk model label; internal model identifiers are private."},"temperature":{"type":"number"},"voiceId":{"type":"string"},"transferPhoneNumber":{"type":"string"},"maxDurationSeconds":{"type":"integer"}}}]},"AgentListResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/Agent"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}},"AgentDetailResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/AgentDetail"},"meta":{"$ref":"#/components/schemas/Meta"}}},"FlowExportResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"version":{"type":"string"},"agentId":{"type":"string"},"agentName":{"type":"string"},"exportedAt":{"type":"string","format":"date-time"},"flow":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"nodes":{"type":"array","items":{"type":"object"}},"edges":{"type":"array","items":{"type":"object"}}}}}},"meta":{"$ref":"#/components/schemas/Meta"}}},"FlowImportRequest":{"type":"object","required":["flow"],"properties":{"flow":{"type":"object","required":["nodes","edges"],"properties":{"name":{"type":"string"},"nodes":{"type":"array","items":{"type":"object"}},"edges":{"type":"array","items":{"type":"object"}}}}}},"FlowImportResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"agentId":{"type":"string"},"message":{"type":"string"}}},"meta":{"$ref":"#/components/schemas/Meta"}}},"CreateContactRequest":{"type":"object","required":["phone"],"properties":{"phone":{"type":"string","minLength":10},"firstName":{"type":"string"},"lastName":{"type":"string"},"email":{"type":"string","format":"email"},"company":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"customFields":{"type":"object","additionalProperties":true}}},"UpdateContactRequest":{"type":"object","properties":{"phone":{"type":"string"},"firstName":{"type":"string"},"lastName":{"type":"string"},"email":{"type":"string","format":"email"},"company":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"customFields":{"type":"object"},"stage":{"type":"string"}}},"Contact":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"phone":{"type":"string"},"firstName":{"type":"string"},"lastName":{"type":"string"},"email":{"type":"string"},"company":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"customFields":{"type":"object"},"stage":{"type":"string"},"leadScore":{"type":"integer"},"aiSummary":{"type":"string"},"sentiment":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"ContactResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/Contact"},"meta":{"$ref":"#/components/schemas/Meta"}}},"ContactListResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/Contact"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}},"BulkImportRequest":{"type":"object","required":["contacts"],"properties":{"contacts":{"type":"array","minItems":1,"maxItems":10000,"items":{"$ref":"#/components/schemas/CreateContactRequest"}},"skipDuplicates":{"type":"boolean","default":true}}},"BulkImportResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"imported":{"type":"integer"},"skipped":{"type":"integer"},"errors":{"type":"array","items":{"type":"object","properties":{"row":{"type":"integer"},"phoneNumber":{"type":"string"},"error":{"type":"string"}}}}}},"meta":{"$ref":"#/components/schemas/Meta"}}},"CreditBalanceResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"available":{"type":"number"},"reserved":{"type":"number"},"total":{"type":"number"},"currency":{"type":"string","example":"credits"}}},"meta":{"$ref":"#/components/schemas/Meta"}}},"CreditUsageResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"period":{"type":"object","properties":{"start":{"type":"string","format":"date-time"},"end":{"type":"string","format":"date-time"}}},"usage":{"type":"array","items":{"type":"object","properties":{"date":{"type":"string","format":"date"},"calls":{"type":"integer","description":"Number of credit deductions on this date, not distinct calls."},"minutes":{"type":"integer","description":"A copy of `credits`, not measured call duration. Kept for backward compatibility.\nUse `credits`, or `GET /analytics/calls` for real duration."},"credits":{"type":"number","description":"Credits deducted on this date."}}}},"total":{"type":"object","properties":{"calls":{"type":"integer"},"minutes":{"type":"integer"},"credits":{"type":"number"}}}}},"meta":{"$ref":"#/components/schemas/Meta"}}},"CallAnalyticsResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"totalCalls":{"type":"integer"},"completedCalls":{"type":"integer"},"failedCalls":{"type":"integer"},"totalDurationMinutes":{"type":"integer"},"averageDurationSeconds":{"type":"integer"},"creditsUsed":{"type":"number"},"period":{"type":"object","properties":{"start":{"type":"string","format":"date-time"},"end":{"type":"string","format":"date-time"}}}}},"meta":{"$ref":"#/components/schemas/Meta"}}},"CampaignAnalyticsResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"type":"object","properties":{"campaignId":{"type":"string"},"name":{"type":"string"},"status":{"type":"string"},"totalContacts":{"type":"integer"},"completed":{"type":"integer"},"successful":{"type":"integer"},"failed":{"type":"integer"},"pending":{"type":"integer"},"successRate":{"type":"integer"},"startedAt":{"type":"string","format":"date-time"},"completedAt":{"type":"string","format":"date-time"}}}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}},"AnalyticsSummaryResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"period":{"type":"object","properties":{"start":{"type":"string","format":"date-time"},"end":{"type":"string","format":"date-time"},"days":{"type":"integer"}}},"calls":{"type":"object","properties":{"total":{"type":"integer"},"completed":{"type":"integer"}}},"campaigns":{"type":"object","properties":{"total":{"type":"integer"},"running":{"type":"integer"},"completed":{"type":"integer"}}}}},"meta":{"$ref":"#/components/schemas/Meta"}}},"CreateWebhookRequest":{"type":"object","required":["url","events"],"properties":{"url":{"type":"string","format":"uri","description":"HTTPS endpoint to receive webhook payloads"},"events":{"type":"array","minItems":1,"items":{"type":"string","enum":["call.started","call.ringing","call.answered","call.completed","call.failed","call.transferred","call.no_answer","call.busy","call.voicemail","inbound_call.received","inbound_call.answered","inbound_call.completed","inbound_call.missed","campaign.started","campaign.completed","campaign.paused","campaign.resumed","campaign.failed","campaign.cancelled","flow.started","flow.completed","flow.failed","appointment.booked","appointment.confirmed","appointment.cancelled","appointment.rescheduled","appointment.completed","appointment.no_show","form.submitted","contact.created","contact.updated","credits.low","credits.depleted"]}},"secret":{"type":"string","description":"Custom signing secret (auto-generated if not provided)"},"description":{"type":"string"}}},"UpdateWebhookRequest":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"events":{"type":"array","minItems":1,"description":"Replaces the subscription's event list. Same accepted names as on create.","items":{"type":"string","enum":["call.started","call.ringing","call.answered","call.completed","call.failed","call.transferred","call.no_answer","call.busy","call.voicemail","inbound_call.received","inbound_call.answered","inbound_call.completed","inbound_call.missed","campaign.started","campaign.completed","campaign.paused","campaign.resumed","campaign.failed","campaign.cancelled","flow.started","flow.completed","flow.failed","appointment.booked","appointment.confirmed","appointment.cancelled","appointment.rescheduled","appointment.completed","appointment.no_show","form.submitted","contact.created","contact.updated","credits.low","credits.depleted"]}},"isActive":{"type":"boolean"},"description":{"type":"string"}}},"Webhook":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"url":{"type":"string"},"events":{"type":"array","items":{"type":"string"}},"isActive":{"type":"boolean"},"description":{"type":"string"},"lastDeliveryAt":{"type":"string","format":"date-time"},"lastDeliveryStatus":{"type":"string"},"createdAt":{"type":"string","format":"date-time"}}},"WebhookResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"allOf":[{"$ref":"#/components/schemas/Webhook"},{"type":"object","properties":{"secret":{"type":"string","description":"Only returned on creation"}}}]},"meta":{"$ref":"#/components/schemas/Meta"}}},"WebhookListResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/Webhook"}},"meta":{"$ref":"#/components/schemas/Meta"}}},"WebhookEventsResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"events":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","example":"call.completed"},"description":{"type":"string"},"emitted":{"type":"boolean","description":"Whether anything in this deployment currently fires the event. `false` means the\nname is accepted on a subscription and never delivered.","example":true}}}}}},"meta":{"$ref":"#/components/schemas/Meta"}}},"WebhookTestResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"delivered":{"type":"boolean"},"statusCode":{"type":"integer"},"message":{"type":"string"}}},"meta":{"$ref":"#/components/schemas/Meta"}}},"DashboardActionPreference":{"type":"object","properties":{"enabled":{"type":"boolean"},"order":{"type":"number","description":"Finite order value; lower values appear first. Defaults to the natural action order."}}},"DashboardCardPreference":{"type":"object","properties":{"enabled":{"type":"boolean"}}},"DashboardShortcut":{"type":"object","properties":{"id":{"type":"string","description":"Optional on input; a missing ID is generated.","maxLength":64},"name":{"type":"string","description":"Trimmed; an empty name becomes Shortcut.","maxLength":40},"icon":{"type":"string","enum":["Phone","PhoneIncoming","PhoneOutgoing","Users","UserPlus","Contact2","Calendar","FileText","BookOpen","Workflow","Bot","Megaphone","Webhook","Target","Plus","Link"],"description":"An unsupported icon becomes Link."},"url":{"type":"string","description":"An internal /app/... path or a valid https:// URL. Invalid URLs are removed from the shortcut\nlist."},"enabled":{"type":"boolean"},"order":{"type":"number"}}},"DashboardPreferences":{"type":"object","properties":{"builtins":{"type":"object","description":"Only these supported action IDs are retained. Omitted actions default to enabled in natural order.\nLayout visibility never grants permission.","properties":{"create-campaign":{"$ref":"#/components/schemas/DashboardActionPreference"},"create-agent":{"$ref":"#/components/schemas/DashboardActionPreference"},"flow-builder":{"$ref":"#/components/schemas/DashboardActionPreference"},"secure-message":{"$ref":"#/components/schemas/DashboardActionPreference"},"open-conversations":{"$ref":"#/components/schemas/DashboardActionPreference"},"team-chat":{"$ref":"#/components/schemas/DashboardActionPreference"},"new-follow-up":{"$ref":"#/components/schemas/DashboardActionPreference"},"book-appointment":{"$ref":"#/components/schemas/DashboardActionPreference"},"meetings":{"$ref":"#/components/schemas/DashboardActionPreference"},"analytics":{"$ref":"#/components/schemas/DashboardActionPreference"}}},"cards":{"type":"object","description":"Supported dashboard cards can be shown or hidden. Cards are not reordered by this contract. Omitted\ncards default to enabled.","properties":{"card-total-calls":{"$ref":"#/components/schemas/DashboardCardPreference"},"card-incoming-calls":{"$ref":"#/components/schemas/DashboardCardPreference"},"card-outgoing-calls":{"$ref":"#/components/schemas/DashboardCardPreference"},"card-contacts":{"$ref":"#/components/schemas/DashboardCardPreference"},"card-campaigns":{"$ref":"#/components/schemas/DashboardCardPreference"},"card-appointments":{"$ref":"#/components/schemas/DashboardCardPreference"},"card-forms-submitted":{"$ref":"#/components/schemas/DashboardCardPreference"},"card-knowledge-base":{"$ref":"#/components/schemas/DashboardCardPreference"},"card-webhooks":{"$ref":"#/components/schemas/DashboardCardPreference"},"card-templates":{"$ref":"#/components/schemas/DashboardCardPreference"},"card-emails-sent":{"$ref":"#/components/schemas/DashboardCardPreference"},"card-sms-sent":{"$ref":"#/components/schemas/DashboardCardPreference"},"card-whatsapp-sent":{"$ref":"#/components/schemas/DashboardCardPreference"},"card-business-snapshot":{"$ref":"#/components/schemas/DashboardCardPreference"},"card-follow-ups":{"$ref":"#/components/schemas/DashboardCardPreference"},"card-secure-messages":{"$ref":"#/components/schemas/DashboardCardPreference"},"card-conversations":{"$ref":"#/components/schemas/DashboardCardPreference"},"card-needs-you":{"$ref":"#/components/schemas/DashboardCardPreference"},"card-recent-calls":{"$ref":"#/components/schemas/DashboardCardPreference"},"card-lead-temperature":{"$ref":"#/components/schemas/DashboardCardPreference"},"card-call-activity":{"$ref":"#/components/schemas/DashboardCardPreference"},"card-caller-mood":{"$ref":"#/components/schemas/DashboardCardPreference"},"card-call-timing":{"$ref":"#/components/schemas/DashboardCardPreference"},"card-workspace":{"$ref":"#/components/schemas/DashboardCardPreference"}}},"shortcuts":{"type":"array","items":{"$ref":"#/components/schemas/DashboardShortcut"},"maxItems":12,"description":"Up to 12 valid custom links. Omitted shortcuts become an empty list when preferences are saved."}},"required":["builtins","cards","shortcuts"],"description":"The normalized dashboard view: quick actions, cards and custom shortcuts. A save replaces the view;\nit does not merge with the previous view. Unknown IDs and fields are removed, and omitted fields use defaults.\nThis configures dashboard content; it does not assign a new landing-page URL or change account permissions."},"DashboardPreferencesInput":{"type":"object","properties":{"builtins":{"type":"object","description":"Only these supported action IDs are retained. Omitted actions default to enabled in natural order.\nLayout visibility never grants permission.","properties":{"create-campaign":{"$ref":"#/components/schemas/DashboardActionPreference"},"create-agent":{"$ref":"#/components/schemas/DashboardActionPreference"},"flow-builder":{"$ref":"#/components/schemas/DashboardActionPreference"},"secure-message":{"$ref":"#/components/schemas/DashboardActionPreference"},"open-conversations":{"$ref":"#/components/schemas/DashboardActionPreference"},"team-chat":{"$ref":"#/components/schemas/DashboardActionPreference"},"new-follow-up":{"$ref":"#/components/schemas/DashboardActionPreference"},"book-appointment":{"$ref":"#/components/schemas/DashboardActionPreference"},"meetings":{"$ref":"#/components/schemas/DashboardActionPreference"},"analytics":{"$ref":"#/components/schemas/DashboardActionPreference"}}},"cards":{"type":"object","description":"Supported dashboard cards can be shown or hidden. Cards are not reordered by this contract. Omitted\ncards default to enabled.","properties":{"card-total-calls":{"$ref":"#/components/schemas/DashboardCardPreference"},"card-incoming-calls":{"$ref":"#/components/schemas/DashboardCardPreference"},"card-outgoing-calls":{"$ref":"#/components/schemas/DashboardCardPreference"},"card-contacts":{"$ref":"#/components/schemas/DashboardCardPreference"},"card-campaigns":{"$ref":"#/components/schemas/DashboardCardPreference"},"card-appointments":{"$ref":"#/components/schemas/DashboardCardPreference"},"card-forms-submitted":{"$ref":"#/components/schemas/DashboardCardPreference"},"card-knowledge-base":{"$ref":"#/components/schemas/DashboardCardPreference"},"card-webhooks":{"$ref":"#/components/schemas/DashboardCardPreference"},"card-templates":{"$ref":"#/components/schemas/DashboardCardPreference"},"card-emails-sent":{"$ref":"#/components/schemas/DashboardCardPreference"},"card-sms-sent":{"$ref":"#/components/schemas/DashboardCardPreference"},"card-whatsapp-sent":{"$ref":"#/components/schemas/DashboardCardPreference"},"card-business-snapshot":{"$ref":"#/components/schemas/DashboardCardPreference"},"card-follow-ups":{"$ref":"#/components/schemas/DashboardCardPreference"},"card-secure-messages":{"$ref":"#/components/schemas/DashboardCardPreference"},"card-conversations":{"$ref":"#/components/schemas/DashboardCardPreference"},"card-needs-you":{"$ref":"#/components/schemas/DashboardCardPreference"},"card-recent-calls":{"$ref":"#/components/schemas/DashboardCardPreference"},"card-lead-temperature":{"$ref":"#/components/schemas/DashboardCardPreference"},"card-call-activity":{"$ref":"#/components/schemas/DashboardCardPreference"},"card-caller-mood":{"$ref":"#/components/schemas/DashboardCardPreference"},"card-call-timing":{"$ref":"#/components/schemas/DashboardCardPreference"},"card-workspace":{"$ref":"#/components/schemas/DashboardCardPreference"}}},"shortcuts":{"type":"array","items":{"$ref":"#/components/schemas/DashboardShortcut"},"maxItems":12,"description":"Up to 12 valid custom links. Omitted shortcuts become an empty list when preferences are saved."}},"description":"Send the full desired view. Any omitted built-in action or card returns to its enabled default; omitted\nshortcuts are cleared. Use an empty object to restore the normal view."},"DashboardViewResponse":{"type":"object","properties":{"prefs":{"$ref":"#/components/schemas/DashboardPreferences"}},"required":["prefs"]},"DashboardSaveResponse":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"prefs":{"$ref":"#/components/schemas/DashboardPreferences"}},"required":["ok","prefs"]},"MemberDashboardViewResponse":{"type":"object","properties":{"prefs":{"$ref":"#/components/schemas/DashboardPreferences"},"inherited":{"type":"boolean"},"roleName":{"type":"string","description":"The member current role label."}},"required":["prefs","inherited","roleName"]},"MemberDashboardSaveResponse":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"prefs":{"$ref":"#/components/schemas/DashboardPreferences"},"inherited":{"type":"boolean","enum":[false]}},"required":["ok","prefs","inherited"]},"MemberDashboardResetResponse":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"prefs":{"$ref":"#/components/schemas/DashboardPreferences"},"inherited":{"type":"boolean","enum":[true]}},"required":["ok","prefs","inherited"]},"DashboardMember":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"email":{"type":"string","format":"email"},"roleName":{"type":"string"},"hasOverride":{"type":"boolean"}},"required":["id","name","email","roleName","hasOverride"]},"MenuPreferences":{"type":"object","properties":{"hidden":{"type":"array","items":{"type":"string","description":"Application menu path."},"maxItems":50},"order":{"type":"array","items":{"type":"string","description":"Application menu path."},"maxItems":50},"sectionOrder":{"type":"array","items":{"type":"string","description":"Menu group identifier."},"maxItems":20}},"description":"Menu visibility, item ordering and group ordering. PUT merges only array fields supplied in the request.\nOmitted fields keep their saved values; an explicit empty array clears that dimension. Non-string array entries\nare removed and arrays are capped. Other existing saved fields are preserved. These preferences do not grant\naccess to hidden or restricted features."},"MenuPreferencesResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"hidden":{"type":"array","items":{"type":"string","description":"Application menu path."},"maxItems":50},"order":{"type":"array","items":{"type":"string","description":"Application menu path."},"maxItems":50},"sectionOrder":{"type":"array","items":{"type":"string","description":"Menu group identifier."},"maxItems":20}},"nullable":true,"description":"null means no saved layout exists for this owner or role."}},"required":["success","data"]},"MenuConfig":{"type":"object","properties":{"categoryNames":{"type":"object","description":"Optional display labels for the supported menu groups. Unknown groups are ignored.","properties":{"General":{"type":"string","maxLength":30},"Build":{"type":"string","maxLength":30},"Telephony":{"type":"string","maxLength":30},"Monitor":{"type":"string","maxLength":30},"Schedule":{"type":"string","maxLength":30},"Team":{"type":"string","maxLength":30},"Help":{"type":"string","maxLength":30},"Settings":{"type":"string","maxLength":30}}},"customItems":{"type":"array","items":{"type":"object","properties":{"label":{"type":"string","maxLength":40},"url":{"type":"string","description":"An internal /app path, /api/docs, or an http:// or https:// URL. Invalid links are dropped.","maxLength":300},"group":{"type":"string","enum":["General","Build","Telephony","Monitor","Schedule","Team","Help","Settings"],"description":"Unknown or omitted groups use Build."}},"required":["label","url"]},"maxItems":30}},"required":["categoryNames","customItems"],"description":"Menu group names and custom navigation links, saved for the current signed-in user context. PUT replaces\nboth collections. Omitted categoryNames or customItems become empty. This is separate from menu visibility/order\npreferences and is not a per-member override API."},"MenuConfigInput":{"type":"object","properties":{"categoryNames":{"type":"object","description":"Optional display labels for the supported menu groups. Unknown groups are ignored.","properties":{"General":{"type":"string","maxLength":30},"Build":{"type":"string","maxLength":30},"Telephony":{"type":"string","maxLength":30},"Monitor":{"type":"string","maxLength":30},"Schedule":{"type":"string","maxLength":30},"Team":{"type":"string","maxLength":30},"Help":{"type":"string","maxLength":30},"Settings":{"type":"string","maxLength":30}}},"customItems":{"type":"array","items":{"type":"object","properties":{"label":{"type":"string","maxLength":40},"url":{"type":"string","description":"An internal /app path, /api/docs, or an http:// or https:// URL. Invalid links are dropped.","maxLength":300},"group":{"type":"string","enum":["General","Build","Telephony","Monitor","Schedule","Team","Help","Settings"],"description":"Unknown or omitted groups use Build."}},"required":["label","url"]},"maxItems":30}},"description":"Menu group names and custom navigation links, saved for the current signed-in user context. PUT replaces\nboth collections. Omitted categoryNames or customItems become empty. This is separate from menu visibility/order\npreferences and is not a per-member override API."},"MenuConfigResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/MenuConfig"}},"required":["success","data"]},"WorkspaceTeamMember":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"name":{"type":"string"},"roleId":{"type":"string","format":"uuid"},"roleName":{"type":"string"},"status":{"type":"string","description":"Membership status; use dashboard-prefs/members for active members eligible for an individual\nview."},"phone":{"type":"string","nullable":true},"smsNotificationsEnabled":{"type":"boolean"},"callNotificationsEnabled":{"type":"boolean"},"lastLoginAt":{"type":"string","format":"date-time","nullable":true},"createdAt":{"type":"string","format":"date-time"}}},"WorkspaceTeamRole":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string","nullable":true},"is_system_role":{"type":"boolean"},"created_at":{"type":"string","format":"date-time"}}},"ClientManualPolicy":{"type":"object","properties":{"version":{"type":"integer","enum":[1]},"timezone":{"type":"string","description":"Exact account timezone from manual/options."},"approval":{"type":"string","enum":["ask","auto"],"default":"ask"},"mode":{"type":"string","enum":["exact","ai","task"],"default":"exact"},"sendWindow":{"type":"object","properties":{"start":{"type":"string","example":"09:00"},"end":{"type":"string","example":"17:00"}},"required":["start","end"],"default":{"start":"09:00","end":"21:00"}},"expiryHours":{"type":"integer","minimum":1,"maximum":168,"default":24}},"required":["version","timezone"]},"ClientTaskAttachment":{"type":"object","properties":{"key":{"type":"string"},"name":{"type":"string"},"contentType":{"type":"string"},"size":{"type":"integer","minimum":0}}},"ClientManualFollowup":{"type":"object","properties":{"requestId":{"type":"string","format":"uuid"},"handledBy":{"type":"string","enum":["human","automated"]},"actionType":{"type":"string","enum":["send_email","send_sms","send_whatsapp","human_task"]},"contactPhone":{"type":"string","example":"+15555550123"},"contactEmail":{"type":"string","example":"client@example.test"},"contactName":{"type":"string"},"sourceCallId":{"type":"string"},"appointmentId":{"type":"string"},"scheduledLocal":{"type":"string","example":"2026-12-01T10:30","description":"Future local account time, at most 365 days ahead. Ambiguous or nonexistent daylight-saving times are refused."},"manualPolicy":{"$ref":"#/components/schemas/ClientManualPolicy"},"message":{"type":"string"},"subject":{"type":"string"},"templateId":{"type":"integer","minimum":1},"aiGuidance":{"type":"string"},"customMessage":{"type":"string"},"visibility":{"type":"string","enum":["shared","internal"]},"context":{"type":"object","properties":{"contactId":{"type":"string"},"attachments":{"type":"array","items":{"$ref":"#/components/schemas/ClientTaskAttachment"},"maxItems":20},"title":{"type":"string"},"category":{"type":"string","enum":["task","call","sms","email","file","other"]},"deliveryMethod":{"type":"string","enum":["none","sms","email","whatsapp","call","in_person"]}}}},"required":["requestId","scheduledLocal","manualPolicy"]},"ClientFollowupItem":{"type":"object","properties":{"id":{"type":"integer","minimum":1},"status":{"type":"string"},"actionType":{"type":"string"},"contactPhone":{"type":"string","nullable":true},"contactEmail":{"type":"string","nullable":true},"scheduledAt":{"type":"string","format":"date-time","nullable":true},"context":{"type":"object"},"sourceCallId":{"type":"string","nullable":true}}},"ClientAIGenerationInput":{"type":"object","properties":{"requestId":{"type":"string","format":"uuid"},"contactPhone":{"type":"string","example":"+15555550123"},"contactEmail":{"type":"string","example":"client@example.test"},"contactName":{"type":"string"},"sourceCallId":{"type":"string"},"appointmentId":{"type":"string"},"scheduledLocal":{"type":"string","example":"2026-12-01T10:30","description":"Future local account time, at most 365 days ahead. Ambiguous or nonexistent daylight-saving times are refused."},"manualPolicy":{"$ref":"#/components/schemas/ClientManualPolicy"},"visibility":{"type":"string","enum":["shared","internal"]},"mode":{"type":"string","enum":["draft_only","generate_and_send"]},"language":{"type":"string","enum":["en","fr","pt"]},"actionType":{"type":"string","enum":["send_email","send_sms"]},"context":{"type":"object","properties":{"contactId":{"type":"string"}},"additionalProperties":false},"aiGuidance":{"type":"string","minLength":1,"maxLength":600},"confirmed":{"type":"boolean"}},"required":["requestId","mode","language","sourceCallId","actionType","contactPhone","scheduledLocal","manualPolicy","aiGuidance"],"additionalProperties":false,"example":{"requestId":"7eb0123b-4153-4a6e-9103-c51e54e8fb20","mode":"draft_only","language":"en","sourceCallId":"example-owned-call","actionType":"send_email","contactPhone":"+15555550123","contactEmail":"client@example.test","scheduledLocal":"2026-12-01T10:30","manualPolicy":{"version":1,"timezone":"America/Toronto","approval":"ask","mode":"exact","sendWindow":{"start":"09:00","end":"17:00"},"expiryHours":24},"aiGuidance":"Summarize only the next step the caller requested."}},"ClientAIDraft":{"type":"object","properties":{"actionType":{"type":"string","enum":["send_email","send_sms"]},"subject":{"type":"string","maxLength":200},"body":{"type":"string","maxLength":2000},"rationale":{"type":"string","maxLength":600},"citations":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"quote":{"type":"string","minLength":5,"maxLength":500}}},"minItems":1,"maxItems":8},"language":{"type":"string","enum":["en","fr","pt"]},"sourceCallId":{"type":"string"},"sourceRevision":{"type":"string"},"contentSha256":{"type":"string"}}},"ClientAIGenerationResult":{"type":"object","properties":{"requestId":{"type":"string","format":"uuid"},"mode":{"type":"string","enum":["draft_only","generate_and_send"]},"status":{"type":"string","enum":["generating","ready","failed","stale","dispatching","dispatched","unknown"]},"draft":{"allOf":[{"$ref":"#/components/schemas/ClientAIDraft"}],"nullable":true},"expiresAt":{"type":"string","format":"date-time"},"queueId":{"type":"integer","nullable":true},"outcome":{"type":"object","properties":{"status":{"type":"string"},"scheduledAt":{"type":"string","nullable":true},"heldFor":{"type":"string","nullable":true},"sent":{"type":"boolean","nullable":true},"delivery":{"type":"string","enum":["unknown"]}},"nullable":true},"noSend":{"type":"boolean"}}},"ClientBulkPreviewInput":{"type":"object","properties":{"ids":{"type":"array","items":{"type":"integer","minimum":1},"minItems":1,"maxItems":100,"uniqueItems":true},"action":{"type":"string","enum":["complete","cancel","reschedule","assign"]},"scheduledLocal":{"type":"string"},"timezone":{"type":"string"},"memberId":{"type":"string","format":"uuid","nullable":true}},"required":["ids","action"]},"ClientBulkResult":{"type":"object","properties":{"operationId":{"type":"string","format":"uuid"},"action":{"type":"string"},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer","minimum":1},"eligible":{"type":"boolean"},"status":{"type":"string","enum":["applied","blocked","stale","pending"]},"reason":{"type":"string","nullable":true},"before":{"type":"string"},"after":{"type":"string"},"at":{"type":"string"},"workflowOnly":{"type":"boolean"}}}},"complete":{"type":"boolean"},"noSend":{"type":"boolean","enum":[true]}}},"ClientTaskEvidence":{"type":"object","properties":{"taskId":{"type":"integer","minimum":1},"taskRevision":{"type":"string"},"range":{"type":"object"},"identity":{"type":"string"},"coverage":{"type":"object","description":"Unavailable sources remain unknown, not zero activity."},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"kind":{"type":"string"},"sourceId":{"type":"string"},"conversationId":{"type":"string","nullable":true},"connectionId":{"type":"string","nullable":true},"occurredAt":{"type":"string","format":"date-time"},"direction":{"type":"string"},"rawStatus":{"type":"string"},"status":{"type":"string"},"excerpt":{"type":"string"},"sourceRevision":{"type":"string"},"provenance":{"type":"string","enum":["stored_platform_record"]},"deliveryProven":{"type":"boolean"}}}},"task":{"type":"object","properties":{"action":{"type":"string"},"status":{"type":"string"},"title":{"type":"string"},"human":{"type":"boolean"},"open":{"type":"boolean"}}},"evidenceRevision":{"type":"string"},"canUpdate":{"type":"boolean"},"readOnly":{"type":"boolean","enum":[true]},"noSend":{"type":"boolean","enum":[true]}}},"ClientEvidenceReview":{"type":"object","properties":{"reviewId":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["analyzing","ready","failed","stale","confirmed"]},"suggestion":{"type":"object","properties":{"action":{"type":"string","enum":["leave_open","review","complete_human"]},"summary":{"type":"string","maxLength":900},"citations":{"type":"array","items":{"type":"string"},"maxItems":10},"aiGenerated":{"type":"boolean"},"requiresConfirmation":{"type":"boolean"}}},"evidence":{"$ref":"#/components/schemas/ClientTaskEvidence"},"expiresAt":{"type":"string"},"noSend":{"type":"boolean","enum":[true]},"result":{"type":"object","properties":{"action":{"type":"string"},"at":{"type":"string"},"before":{"type":"string"},"after":{"type":"string"},"citations":{"type":"array","items":{"type":"string"}},"evidenceRevision":{"type":"string"},"workflowOnly":{"type":"boolean","enum":[true]},"deliveryClaim":{"type":"boolean","enum":[false]}}}}},"ClientWorkExportSettings":{"type":"object","properties":{"revision":{"type":"string"},"scope":{"type":"string","enum":["personal","office"]},"permissions":{"type":"object","properties":{"followup":{"type":"boolean"},"booking":{"type":"boolean"}}},"connections":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer","minimum":1},"provider":{"type":"string"},"calendarId":{"type":"string"}}}},"bindings":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"kind":{"type":"string","enum":["booking","followup"]},"integrationId":{"type":"integer","minimum":1},"calendarId":{"type":"string"},"enabled":{"type":"boolean"},"connectionCurrent":{"type":"boolean"},"consentAt":{"type":"string","nullable":true}}}},"states":{"type":"array","items":{"type":"object","properties":{"state":{"type":"string"},"count":{"type":"integer"}}}},"noAttendees":{"type":"boolean","enum":[true]}}},"ClientTaskAssignee":{"oneOf":[{"type":"object","properties":{"type":{"type":"string","enum":["owner","none"]}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","enum":["member"]},"memberId":{"type":"string","format":"uuid"}},"required":["type","memberId"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","enum":["round_robin"]},"memberIds":{"type":"array","items":{"type":"string","format":"uuid"},"minItems":1,"maxItems":25,"uniqueItems":true}},"required":["type","memberIds"],"additionalProperties":false}]},"ClientTaskRuleMatch":{"type":"object","properties":{"sources":{"type":"array","items":{"type":"string","enum":["callback_request","property_request","promise_keeper","message_verifier","meeting","follow_up_rule","manual"]},"minItems":1},"includeManual":{"type":"boolean"},"agentIds":{"type":"array","items":{"type":"string"},"minItems":1,"maxItems":25},"requestKinds":{"type":"array","items":{"type":"string","enum":["repair","quote","other"]},"minItems":1},"keywords":{"type":"array","items":{"type":"string","minLength":1,"maxLength":60},"minItems":1,"maxItems":10},"urgentOnly":{"type":"boolean"},"callerType":{"type":"string","enum":["new","returning"]},"hours":{"type":"string","enum":["open","closed"]}},"additionalProperties":false},"ClientTaskRuleInput":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":80},"match":{"$ref":"#/components/schemas/ClientTaskRuleMatch"},"assignee":{"$ref":"#/components/schemas/ClientTaskAssignee"},"enabled":{"type":"boolean","default":true}},"required":["name","assignee"]}}}}