For the complete documentation index, see llms.txt. This page is also available as Markdown.

Archive: v0.9.250 - v0.9.399

Archived Amigo API release notes covering v0.9.250 - v0.9.399. For current releases, see the main Amigo API changelog.

Archived release history for the Amigo API. For current releases, see the Amigo API changelog.

v0.9.399 - Platform API: Atlas Handoff Prompting (July 2026)

Atlas Handoff Prompting

Atlas phase agents now receive explicit prompting that teaches the model how to advance through the conversation workflow using transfer tools. This fixes an issue where the voice model would remain in the entry phase without handing off, because it was never told that transfer_to_<step> tools are the mechanism to advance.

What changed:

  • Handoff system context. Phase agents that have outgoing handoffs now receive a system context block explaining the multi-step call structure. The context tells the model it handles one step, that transfer tools are the only way to move the call forward, and that it should advance immediately once its step's goal is met. Agents without handoffs do not receive this block.

  • Directive transfer tool descriptions. Each transfer tool's description is now written as a directive ("Hand the call off to the next step. Use this WHEN: ...") rather than a passive label. This helps the model understand when to invoke the tool.

  • Per-phase advancement instructions. Each phase agent with outgoing handoffs receives a "How to advance" section appended to its instructions. This section lists every available transfer tool alongside its trigger condition as a capitalized directive, so the model has an unambiguous reference for when to call each transfer tool.

  • No mention of transfers to the caller. The system context instructs the model never to mention transfers, connections, or handoffs to the caller - transitions happen silently in the background.

What you need to do:

  • No action required. The improved prompting is applied automatically to all Atlas phase agents with outgoing handoffs. No configuration changes are needed.

  • Expect better handoff behavior. If you observed Atlas calls stalling in the entry phase with zero handoffs, this update addresses the root cause. The model now reliably invokes transfer tools when a phase's goal is met.

v0.9.398 - Platform API: Atlas Global Tool Set and Handoff Observability (July 2026)

Atlas Global Tool Set and Handoff Observability

Atlas phase agents now receive the full platform tool set on every phase, and handoff events between phase agents are emitted to the call timeline for observability.

What changed:

  • Global tool set on every phase agent. Previously, each phase agent received only the tools explicitly bound to its context graph state. In practice, context graph states often bind only a minimal set (or none), which left agents without the platform's globally available tools (skills and surface tools). Now every phase agent receives the full platform tool set in addition to any per-state bindings, matching how tools are exposed in other voice runtimes. Duplicate tools are deduplicated by name.

  • Handoff observability. When one phase agent hands off to another, a state transition event is now emitted to the call timeline. This means phase-to-phase transitions appear in existing dashboards and call detail views alongside transcript and tool call events. Each handoff is also logged for diagnostics.

  • Agent activation logging. When a phase agent becomes active (after a handoff or at call start), the event is logged for diagnostics.

What you need to do:

  • No action required. Phase agents automatically receive the full tool set and handoff events appear in the call timeline. No configuration changes are needed.

  • Review call timelines. If you use Atlas, call detail views now show state transition events for phase handoffs, giving you visibility into how the agent navigates the conversation workflow.

v0.9.397 - Platform API: Atlas Voice Runtime (July 2026)

Atlas Voice Runtime

A new voice session runtime - Atlas - is now available as an opt-in selection for voice agents. Atlas compiles the agent's context graph into a graph of self-sequencing phase agents connected by native handoffs, so the conversation workflow is driven by structured agent collaboration rather than a single flattened prompt. Atlas ships dark by default and is selected only through explicit runtime configuration.

What changed:

  • New atlas session provider. The voice configuration now accepts atlas as a session provider value alongside the existing inhouse and real-time speech-to-speech options. The runtime is selected per service, per agent, or per workspace, with inheritance up the configuration hierarchy (service > agent > workspace > environment default).

  • Context graph compiled to agent graph. When Atlas owns a call, it compiles the context graph into a set of phase agents - each representing a conversation phase with its own objectives, guidelines, and available tools. Agents hand off to each other using native handoffs derived from the context graph's exit conditions. This preserves the context graph as the authoring surface while giving the voice runtime structured multi-agent collaboration.

  • Degraded single-agent fallback. If the agent engine is unavailable at call start, Atlas falls back to a single agent with all available tools and no handoffs. The call stays alive rather than dropping.

  • Barge-in and interruption handling. Atlas supports server-side voice activity detection with interrupt-and-respond behavior. When the caller interrupts, stale audio from the previous response is suppressed and the telephony output buffer is flushed.

  • Transcript and tool call observability. Caller and agent transcripts, tool call start/complete events, barge-in events, and time-to-first-audio latency are emitted through the standard call timeline, so existing dashboards and call detail views work without changes.

  • Token metering. Per-response token counts are recorded for observability, tagged by provider and workspace. Full billing metering is deferred to a future release.

  • Dark by default. Atlas is not enabled unless explicitly configured. Existing voice agents continue to use their current runtime with no change in behavior.

What you need to do:

  • No action required for existing agents. Atlas is opt-in only. Your current voice configuration is unaffected.

  • To try Atlas: Set the session provider to atlas in your service, agent, or workspace voice configuration. Atlas requires a context graph to compile its agent graph - agents without a context graph will run in degraded single-agent mode.

  • Review context graph structure. Atlas derives its phase agents and handoffs from the context graph. Clear step objectives, action guidelines, and exit conditions improve the quality of the compiled agent graph.

v0.9.396 - Platform API: Per-Model Region Routing for Voice Agent (July 2026)

Per-Model Region Routing for Voice Agent

The voice agent engine now performs per-model region routing for supported model families. Newer model versions that are served exclusively on a global endpoint are automatically routed there, while older versions in the same family continue to use the workspace's configured regional endpoint.

What changed:

  • Automatic global endpoint routing. Models in certain families that require a global endpoint (such as newer-generation models) are now routed to that endpoint transparently. The platform detects the model version and selects the correct endpoint without any configuration changes.

  • Regional endpoint preserved for older models. Older model versions that support regional endpoints continue to use the workspace's configured region. There is no change to data residency behavior for these models.

  • Dual-client architecture. The voice agent engine maintains separate connections for regional and global endpoints, selecting the appropriate one per request based on the model being invoked. This ensures that routing decisions are made per-call rather than per-session.

What you need to do:

  • No action required. Region routing is automatic based on the model configured for your agent. Workspaces using older model versions see no change in behavior. Workspaces using newer model versions that were previously unavailable on regional endpoints can now use them without manual endpoint configuration.

v0.9.395 - Platform API: Voice Agent Single-Agent Workflow (July 2026)

Voice Agent Single-Agent Workflow

Real-time voice sessions now use a single-agent workflow model. The voice agent receives the entire conversation workflow as a structured prompt and reasons through all steps itself, with the full tool set always available. This replaces the previous per-state gating approach (v0.9.394) where tools and persona changed at each state transition - that approach caused the voice model to resist transitions and created an impedance mismatch between fine-grained state control and real-time conversation flow.

What changed:

  • Whole-workflow prompt. The voice agent receives a single system prompt that includes the agent's persona, the full conversation workflow rendered as an ordered list of step objectives and guidelines, global guidelines, and global constraints. The agent reasons through the steps in order rather than being gated to one state at a time.

  • Full tool set always available. All of the agent's configured tools are declared at session start and remain available throughout the call. The agent decides when to use each tool based on the workflow context. There is no per-state restriction on which tools appear.

  • Workflow steps derived from context graph. The workflow steps in the prompt are generated from the context graph's engageable states (action and data collection states), ordered by conversation flow. Each step includes the state's objective and any action guidelines. The context graph remains the authoring source of truth for conversation design.

  • Safety model. Write safety is enforced by the prompt (which describes the workflow and when writes are appropriate), the tools the agent is given, and the existing write deduplication on the execution layer. There is no real-time human approval gate on the voice path - an approval step in the hot path would stall a live call.

  • No per-state transitions. The synthetic state transition mechanism from v0.9.394 has been removed. The voice agent no longer signals explicit state transitions, and no transition events are emitted during voice calls.

  • Parallel tool calls disabled. Voice sessions continue to execute tool calls sequentially (one at a time), preventing duplicate parallel invocations.

What you need to do:

  • No action required for existing agents. Voice sessions automatically use the single-agent workflow model. Agents without context graphs are unaffected.

  • Review context graph step objectives. The voice agent uses step objectives and action guidelines from the context graph to understand the workflow. Clear, descriptive objectives improve the agent's ability to work through the call correctly.

  • Exit condition descriptions are no longer used for voice transitions. If you previously tuned exit condition descriptions specifically for voice transition accuracy (per v0.9.394 guidance), those descriptions no longer affect voice sessions. They remain relevant for text session navigation.

v0.9.394 - Platform API: Voice Agent Per-State Gating (July 2026) [Reverted in v0.9.395]

Voice Agent Per-State Gating

Real-time voice sessions now constrain the agent's persona and available tools to the current conversation state, matching the state-aware behavior of text sessions. Previously, voice sessions exposed the full tool set for the entire call. Now, tools and persona instructions update automatically as the conversation advances through the context graph.

What changed:

  • State-gated tools and persona. When a voice call starts, the agent's persona and available tools are derived from the starting state in the context graph. Only tools authorized by the current state are available to the agent - a write tool does not appear until the conversation reaches a state that authorizes it.

  • Model-driven state transitions. The voice agent can advance through context graph states during the call. When the agent determines the current state's objective is complete, it signals a transition to the next state. The platform validates the transition against the context graph's exit conditions, reconfigures the session with the new state's persona and tools, and the agent continues in the new scope. Invalid transitions are rejected and the agent stays in the current state.

  • Routing state resolution. Annotation and decision states in the context graph are resolved automatically during transitions, so the agent always lands on an actionable state. Decision states are resolved using the same navigation logic as text sessions.

  • Terminal state handling. When the conversation reaches the terminal state in the context graph, all tools are removed and the agent delivers a closing message without starting new topics or invoking tools.

  • State transition events. Each state transition emits a state_transition event to the call trace, recording the new state and whether it is terminal. These events appear in the call timeline alongside existing transcript and tool call events.

  • Defense in depth. Per-state gating is the primary access control for tools in voice sessions. Existing write gates (approval policies, write deduplication) continue to apply underneath as defense in depth.

  • No free-form tool fallback. Voice sessions without a co-located agent engine run without tools rather than falling back to the full tool set. This closes the previous gap where all tools could be exposed before state gating was in place.

What you need to do:

  • No action required for existing agents. Voice sessions automatically use per-state gating when the agent has a context graph configured. Agents without context graphs are unaffected.

  • Review context graph exit conditions. The voice agent uses exit condition descriptions to decide when and where to transition. Clear, descriptive exit conditions improve transition accuracy. If your context graph has ambiguous or missing exit condition descriptions, consider updating them.

  • Parallel tool calls disabled. Voice sessions now execute tool calls sequentially (one at a time) to ensure clean state transitions. This may affect agents that previously relied on parallel tool execution in voice sessions.

v0.9.393 - Platform API: Voice Agent Function Calling and Token Metering (July 2026)

Voice Agent Function Calling and Token Metering

The real-time voice agent now supports function calling and per-response token metering, allowing voice agents to invoke the same tools available to text conversations and providing visibility into token consumption.

What changed:

  • Function calling in voice sessions. Voice agents can now call the same tools (skills, integrations, platform functions) available to text sessions. When the agent's tool configuration is available, the voice session declares those tools to the voice model. The model can invoke tools mid-conversation, and results are returned to the model so it can continue speaking with the tool's output. Tool execution runs concurrently with audio processing, so a slow tool does not block audio playback or caller interruptions.

  • Observer trace for tool calls. Each tool invocation emits tool_call_started and tool_call_completed events to the call trace, including the tool name, execution duration, and success status. These events appear in the call timeline and playground trace alongside existing transcript and barge-in events.

  • Graceful tool failure. If a tool execution fails, the voice agent returns a structured error to the model rather than dropping the call. The model can recover and continue the conversation. Failed tool calls are logged in the call trace with failure status.

  • Per-response token metering. Each voice model response now emits token usage counts (input and output tokens) to the monitoring pipeline. Token counts are tagged by workspace for per-tenant cost visibility. This is observability-only - billing integration is a future phase.

  • Tool-less fallback. If the agent's tool configuration is unavailable (for example, due to a transient error during call setup), the voice session runs without tools rather than failing the call. The agent continues to handle the conversation without tool capabilities.

  • Clean teardown of in-flight tools. When a call ends, any tool executions still in progress are cancelled immediately, preventing tools from running side effects after the call has concluded.

What you need to do:

  • No action required for existing agents. If your agent has tools configured, voice sessions will automatically make them available. Agents without tools are unaffected.

  • Review tool behavior for voice. Tools that work in text sessions will work in voice sessions using the same execution path. However, tools with long execution times may cause brief pauses in agent speech. Consider this when designing tools for voice-heavy workflows.

v0.9.392 - Platform API: Per-Agent Persona and Language for Voice Sessions (July 2026)

Per-Agent Persona and Language for Voice Sessions

Real-time voice sessions now use the agent's configured persona and spoken language, so each voice agent behaves according to its own identity settings rather than using a generic default.

What changed:

  • Agent persona in voice sessions. Voice sessions now receive the agent's configured persona (service description, capabilities, and behavioral instructions) automatically. Previously, voice sessions used a generic default persona. The persona is derived from the agent's static identity configuration - it does not change based on the caller's current position in the conversation flow.

  • Agent spoken language in voice sessions. The agent's configured default spoken language is now forwarded to voice sessions automatically. The language value is normalized from its stored format to a standard two-letter code (e.g. en, es, fr) before being applied. Supported language codes include en, es, fr, de, pt, ar, zh, ja, and ko. If no language is configured on the agent, the session uses the default language.

  • Cross-pod consistency. Both persona and language are resolved during call preparation and made available to the voice session regardless of which infrastructure node handles the call. This eliminates cases where a voice session could miss the agent's identity configuration due to internal routing.

What you need to do:

  • No action required for existing agents. If your agent already has a persona and spoken language configured, voice sessions will automatically use them.

  • To customize voice agent behavior, configure the agent's identity settings (persona description and default spoken language) through the agent configuration. Voice sessions will reflect these settings on the next call.

v0.9.391 - Platform API: Identity Binding Test Values for Custom Token Exchange Integrations (July 2026)

Identity Binding Test Values for Custom Token Exchange Integrations

Custom token exchange integrations now support optional test values for identity-bound parameters, enabling workspace authors to test identity-bound integration endpoints from the Developer Console without requiring an external user session.

What changed:

  • New optional field: identity_binding_test_values. When configuring a custom token exchange integration, you can now provide a map of test values for identity-bound parameters. Test values are only supported for external_user.subject_key bindings - other binding types are rejected at configuration time.

  • Author-time validation. Test value keys must reference parameters declared in identity_bindings, and those bindings must use the external_user.subject_key attribute path. Values must be non-empty strings of at most 512 characters.

  • Gated runtime use. Test values are used only during workspace-authenticated text conversation turns where no external user identity is present and the actor holds integration view permissions. They are never used on voice paths, external-user sessions, or principal bindings. When a test value is used, the platform logs the event for observability.

  • Fail-closed behavior preserved. If a required identity attribute is unavailable and no gated test value applies, the integration call is refused rather than executed with an absent identity.

What you need to do:

  • No action required for existing integrations. The field is optional and defaults to an empty map. Existing integrations are unaffected.

  • To configure test values, add identity_binding_test_values to your custom token exchange auth configuration, mapping each identity-bound parameter name to a test string. Use this to test identity-bound endpoints from workspace-authenticated text conversations in the Developer Console without needing an external user session.

v0.9.390 - Platform API: Voice Agent Observability and Transcripts (July 2026)

Voice Agent Observability and Transcripts

The real-time voice agent now emits observability events and call transcripts, bringing its trace output in line with the in-house voice pipeline.

What changed:

  • Time-to-first-audio latency. The voice agent now measures and reports time-to-first-audio (the delay between call start and the first agent audio reaching the caller). This metric appears on the same monitoring dashboards as the in-house pipeline's setup delay metric. The call timeline displays real latency numbers rather than missing values.

  • Barge-in events. Each caller interruption emits a trace event recording which speaker was interrupted, which speaker interrupted, and a running count of barge-ins for the call. These events appear in the call timeline and playground trace.

  • Caller transcripts. The voice agent now emits caller speech transcripts to the call trace. Transcripts are generated as a side-channel for observability - the voice model hears the audio directly and does not depend on these transcripts for comprehension.

  • Agent transcripts. The voice agent now emits agent speech transcripts to the call trace, so the full conversation text is available in the call timeline and analytics pipeline.

  • Privacy-safe logging. Transcript content is delivered through the trace channel but is not written to application logs. Log entries record transcript length only, with no speech content.

What you need to do:

  • No action required. Observability events and transcripts are emitted automatically for all real-time voice sessions. Call timelines, playground traces, and analytics pipelines pick up the new events without configuration changes.

v0.9.389 - Platform API: Voice Agent Barge-In, Greeting, and Language Control (July 2026)

Voice Agent Barge-In, Greeting, and Language Control

The real-time voice agent now supports caller barge-in (interruption handling), automatic inbound greetings, and per-agent language configuration.

What changed:

  • Barge-in support. When a caller speaks while the agent is responding, the agent stops its current reply immediately. Buffered agent audio is flushed from the telephony path so the caller does not hear stale output after interrupting. The agent then responds to the caller's new input rather than continuing the interrupted reply.

  • Inbound greeting. On inbound calls, the agent now greets the caller immediately when the call connects rather than waiting for the caller to speak first. This reduces perceived startup delay and establishes a natural call opening. Outbound calls are not affected - outbound greeting orchestration is handled separately.

  • Language configuration. Voice agents now accept a language parameter in their provider configuration. When set to a supported language code (e.g. en, es, fr, de, pt, ar, zh, ja, ko, hi, it), the agent responds exclusively in that language and does not switch languages based on caller accent or occasional foreign-language words. The default is en (English). Setting the value to multilingual or an unmapped code removes the language restriction, allowing the agent to respond in multiple languages.

  • Voice selection. Voice agents now accept a voice parameter in their provider configuration to select the agent's speaking voice.

  • Updated default model. The default real-time voice model has been updated to the latest generally available version.

  • Telephony-optimized audio input. Voice input now uses noise reduction optimized for close-talking telephony (phone held to the ear), improving turn detection accuracy on phone calls.

What you need to do:

  • No action required for existing agents. Barge-in, inbound greeting, and English language default are enabled automatically.

  • To change the agent's response language, set the language field in the voice provider configuration to a supported language code.

  • To change the agent's voice, set the voice field in the voice provider configuration.

  • To enable multilingual responses, set language to multilingual or omit a single-language restriction.

v0.9.388 - Platform API: Toll-Free Verification Privacy, Terms, and Age-Gated Content Fields (July 2026)

Toll-Free Verification Privacy, Terms, and Age-Gated Content Fields

Toll-free verification submissions now require privacy policy and terms-and-conditions URLs, plus an age-gated content declaration. These fields are submitted to the carrier during verification and returned on the verification response.

What changed:

  • New required field: privacy_policy_url. A public URL pointing to the business's privacy policy. Must be a valid HTTP(S) URL.

  • New required field: terms_and_conditions_url. A public URL pointing to the business's terms and conditions. Must be a valid HTTP(S) URL.

  • New required field: age_gated_content. A boolean indicating whether the messaging campaign carries age-gated content.

  • Response includes new fields. The toll-free verification response object now includes privacy_policy_url, terms_and_conditions_url, and age_gated_content.

  • Fields submitted to carrier. All three fields are forwarded to the carrier as part of the toll-free verification request, both for new submissions and resubmissions of previously rejected verifications.

What you need to do:

  • Add privacy_policy_url, terms_and_conditions_url, and age_gated_content to all toll-free verification submissions. These fields are now required. Provide publicly accessible URLs for your privacy policy and terms, and indicate whether your messaging content is age-gated.

  • Update integrations that read verification responses. The response now includes privacy_policy_url, terms_and_conditions_url, and age_gated_content. Update your response parsing to handle these fields.

v0.9.386 - Platform API: Toll-Free Verification Business Registration Fields (July 2026)

Toll-Free Verification Business Registration Fields

Toll-free verification submissions now require business registration fields that describe the legal structure and registration details of the business behind the messaging program.

What changed:

  • New required field: business_type. Every toll-free verification submission must now include a business_type field indicating the legal structure of the business. Accepted values: PRIVATE_PROFIT, PUBLIC_PROFIT, SOLE_PROPRIETOR, NON_PROFIT, GOVERNMENT.

  • New conditionally required fields: business_registration_number, business_registration_authority, business_registration_country. For every business_type except SOLE_PROPRIETOR, all three business registration fields are required. business_registration_number is the legally recognized registration number (max 64 characters). business_registration_authority is the issuing authority (accepted values: EIN, CBN, CRN, PROVINCIAL_NUMBER, VAT, ACN, ABN, BRN, SIREN, SIRET, NZBN, USt-IdNr, CIF, NIF, CNPJ, UID, NEQ, OTHER). business_registration_country is the ISO 3166-1 alpha-2 country code of registration.

  • Conditional validation. Submitting a business_type other than SOLE_PROPRIETOR without all three registration fields returns a 422 error. Sole proprietors may omit the registration fields.

  • Response includes new fields. The toll-free verification response object now includes business_type (always present), business_registration_number, business_registration_authority, and business_registration_country (null when business_type is SOLE_PROPRIETOR).

What you need to do:

  • Add business_type to all toll-free verification submissions. This field is now required. Choose the value that matches your business's legal structure.

  • Add business registration fields for non-sole-proprietor submissions. If your business_type is anything other than SOLE_PROPRIETOR, include business_registration_number, business_registration_authority, and business_registration_country in your submission.

  • Update integrations that read verification responses. The response now includes business_type, business_registration_number, business_registration_authority, and business_registration_country. Update your response parsing to handle these fields.

v0.9.385 - Platform API: Console Intake Catalog and Schema Registry (July 2026)

Console Intake Catalog and Schema Registry

The Platform API now includes console-facing endpoints for managing customer data intake - a file catalog with upload, download, and listing, plus a schema registry for defining dataset contracts. All endpoints use standard workspace session (JWT) authentication.

What changed:

  • New endpoint: GET /v1/{workspace_id}/intake/files. List uploaded files with pagination, sorting, status filtering, and filename search. Each file shows its dataset, schema version, validation status, size, and upload timestamp. Files that failed validation include a human-readable error reason.

  • New endpoint: POST /v1/{workspace_id}/intake/files. Upload a file to a registered dataset via multipart form data. The platform validates the file synchronously against the dataset's schema contract and assigns a terminal status (success or failed) on upload. Byte-identical re-uploads to the same dataset are deduplicated and return the existing file. Maximum upload size is 100 MB.

  • New endpoint: GET /v1/{workspace_id}/intake/files/{file_id}/download. Download the original uploaded file bytes by file ID.

  • New endpoint: GET /v1/{workspace_id}/intake/datasets. List registered schemas with pagination, sorting, and search by dataset name.

  • New endpoint: POST /v1/{workspace_id}/intake/schema/register. Register a new schema contract for a dataset. A schema defines the expected file format (CSV), primary key columns, and typed field definitions (string, integer, float, boolean, date, datetime). Dataset names must be unique within a workspace.

  • External integration upload path relocated. The HMAC-authenticated external integration upload endpoint has moved from POST /v1/{workspace_id}/intake/files to POST /v1/{workspace_id}/intake/files/external to accommodate the new console upload endpoint.

  • Upload validation. Uploaded CSV files are validated against the dataset's schema: UTF-8 encoding, header presence, required columns, per-cell type coercion, and non-empty primary key values. Validation stops at the first violation and reports the error inline on the file record.

  • Malware scanning. All uploads are scanned before processing. If the scanner is unavailable, uploads are rejected (fail-closed).

  • Versioning. Each uploaded file receives a monotonically increasing version number within its dataset. Concurrent uploads receive distinct versions.

What you need to do:

  • Update external integration upload paths. If your integration uploads files via the HMAC-authenticated path at POST /v1/{workspace_id}/intake/files, update the URL to POST /v1/{workspace_id}/intake/files/external. The request format and authentication are unchanged.

  • No action needed for console users. The new file catalog and schema registry endpoints are available immediately for workspace session-authenticated callers.

v0.9.384 - Platform API: Per-Service and Per-Agent Voice Session Provider Selection (July 2026)

Per-Service and Per-Agent Voice Session Provider Selection

The voice session runtime - which controls whether a call uses the default in-house audio pipeline or a speech-to-speech runtime - can now be configured per-service and per-agent, instead of only as a global default.

What changed:

  • New field: voice_config.session_provider on agents. Agent voice configuration now accepts an optional session_provider field. Accepted values are inhouse (the default audio pipeline) and openai_realtime (speech-to-speech runtime). When set, this overrides the global default for calls handled by that agent. When null or omitted, the agent inherits the global setting.

  • New field: voice_config.session_provider on services. Service voice configuration now accepts the same optional session_provider field. This is the highest-precedence tier - when set, it overrides both the agent-level and global settings. When null or omitted, the service inherits from the agent or global default.

  • Tiered precedence. Resolution follows a precedence ladder: service overrides agent, agent overrides global default. At each tier, a null or omitted value means "inherit from the tier below." This mirrors the existing precedence model used for TTS provider selection.

  • No breaking changes. Existing configurations are unaffected. Both fields default to null, which preserves the current behavior (global default applies).

What you need to do:

  • No action required. Existing agents and services continue to use the global default. To override the voice session runtime for a specific agent or service, set voice_config.session_provider to inhouse or openai_realtime on the agent or service configuration.

v0.9.383 - Platform API: Toll-Free Verification Business Identity Sourced from Customer Profile (July 2026)

Toll-Free Verification Business Identity Sourced from Customer Profile

Toll-free verification submissions no longer accept or return business identity fields (address and contact information). Business identity is now sourced exclusively from the verified Customer Profile attached to the setup.

What changed:

  • Business identity fields removed from the submission endpoint. The following form fields are no longer accepted when submitting a toll-free verification: business_street_address, business_street_address2, business_city, business_state_province_region, business_postal_code, business_country, business_contact_first_name, business_contact_last_name, business_contact_email, business_contact_phone. The carrier sources this information from the verified Customer Profile linked to the setup.

  • Business identity fields removed from the response object. The toll-free verification response no longer includes business_street_address, business_street_address2, business_city, business_state_province_region, business_postal_code, business_country, business_contact_first_name, business_contact_last_name, business_contact_email, or business_contact_phone. The additional_information field remains.

  • Customer Profile is the source of truth. Business identity for toll-free verifications is determined by the Customer Profile associated with the setup. Submitting business address or contact fields alongside a Customer Profile is not supported by the carrier and was previously error-prone.

What you need to do:

  • Remove business identity fields from toll-free verification submissions. If your integration submits toll-free verifications, remove all business address and contact fields from the request. These fields are now rejected. Ensure your Customer Profile on the setup contains accurate business identity information.

  • Update integrations that read verification responses. If you parse the toll-free verification response, remove references to the business address and contact fields. Only additional_information remains as an optional free-text field.

v0.9.382 - Platform API: Toll-Free Verification Enum Updates (July 2026)

Toll-Free Verification Enum Updates

Toll-free verification submissions now use updated enum values that align with the carrier API vocabulary for opt-in types, use-case categories, and message volume buckets.

What changed:

  • New opt-in type: IMPORT. The IMPORT opt-in type is now accepted for toll-free verification submissions, representing a bulk-import opt-in workflow.

  • Use-case categories updated. The accepted use-case category values have changed to match the carrier's API codes. The previous human-readable category names (e.g. "2FA", "General Marketing", "Fraud Alerts") are replaced with standardized codes (e.g. TWO_FACTOR_AUTHENTICATION, MARKETING, FRAUD_ALERT_MESSAGING). The full set of accepted values is: TWO_FACTOR_AUTHENTICATION, ACCOUNT_NOTIFICATIONS, CUSTOMER_CARE, CHARITY_NONPROFIT, DELIVERY_NOTIFICATIONS, FRAUD_ALERT_MESSAGING, EVENTS, HIGHER_EDUCATION, K12, MARKETING, POLLING_AND_VOTING_NON_POLITICAL, POLITICAL_ELECTION_CAMPAIGNS, PUBLIC_SERVICE_ANNOUNCEMENT, SECURITY_ALERT.

  • Message volume buckets updated. The highest volume bucket has changed from 5,000,000+ to two separate buckets: 5,000,000 and 10,000,000+.

What you need to do:

  • Update use-case categories in toll-free verification submissions. If your integration submits toll-free verifications, replace the previous human-readable category values with the new standardized codes listed above. Submissions using the old category names will be rejected.

  • Update message volume values if applicable. If you were using 5,000,000+, switch to either 5,000,000 or 10,000,000+ depending on your actual volume.

  • No action needed for opt-in types unless you want to use the new IMPORT opt-in type for bulk-import workflows.

v0.9.381 - Platform API: Opt-In Confirmation Message on Toll-Free Verification (July 2026)

Opt-In Confirmation Message on Toll-Free Verification

Toll-free verification submissions now require an opt-in confirmation message - the SMS text sent to confirm a recipient's opt-in.

What changed:

  • New required field: opt_in_confirmation_message. The toll-free verification submission endpoint now requires an opt_in_confirmation_message field (string, 1-160 characters). This is the SMS message sent to recipients to confirm their opt-in, and it is forwarded to the carrier as part of the verification request.

  • Returned in verification responses. The opt_in_confirmation_message field is included in the toll-free verification response object, so you can confirm what was submitted.

  • Stored on the verification record. The confirmation message is persisted alongside other verification fields and is included when retrieving existing verifications.

What you need to do:

  • Include opt_in_confirmation_message in toll-free verification submissions. All new submissions must include this field. The value must be between 1 and 160 characters. This is the exact SMS text your recipients receive to confirm their opt-in.

  • Update integrations that read verification responses. The response object now includes the opt_in_confirmation_message field.

v0.9.380 - Platform API: Operator Endpoint to Clear SMS Setup Opt-Outs (July 2026)

Operator Endpoint to Clear SMS Setup Opt-Outs

Operators can now clear a setup-wide SMS opt-out for a recipient, re-enabling sends to that phone number on the setup. This is the only path to reverse a STOP today - there is no recipient-initiated re-subscribe-via-text flow that clears setup-level opt-outs.

What changed:

  • New endpoint: clear SMS setup opt-out. A new POST endpoint allows operators to remove a live setup-wide SMS opt-out for a given setup and phone number. The request requires a reason (1-2000 characters, whitespace-trimmed) that serves as the durable audit record of why the STOP was reversed.

  • 204 on success. When a live opt-out exists and is successfully cleared, the endpoint returns 204. The recipient can be sent to again on this setup.

  • 404 when no live opt-out exists. If no live setup-wide opt-out exists for the given setup and phone number, the endpoint returns 404.

  • 409 when a toll-free opt-out is still active. If the recipient still has an active opt-out against a US/CA toll-free number under the same setup, the endpoint returns 409. Toll-free opt-outs have a clean recipient-initiated reversal path (the recipient texts START or UNSTOP to the toll-free number), so the operator must route the recipient through that first. Once the toll-free opt-out is cleared by the recipient, the operator can retry the setup opt-out clear.

  • Audit trail. The reason supplied by the operator is persisted alongside the soft-delete timestamp as the permanent record of why the opt-out was reversed. There is no separate audit log - the reason on the cleared record is the audit trail.

What you need to do:

  • No action required for existing integrations. This is a new endpoint. Existing SMS send behavior is unchanged.

  • To clear a setup opt-out: POST to the new endpoint with the setup ID, recipient phone number (E.164 format), and a reason explaining why the STOP is being reversed (for example, out-of-band proof of fresh consent). Handle 404 (no live opt-out) and 409 (toll-free opt-out still active) responses.

  • Toll-free opt-outs must be cleared by the recipient first. If the endpoint returns 409, instruct the recipient to text START or UNSTOP to the toll-free number, then retry.

v0.9.379 - Platform API: US/CA Toll-Free SMS Opt-Out Management (July 2026)

US/CA Toll-Free SMS Opt-Out Management

The platform now manages STOP/START/UNSTOP keyword handling for US and CA toll-free SMS numbers. Opt-out enforcement has also been expanded so that all SMS number types - not just A2P 10DLC long codes - block sends to recipients who have opted out.

What changed:

  • Toll-free STOP/START/UNSTOP handling. Inbound STOP, START, and UNSTOP keywords from recipients on US/CA toll-free numbers are now processed by the platform. A STOP creates an opt-out record that blocks further sends to that recipient. START or UNSTOP reverses a live opt-out. These keyword messages are consumed by the platform and never forwarded to the agent.

  • Opt-out enforcement applies to all number types. Previously, the opt-out send gate only applied to A2P 10DLC long-code sends. It now applies to all SMS sends regardless of number type (toll-free, long code, short code). If a recipient has opted out for the active use case, the send endpoint returns 422 with a message indicating the recipient has opted out.

  • No change to recipient-initiated re-subscription. A recipient who has sent STOP can re-subscribe by sending START or UNSTOP to the same toll-free number. Operator-driven opt-out reversal remains unsupported.

  • Idempotent keyword processing. Repeated STOP messages from an already opted-out recipient, or START/UNSTOP messages from a recipient who is not opted out, are accepted silently with no state change. The keyword is still suppressed from the agent in all cases.

What you need to do:

  • No action required for most integrations. If you send SMS through the platform, opt-out enforcement is automatic. Sends to opted-out recipients now return 422 regardless of number type.

  • Update error handling if needed. If your integration previously only expected 422 opt-out errors on A2P 10DLC sends, be aware that the same error can now occur on toll-free sends.

v0.9.378 - Platform API: Opt-In Resend Can No Longer Reverse SMS Opt-Out (July 2026)

Opt-In Resend Can No Longer Reverse SMS Opt-Out

The SMS opt-in resend endpoint no longer supports reversing a recipient's opt-out (STOP). Once a recipient opts out, re-subscription requires a fresh, recipient-initiated consent path - an operator-driven resend cannot override it.

What changed:

  • reverses_opt_out field removed. The opt-in resend request no longer accepts the reverses_opt_out boolean field. Previously, setting this to true allowed an opt-in resend to reverse a live opt-out. This parameter has been removed from the request schema.

  • 409 is now unconditional on opt-out. If the recipient has opted out (a prior STOP), the endpoint always returns 409 Conflict. There is no way to override this through the opt-in resend endpoint.

  • Re-subscription requires recipient-initiated consent. To re-subscribe a recipient who has opted out, a fresh consent path initiated by the recipient is required. Operator-driven resends cannot reverse a STOP.

  • Idempotent behavior unchanged. If the recipient is already opted in, the endpoint still returns 201 with no message re-sent (no-op).

What you need to do:

  • Remove reverses_opt_out from opt-in resend requests. If your integration passes reverses_opt_out in the request body, remove it. The field is no longer accepted.

  • Update opt-out handling workflows. If you relied on reverses_opt_out=true to re-subscribe contacts who sent STOP, you must implement a recipient-initiated consent path instead. The platform no longer permits operator-driven opt-out reversal.

v0.9.377 - Platform API: Per-Skill Sampling Parameters (July 2026)

Per-Skill Sampling Parameters

Skills now support optional temperature and top_p fields for controlling response randomness and diversity on a per-skill basis.

What changed:

  • temperature field on skills. Skills now accept an optional temperature field (number, 0-1) on create and update. Controls sampling temperature for the skill's model. Returned in skill responses.

  • top_p field on skills. Skills now accept an optional top_p field (number, 0-1) on create and update. Controls nucleus sampling for the skill's model. Returned in skill responses.

  • Model-gated behavior. Sampling parameters are model-gated - models that do not support sampling parameters ignore them silently rather than returning an error. No action is needed for skills targeting these models.

  • Mutual exclusivity. Set at most one of temperature or top_p. If both are provided, the runtime keeps temperature and drops top_p. Models that reject receiving both parameters are handled automatically.

  • Defaults. Both fields default to null (not set), which preserves the model's default sampling behavior. Existing skills are unaffected.

What you need to do:

  • No action required for existing skills. Both fields default to null, so existing skills behave exactly as before.

  • To use sampling parameters: Add temperature or top_p (not both) to your skill create or update request. Values must be between 0 and 1 inclusive.

v0.9.376 - Platform API: External User Subject Key Binding for Integration Auth (July 2026)

External User Subject Key Binding for Integration Auth

Integration identity bindings now support the external_user.subject_key binding path, allowing custom token exchange integrations to inject the verified external user's subject key into auth parameters without requiring a materialized session principal.

What changed:

  • New external_user.subject_key binding. Custom token exchange integrations can now bind a declared auth parameter to external_user.subject_key in addition to the existing principal.subject_key and principal.subject_id paths. The new binding resolves from the external-user authentication context verified at token issuance, so external-user sessions can use per-user integration auth without an entity-anchored role assignment.

  • External subject key on session tokens. External-user session tokens now carry the subject key provided at token issuance. The subject key is included in access tokens, refresh tokens, and token rotation, and is validated (non-empty string, max 512 characters) at issuance time.

  • External subject key on text interactions. The text interaction request now accepts an optional external_subject_key field (string, max 512 characters) that is forwarded to the agent engine for identity binding resolution.

  • Fail-closed binding resolution. If an integration declares an external_user.* identity binding but the session has no external-user context, or declares a principal.* binding but the session has no materialized principal, the integration call is refused with a structured error. Integrations without identity bindings are unaffected.

  • Identity binding validation updated. The identity_bindings field on custom token exchange auth configuration now accepts external_user.subject_key as a valid binding target alongside the existing principal.subject_key and principal.subject_id values.

What you need to do:

  • To use the new binding: Update your integration's identity_bindings to map a declared param name to external_user.subject_key. Ensure that external-user session tokens are issued with a subject key (the external_subject_key field on the session grant request).

  • Existing integrations are unaffected. Integrations using principal.* bindings continue to work as before. Integrations with no identity bindings are unchanged.

v0.9.375 - Platform API: Reversible SMS Opt-Out via Opt-In Resend (July 2026)

Reversible SMS Opt-Out via Opt-In Resend

The SMS opt-in endpoint now supports reversing a prior STOP (setup-wide opt-out) when resending an opt-in message, and the opt-out model uses soft-delete semantics so the full opt-out history is retained for audit.

What changed:

  • reverses_opt_out field on opt-in request. The send opt-in message endpoint now requires a reverses_opt_out boolean. When true and the recipient has a live opt-out (a prior STOP), the opt-out is reversed before the opt-in message is sent. When false and an opt-out exists, the endpoint returns 409. This field is required so callers explicitly acknowledge re-subscribing a contact who previously opted out.

  • Opt-out reversal is soft-delete. Reversing an opt-out does not destroy the original opt-out record. The record is marked as reversed, and a subsequent STOP from the same recipient creates a new opt-out record. This preserves the full compliance history for audit.

  • Idempotent opt-in resend. If the recipient is already opted in for the use case, the endpoint returns 201 with no message re-sent. Any opt-out reversal requested in the same call is still applied, so the reversal persists even when consent was already on file.

  • 409 response updated. The 409 response now indicates that the recipient has a live setup-wide opt-out and reverses_opt_out is false, rather than indicating a duplicate opt-in.

  • Opt-out check on send. The SMS send endpoint now checks only live (non-reversed) opt-outs when determining whether a recipient is blocked. Previously reversed opt-outs no longer prevent sending.

What you need to do:

  • Add reverses_opt_out to opt-in requests. The field is required. Set it to true when you intend to re-subscribe a contact who previously sent STOP. Set it to false if you want the request to fail when an opt-out exists.

  • Update 409 handling. If your integration handles the 409 response from the opt-in endpoint, update your logic to reflect the new meaning: the recipient has a live opt-out and reverses_opt_out was not set to true.

v0.9.374 - Platform API: Feature Flag Targeting Key and Unconditional Provider Registration (July 2026)

Feature Flag Targeting Key and Unconditional Provider Registration

The platform's feature flag evaluation now accepts an optional targeting key and always registers the flag provider regardless of environment.

What changed:

  • Targeting key support. Feature flag evaluations now accept an optional targeting_key parameter that identifies the entity the flag is evaluated against. The targeting key enables consistent percentage-rollout bucketing and sticky per-entity flag assignment. When omitted, evaluations behave as before.

  • Unconditional provider registration. The feature flag provider is now registered in all environments. Previously, provider initialization was skipped in local and dev environments, causing all evaluations to return defaults. The provider is now always initialized, and whether evaluations resolve from targeting rules or return the passed default is controlled by the deployment environment's runtime configuration - not by application-level gating.

What you need to do:

  • No action required for existing integrations. Existing flag evaluations continue to work without changes. The targeting key is optional - omitting it preserves current behavior.

  • Pass a targeting key for per-entity rollouts. If you use percentage-based rollouts or per-entity flag assignment, pass the relevant entity identifier as the targeting key to get consistent bucketing.

v0.9.373 - Platform API: A2P Campaign Subscriber Opt-In Simplified (July 2026)

A2P Campaign Subscriber Opt-In Simplified

The A2P campaign submit request and campaign response no longer include a subscriber_opt_in field. The platform always collects consent and sends the opt-in message as the first message before any other message on the use case, so subscriber opt-in is always true. The field has been removed from the request and response to reflect this.

What changed:

  • subscriber_opt_in removed from submit request. The A2P campaign submit endpoint no longer accepts subscriber_opt_in as a request field. The platform always sets subscriber opt-in to true when registering the campaign.

  • subscriber_opt_in removed from campaign response. The A2P campaign response no longer includes subscriber_opt_in. All campaigns are treated as having subscriber opt-in.

  • opt_in_message is always required. The opt_in_message field was already required, but its role is now clearer: the platform sends opt_in_message to a recipient as the first message before any other message on the use case, so every campaign must carry it.

  • opt_in_keywords clarified. The opt_in_keywords field controls text-to-join keyword opt-in (e.g. "START"). It can be empty when the campaign collects consent through other channels such as web or paper forms.

What you need to do:

  • Remove subscriber_opt_in from campaign submit requests. If your integration sends subscriber_opt_in when submitting A2P campaigns, remove it. The field is no longer accepted.

  • Update response parsing. If your code reads subscriber_opt_in from campaign responses, remove that field access. The field is no longer present.

v0.9.372 - Platform API: SMS Opt-In Enforcement and STOP/HELP Opt-Out Management (July 2026)

SMS Opt-In Enforcement and STOP/HELP Opt-Out Management

The channel service now enforces A2P opt-in consent for US SMS numbers and handles STOP/HELP keyword management directly, replacing carrier-level handling with platform-managed compliance.

What changed:

  • Opt-in consent endpoint. A new SMS opt-in endpoint sends the A2P campaign's registered consent message to a recipient phone number for a given use case. The opt-in is recorded per use case and phone number. Resending an opt-in to a number that has already received one returns 409. The endpoint requires a verified A2P campaign to be associated with the use case.

  • Send-time opt-in enforcement. Outbound SMS sends to US numbers with A2P campaign management now require that the opt-in consent message has been sent for the use case and phone number combination. Sends to numbers without a prior opt-in are rejected with a 422 error.

  • Send-time opt-out enforcement. Outbound SMS sends now check whether the recipient has opted out. Sends to opted-out numbers are rejected with a 422 error rather than failing at the carrier level.

  • STOP keyword handling. When a recipient texts a registered opt-out keyword (e.g. STOP), the platform records the opt-out, replies with the registered opt-out confirmation message, and does not forward the message to the agent. Opt-outs apply across all SMS use cases under the same business identity.

  • HELP keyword handling. When a recipient texts a registered help keyword (e.g. HELP), the platform replies with the registered help message and does not forward the message to the agent.

  • Non-keyword messages unchanged. Inbound SMS messages that do not match opt-out or help keywords continue to be forwarded to the agent as normal conversation turns.

Error responses on the opt-in endpoint:

Status
Condition

404

SMS use case not found

409

Opt-in already sent for this use case and phone number

422

No verified A2P campaign, invalid destination (landline, malformed, premium-rate), recipient opted out, destination region not permitted, or brand registration suspended

Error responses on the send endpoint (new conditions):

Status
Condition

422

Opt-in message not yet sent for this use case and phone number

422

Destination phone number has opted out of receiving messages

What you need to do:

  • Send opt-in messages before sending SMS. For US numbers with A2P campaign management, call the opt-in endpoint for each use case and recipient phone number before sending messages. Sends without a prior opt-in will be rejected.

  • Handle new 422 error responses. Update your error handling for the SMS send endpoint to handle the new opt-in and opt-out enforcement errors.

  • No changes needed for non-US numbers or use cases without A2P campaigns. The opt-in and opt-out enforcement only applies to use cases with verified A2P campaigns.

v0.9.371 - Platform API: Unified Email Read Surface and Simplified Send Paths (July 2026)

Unified Email Read Surface and Simplified Send Paths

The channel service email endpoints have been consolidated into a single namespace. Inbound and outbound emails are now served from one set of read endpoints, and send paths use cleaner route conventions.

What changed:

  • Unified email list and detail endpoints. The list endpoint now returns both inbound and outbound emails in a single chronological feed, discriminated by a direction field on each item. You can filter to one direction with the optional direction=inbound|outbound query parameter. The separate /inbound list endpoint has been removed.

  • Unified get-one endpoint. The detail endpoint returns a discriminated response keyed on direction. Inbound emails include fields such as received timestamp, body kind, reply linkage, and attachment filenames. Outbound emails include delivery state, engagement counts, and event timestamps. The separate /inbound/{email_id} detail endpoint has been removed.

  • Unified body, attachment, and raw endpoints. The /body, /attachment/{filename}, and /raw sub-resource endpoints now serve both inbound and outbound emails by ID. The /raw endpoint returns the original MIME bundle for inbound emails only (outbound emails do not retain a raw bundle and return 404). The separate /inbound/{email_id}/body, /inbound/{email_id}/attachment/{filename}, and /inbound/{email_id}/raw endpoints have been removed.

  • Peer address filter. The to_address filter on the list endpoint has been renamed to peer_address. For outbound emails it matches the recipient; for inbound emails it matches the sender. Set semantics (any match) are preserved.

  • Reply linkage filter. A new in_reply_to_email_id filter on the list endpoint lets you find emails that are replies to a specific outbound or inbound email.

  • Simplified send paths. The email send endpoint has moved from POST .../send to POST .../ on the email namespace. The iMessage send endpoint has similarly moved from POST .../send to POST .../ on the iMessage namespace. Request and response shapes are unchanged.

What you need to do:

  • Update any calls to the removed inbound endpoints. Replace calls to the /inbound, /inbound/{email_id}, /inbound/{email_id}/body, /inbound/{email_id}/attachment/{filename}, and /inbound/{email_id}/raw endpoints with the corresponding unified endpoints. Use the direction query parameter or the direction field on the response to distinguish inbound from outbound.

  • Update the to_address filter. If you use the to_address query parameter on the email list endpoint, rename it to peer_address.

  • Update send endpoint paths. If you call the email or iMessage send endpoints directly, update the path to remove the /send suffix.

  • Handle the discriminated response shape. The list and detail endpoints now return items with a direction field. Update your client models to handle both the inbound and outbound response variants.

v0.9.370 - Platform API: Inbound SMS via Channel Manager (July 2026)

Inbound SMS via Channel Manager

The platform now drives inbound SMS conversations end-to-end through the channel manager path, alongside the existing iMessage and email channels.

What changed:

  • Inbound SMS processing (channel-manager path). Inbound SMS messages arriving through the channel manager are now fully processed by the agent engine. Messages from the same caller on the same use case are serialized onto a single durable conversation, matching the session model used by iMessage. The agent's reply is delivered as plain text.

  • Distinct from classic SMS path. This channel-manager SMS path is keyed on the use case and uses the channel manager's sender pool. It is separate from the classic SMS service path, which routes inbound messages using phone number mappings and processes turns within the SMS service. Both paths coexist - the routing depends on how the inbound message arrives.

  • Session routing. Channel-manager SMS conversations use a routing key derived from the caller and use case, so repeat messages from the same caller on the same use case resume the existing conversation rather than starting a new one.

What you need to do:

  • To receive inbound SMS through the channel manager, create a use case service binding with channel sms for the relevant service. Inbound SMS messages matching the bound use case will be routed to the agent automatically.

  • No changes needed for existing SMS integrations. If you use the classic SMS service with phone number mappings, that path continues to work unchanged. The two SMS paths are independent.

v0.9.369 - Platform API: iMessage Inbound Turns and Proactive Outbound iMessage (July 2026)

iMessage Inbound Turns and Proactive Outbound iMessage

The platform now drives inbound iMessage conversations end-to-end and supports proactive (agent-initiated) iMessage sends through the outbound text endpoint.

What changed:

  • Inbound iMessage processing. Inbound iMessages are now fully processed by the agent engine. Messages from the same caller on the same use case are serialized onto a single durable conversation using a two-hour conversation window, matching the phone-shaped session model used by SMS. The agent's reply is delivered as plain text with no subject line or unsubscribe footer.

  • Proactive outbound iMessage. The /create_outbound_text endpoint now accepts channel_kind='imessage'. When set, the agent-initiated message is delivered through the channel's managed sender pool resolved from the use case. The use_case_id field is required when channel_kind is imessage.

  • Use case service binding channels expanded. Use case service bindings now accept sms and imessage as binding channels, in addition to the existing inbound_voice, outbound_voice, ringless_voicemail, and email channels. These bindings allow the channel service's inbound webhooks to resolve incoming SMS and iMessage turns to the correct workspace.

  • Use case list filter expanded. The channel query parameter on the list use cases endpoint now accepts sms and imessage as filter values.

What you need to do:

  • To receive inbound iMessages, create a use case service binding with channel imessage for the relevant service. Inbound iMessages matching the bound use case will be routed to the agent automatically.

  • To send proactive iMessages, call /create_outbound_text with channel_kind='imessage' and include the use_case_id of the use case whose sender pool should be used. The service_number field is not used for iMessage delivery.

  • Update client models if needed. If your client validates the binding channel enum or the channel_kind field, add sms and imessage as accepted values.

v0.9.368 - Platform API: Per-Tenant Intake Volume Routing (July 2026)

Per-Tenant Intake Volume Routing

Customer data intake uploads can now be routed to dedicated per-tenant storage volumes instead of the shared documents volume. Routing is controlled by a global configuration flag (default OFF) with an exclusion list for workspaces that need to remain on the legacy layout. No API changes are required for callers.

What changed:

  • Per-tenant volume routing. When enabled, new file uploads are written to a dedicated volume scoped to the workspace. Files are stored by date partition and file ID only - filenames and customer identifiers are not included in the storage path, reducing exposure of patient-identifiable information in storage infrastructure.

  • Global-on with exclusion list. When the global flag is ON, all workspaces route to per-tenant volumes except those on the exclusion list. The exclusion list holds workspaces whose downstream pipeline triggers still depend on the legacy storage layout and need coordinated re-pointing before they can move. Once a workspace's triggers are updated, it is removed from the exclusion list. The exclusion list is environment-agnostic - a workspace identifier that does not exist in a given environment is simply never matched, so the same list works across staging and production.

  • Backward-compatible reads. File downloads, metadata lookups, and deletions automatically resolve the correct storage layout based on the stored path. Files written under the previous shared-volume layout continue to work without modification or migration. A mixed state where some workspaces use per-tenant and others use shared is always safe.

  • No blob rewrite required. Existing files remain in place. The platform resolves both layouts transparently, so enabling per-tenant routing for new uploads does not affect access to historical files.

  • Startup validation. The intake volume configuration, including the exclusion list, is validated at service startup to catch misconfigurations before they affect uploads. Malformed workspace identifiers in the exclusion list are rejected at startup rather than silently ignored.

What you need to do:

  • No action required for existing integrations. The flag defaults to OFF and the exclusion list defaults to empty, so current behavior is unchanged. File upload and download APIs are unaffected.

  • To enable per-tenant routing for all workspaces, coordinate with your deployment team to ensure per-tenant volumes are provisioned before enabling the global flag. File-arrival triggers for downstream pipelines must also be updated to watch the new volume locations.

  • To hold specific workspaces on the legacy layout, add their workspace identifiers to the exclusion list before enabling the global flag. This keeps those workspaces on the shared layout until their pipeline triggers are re-pointed, while all other workspaces - including any newly created ones - automatically route to per-tenant volumes.

  • If you previously used the per-workspace allow-list, note that the routing model has changed from opt-in (allow-list) to opt-out (exclusion list). The global flag now controls the default for all workspaces, and only workspaces that cannot move yet need to be listed. Update your configuration accordingly.

v0.9.367 - Platform API: MMS as a First-Class Phone Number Capability (July 2026)

MMS as a First-Class Phone Number Capability

Phone number provisioning and search now surface MMS as a first-class capability alongside voice and SMS.

What changed:

  • MMS capability on phone numbers. Provisioned phone numbers now report mms in their capabilities list when the underlying number supports MMS. Previously, only voice and sms were tracked.

  • Search by MMS capability. The list available phone numbers endpoint now accepts mms in the capabilities filter. When specified, only numbers that support MMS are returned.

  • Capability set expanded. The phone number capability type now includes mms in addition to voice and sms. Existing numbers that support MMS will reflect this capability after re-provisioning or on new provisioning requests.

What you need to do:

  • No action required for existing integrations. Existing phone numbers continue to work as before. The mms capability will appear on newly provisioned numbers that support it.

  • To filter by MMS support, include mms in the capabilities parameter when searching for available phone numbers.

  • Update client models if needed. If your client strictly validates the capability enum, add mms as an accepted value.

v0.9.366 - Platform API: Inbound MMS Support and Attachment Access (July 2026)

Inbound MMS Support and Attachment Access

The SMS channel now supports receiving MMS messages with media attachments. Inbound media is persisted, exposed through the existing attachment endpoint, and forwarded to the agent as file content parts.

What changed:

  • Inbound MMS media handling. When an inbound SMS includes media (MMS), the platform downloads and stores each attachment. Media filenames and content types are preserved. The agent receives each attachment as a file content part alongside any text body.

  • body is now optional on inbound messages. A captionless MMS (media with no text) stores the body as null rather than an empty string, consistent with outbound MMS behavior.

  • attachment_names on inbound get-message response. The get-message response for inbound messages now includes an attachment_names field (array of strings) listing the filenames of any received media attachments.

  • num_attachments on inbound list-messages response. The list-messages response now includes a num_attachments field on inbound messages, reflecting the count of received media attachments. Previously, inbound messages always showed 0.

  • Attachment download works for inbound messages. GET /v1/sms/{sms_id}/attachment/{attachment_name} now supports both outbound and inbound messages. If the message ID matches an inbound message with the given attachment name, the endpoint returns a redirect to a short-lived download URL. Returns 404 if neither an outbound nor inbound message with that attachment is found.

  • is_mms filter applies to inbound messages. The is_mms query parameter on the list-messages endpoint now filters inbound messages by attachment presence, consistent with outbound filtering.

  • Inbound MMS media cleanup. After the inbound message is persisted and the agent turn is driven, the platform removes the provider-hosted copy of the media on a best-effort basis. The platform's own copy is retained for audit and retrieval.

What you need to do:

  • No action required for existing integrations. Text-only inbound SMS continues to work as before.

  • Update client models for nullable body. The body field on inbound messages is now nullable. If your client parses this field strictly, update your model to accept null values.

  • To access inbound attachments, use the existing GET /v1/sms/{sms_id}/attachment/{attachment_name} endpoint with the inbound message ID and attachment name from the attachment_names field.

v0.9.365 - Platform API: Outbound MMS Support on SMS Send (July 2026)

Outbound MMS Support on SMS Send

The SMS send endpoint now supports sending MMS messages with media attachments alongside or instead of text content.

What changed:

  • MMS support on POST /v1/sms/. The send endpoint now accepts multipart form data with optional media_attachments (up to 10 files per message). Including any media attachment sends the message as MMS. At least one of message (text body) or media_attachments is required.

  • body is now optional. The message field on the send request is no longer required. You can send a media-only MMS with no text body. The body field in responses is now nullable (null for media-only messages).

  • Attachment metadata on responses. The get-message response now includes an attachment_names field (array of strings) listing the filenames of any media attachments on the message.

  • num_attachments on list responses. The list-messages response now includes a num_attachments field (integer) on each outbound message, indicating how many media attachments are present.

  • New is_mms query filter. The list-messages endpoint accepts a new is_mms boolean query parameter to filter for messages with attachments (true) or text-only messages (false).

  • New attachment download endpoint. GET /v1/sms/{sms_id}/attachment/{attachment_name} returns a redirect to a short-lived download URL for a specific attachment on an outbound message. Returns 404 if the message or attachment name is not found.

  • Capability validation. MMS sends require at least one MMS-capable phone number in the sender pool. Text-only sends require at least one SMS-capable phone number. Sends return 422 if the pool lacks the required capability.

  • Attachment validation. Each attachment must have a valid filename (max 20 characters), be between 1 byte and 600 KB in size, and have a unique name within the message. Total message size (text body plus all attachments) must be under 5 MB. Invalid attachments return 422 with a descriptive error.

What you need to do:

  • No action required for existing SMS integrations. Text-only SMS sends continue to work as before. The body field is now nullable in responses - update your client models if you parse this field strictly.

  • To send MMS, switch your send request to multipart form encoding and include files in the media_attachments field. Ensure your sender pool includes at least one MMS-capable phone number.

  • To download attachments, use the new GET /v1/sms/{sms_id}/attachment/{attachment_name} endpoint. The response is a 307 redirect to a short-lived download URL.

v0.9.364 - Platform API: External-User Self-Approval for Conversations (July 2026)

External-User Self-Approval for Conversations

External users can now approve or reject a parked, approval-gated write in their own conversation without waiting for an operator to act through the review queue.

What changed:

  • New POST /v1/{workspace_id}/conversations/{conversation_id}/approval endpoint. External users can submit an approve or reject decision for a write that the agent paused for confirmation in their own conversation. The request body accepts a decision field (approve or reject) and an optional reason (1-512 characters). Returns 204 on success.

  • New conversations:approve_own scope. A new scope has been added to the set of scopes available for external user tokens. This scope is required to call the self-approval endpoint. It is included in the default external user scope set.

  • Ownership enforcement. Only the external user who owns the conversation can submit a decision. Requests for conversations owned by other users return 404. Requests from non-external-user tokens (API keys, role-based principals) return 403.

  • Durable decision recording. The decision is durably recorded and consumed by the agent on the conversation's next turn, consistent with the transport-agnostic approval resume behavior used by operator review.

  • 503 on store unavailability. If the decision store is temporarily unavailable, the endpoint returns 503 rather than 500, signaling that the request is safe to retry.

What you need to do:

  • No action required for existing integrations. This is a new endpoint and scope. Existing operator review-queue workflows are unaffected.

  • To enable self-approval for external users, ensure the external user token includes the conversations:approve_own scope. This scope is included in the default external user scope set, so tokens issued with default scopes already have it.

  • Client integration. To use self-approval, POST to the new endpoint with the external user's token when a parked write requires confirmation. The agent will consume the decision on the next turn.

v0.9.363 - Platform API: Patient-Facing URL on Surface GET Response (July 2026)

Patient-Facing URL on Surface GET Response

The GET surface endpoint now returns a url field containing a patient-facing link that operators can copy and share directly.

What changed:

  • New url field on surface responses. The GET surface response now includes a url field (string or null). The URL is minted on each read, so operators can retrieve and share the link from the read view without needing to re-create the surface.

  • Null when a URL cannot be generated. If the surface lacks the required entity or expiry information, or if the workspace is not configured for token minting, the url field is returned as null.

  • No changes to create or update. The url field is read-only and does not appear on create or update request bodies. It is computed on retrieval only.

What you need to do:

  • No action required. This is a non-breaking addition. Existing integrations will see the new url field in GET surface responses. You can use this field to display or share the patient-facing link directly from your application.

v0.9.362 - Platform API: Live Model Catalog Validation on Service Configuration (July 2026)

Live Model Catalog Validation on Service Configuration

Service create and update endpoints now validate model IDs in version set preferences against the set of models the platform account can actually serve. This catches within-family typos (such as a misspelled model variant) at configuration time rather than letting them degrade at runtime.

What changed:

  • Model ID validation against a live catalog. When you create or update a service with version_sets, the platform checks each model ID that routes through the primary LLM provider against a cached catalog of models the account can access. A model ID that is structurally valid (passes the prefix check) but does not appear in the catalog is rejected with 422 Unprocessable Entity. The error message lists the offending version set entries and model IDs.

  • Fail-open behavior. If the live catalog is temporarily unavailable (cold cache, transient infrastructure issue), the validation is skipped and the request falls back to the existing structural prefix check. A catalog gap never blocks a legitimate configuration write - this is important because writing a new-model configuration is how an operator adopts a just-released model.

  • Non-primary-provider models are unaffected. Models that route to other provider families are not covered by this catalog and continue to use the structural prefix gate only.

  • Background catalog refresh. The model catalog is refreshed automatically on a background loop. The cached catalog has a TTL significantly longer than the refresh interval, so a single failed refresh never expires the cache - readers keep the last-good set until a refresh succeeds.

What you need to do:

  • No action required for correctly configured services. If your version sets reference valid, currently-served model IDs, nothing changes.

  • Fix any typos in model IDs. If a service create or update starts returning 422 with a message about model IDs not served for your account, check the listed model IDs for typos or retired model variants. The error message identifies the exact version set entry and model ID that failed validation.

  • Newly released models. If you are adopting a model that was just released and the catalog has not refreshed yet, the validation will fail open (skip the catalog check) and allow the write. You do not need to wait for a catalog refresh.

v0.9.361 - Platform API: Cached Principal Resolution with Automatic Invalidation (July 2026)

Cached Principal Resolution with Automatic Invalidation

External principal resolution is now cached per workspace so that per-turn authorization checks during a conversation do not require a database read. Mutations to role assignments, role grants, and external roles automatically invalidate the workspace's cached principals, so changes take effect on the next conversation turn.

What changed:

  • Per-turn principal lookups are now cached. When a conversation turn resolves the session's external principal, the result is read from a short-lived per-workspace cache instead of the database. Cache misses trigger a database load and populate the cache for subsequent turns. Sessions without a principal (the normal patient path) also cache the no-principal result, avoiding unnecessary lookups.

  • Automatic invalidation on mutation. Creating, updating, or deleting a role assignment (via the External Role Assignments endpoints), creating or deleting a role grant (via the Role Grants endpoints), or deleting an external role (via the External Roles endpoints) now automatically invalidates all cached principals for the affected workspace. The next conversation turn re-resolves from the database and sees the updated state.

  • Fail-closed on cache unavailability. If the cache is temporarily unreachable, the platform falls back to a direct database load. Authorization decisions remain fail-closed - a cache miss never results in elevated access. Cache write failures are non-fatal and do not affect the mutating API request.

  • TTL-bounded staleness. Cached entries carry a short TTL. Even if an invalidation is missed due to a transient infrastructure issue, the cached principal expires and is refreshed within the TTL window.

What you need to do:

  • No action required. This is a transparent performance improvement. All existing API endpoints behave identically. Role assignment and grant mutations continue to return the same responses - the invalidation happens automatically after the mutation succeeds.

  • Suspensions and grant edits are now near-instant. Previously, a role assignment deletion or grant change could take effect only after a session was re-opened. Now, the change is visible on the very next conversation turn in any active session for the affected workspace.

v0.9.360 - Platform API: External Role Conflict Detection and Deletion Improvements (July 2026)

External Role Conflict Detection and Deletion Improvements

External role creation and role grant creation now return proper conflict responses when a duplicate is detected, and external role deletion correctly removes associated grants before deleting the role.

What changed:

  • Reliable conflict detection on role creation. Creating an external role with a name or external_name that already exists in the workspace now consistently returns 409 Conflict. Previously, certain database driver configurations could cause this to surface as a 500 instead of a clean conflict response.

  • Reliable conflict detection on grant creation. Creating a role grant that duplicates an existing active grant (same role, resource, and access level) now consistently returns 409 Conflict. Similarly, supplying a role_id that does not belong to the workspace consistently returns 422 Unprocessable Entity. Previously, these could intermittently surface as 500 errors.

  • External role deletion removes associated grants. Deleting an external role now removes all role grants associated with that role in the same operation. Previously, roles that had been granted access to resources could not be deleted because the grant records blocked removal, resulting in a 500 error. Grants are meaningless without their parent role, so they are cleaned up automatically as part of the delete.

What you need to do:

  • No action required for most users. If you have error-handling code that catches 500 errors on role or grant creation and treats them as duplicates, you can now rely on 409 consistently.

  • Role deletion is now safe for roles with grants. You no longer need to manually remove grants before deleting an external role. The delete operation handles this automatically.

v0.9.359 - Platform API: Channel Access Request Endpoint (July 2026)

Channel Access Request Endpoint

Workspaces can now request access to internal-preview channels (email, SMS, iMessage, WhatsApp) through the API. These channels are not self-serve provisionable - they require operator-managed enablement due to regulatory requirements or managed rollout. The new endpoint records the request and notifies the Amigo operator team to action it.

What changed:

  • New POST /channels/access-requests endpoint. Submit a request for operator enablement of an internal-preview channel. The endpoint accepts a channel field (one of email, sms, imessage, whatsapp) and an optional note field for context (use case, volume, timeline). Returns 202 Accepted with {"status": "received", "channel": "..."}. This endpoint does not provision anything - it hands off to the operator team for out-of-band enablement.

  • Low-privilege permission. The endpoint requires only Channel.view permission, since requesting enablement is informational and provisions nothing.

  • PHI safety. The note field is delivered to an operator channel outside the tenant boundary. Do not include patient data (PHI) in the note.

What you need to do:

  • No action required for existing workflows. This is a new endpoint. If you are building a console or portal that surfaces internal-preview channels, you can now offer a "Request access" action that calls this endpoint.

  • Ensure API keys carry Channel.view. Any API key used to call this endpoint must have a role with the Channel.view permission.

v0.9.358 - Platform API: Per-Workspace Speech-to-Text Provider Setting (July 2026)

Per-Workspace Speech-to-Text Provider Setting

Workspaces can now select a preferred speech-to-text provider for caller audio through voice settings. The platform honors the preference when the chosen provider is available and compatible with the call's language, and falls back to the default routing chain otherwise.

What changed:

  • New stt_provider field on voice settings. The voice settings request and response models now include an stt_provider field. Accepted values are "deepgram", "openai", and "cartesia". Setting the field to null (the default) inherits the deployment-default speech-to-text routing.

  • Graceful fallback. When the workspace's chosen provider cannot serve a call - because it does not support the caller's language or is temporarily unavailable - the platform falls through to the default provider chain automatically. A set-but-unusable preference never causes a transcription failure.

  • Operator audio unaffected. Clinical-staff (operator) audio always uses the default provider regardless of workspace preference.

What you need to do:

  • No action required. Existing workspaces default to null (inherit deployment default). To select a provider, update your workspace voice settings and set stt_provider to one of the accepted values.

v0.9.357 - Platform API: Trust Root Gate for Starting Conversations as External Principals (July 2026)

Trust Root Gate for Starting Conversations as External Principals

Starting a conversation anchored to an entity that has an active external role assignment now requires explicit permission and is audit-logged. This closes the trust root for the API-start path - workspace credentials can still anchor conversations to ordinary entities freely, but anchoring to a mapped external principal is treated as impersonation and gated accordingly.

What changed:

  • Permission gate on principal conversations. When a workspace credential creates a conversation with an explicit entity ID and that entity has an active external role assignment, the platform now checks for the Conversation.CreateForPrincipal permission. This permission is granted to admin and owner roles only. Credentials without this permission receive a 403 response.

  • Audit logging. When a principal session is opened through this path, the platform records a principal.session.opened audit event capturing the conversation ID, the acting credential, and the target entity ID.

  • No change for ordinary entities. Conversations anchored to entities without an active role assignment are unaffected. No additional permission is required, and no additional audit event is emitted.

  • No change for sessions without a principal. The normal patient conversation path (no entity ID or entity without a role assignment) behaves exactly as before.

What you need to do:

  • Verify credential roles. If you use workspace API keys to start conversations anchored to entities with external role assignments, ensure those keys carry admin or owner roles. Member, operator, and viewer credentials will now receive 403 on these requests.

  • No action for standard conversations. If you do not use external principals or do not anchor conversations to entities with role assignments, no changes are needed.

v0.9.356 - Platform API: External Principals - Entity-Anchored, Role-Scoped Tool Access (July 2026)

External Principals - Entity-Anchored, Role-Scoped Tool Access

The platform now supports external principals - a system for binding external user identities to workspace entities and scoping their agent sessions to specific tools, skills, and data based on assigned roles. This is designed for partner integrations where an end user (such as a clinician or care coordinator) drives conversations through the agent and should only access resources their role permits.

What changed:

  • Role registry. Workspaces can now define internal roles with normalized names that map to external role strings from the customer's identity system. Roles are workspace-scoped and unique.

  • Role assignments. An assignment record binds an external user (by subject key and optional subject ID) to a workspace entity with one or more internal roles. Assignments carry status (active, suspended, revoked), provisioning method (roster sync or just-in-time), and role verification state.

  • Role grants. Grants map a registry role to a specific resource (integration endpoint, skill, or knowledge base scope) with read or write access. Grants are immutable for audit - changes insert a new active row and mark the prior one as superseded.

  • Session principal resolution. When a session opens anchored to an entity with an active role assignment, the platform resolves a session principal carrying the user's identity, role union, allow-grants, and the workspace's restricted resource set. This happens once at session open.

  • Grant gating at tool dispatch. Restricted resources (any resource referenced by any active grant in the workspace) require the principal's roles to grant the required access level. Unrestricted resources remain workspace-open. Workspaces with no grants are unaffected.

  • Identity bindings on custom token exchange. Integration authors can now declare identity_bindings on custom token exchange authentication, mapping exchange parameters to the verified principal's identity attributes (principal.subject_key or principal.subject_id). Bound parameters are removed from the agent-facing tool schema, stripped from model-supplied parameters, and injected from the verified principal at dispatch. A missing principal value fails the call closed.

  • Param binding constraints on grants. Grants can carry an optional parameter binding that injects a principal attribute into call parameters at dispatch, enabling self-scoping (for example, restricting a provider ID parameter to the principal's own subject ID).

  • Entity conflict detection on session mint. The identity service now rejects session mint requests where the external subject key is already bound to a different entity, preventing silent identity rebinding through the session creation path.

What you need to do:

  • No action required for existing workspaces. Workspaces that do not define external roles or grants are completely unaffected. All tools and resources remain workspace-open.

  • To adopt external principals: Define internal roles in your workspace, create role assignments binding external users to entities, and author grants scoping roles to specific integration endpoints, skills, or knowledge base scopes.

  • Update custom token exchange integrations if you want to bind exchange parameters to the session principal's identity. Add identity_bindings to your integration's auth configuration, mapping parameter names to principal.subject_key or principal.subject_id. Each bound parameter name must reference a parameter already declared on the exchange's headers or body fields.

  • Handle new error responses. Session mint requests that attempt to rebind an external subject to a different entity now return a 400 error with error: "invalid_request" indicating the identity/entity conflict.

v0.9.355 - Platform API: Inline Malware Scanning for Intake Uploads (July 2026)

Inline Malware Scanning for Intake Uploads

The intake pipeline now supports inline malware scanning for all file uploads. When scanning is enabled, every uploaded file is scanned before it is written to storage. Infected files are rejected immediately and never persisted. The feature is config-gated and off by default - existing deployments are unaffected until scanning infrastructure is provisioned.

What changed:

  • Fail-closed scanning. When scanning is enabled, every intake upload (both HMAC-authenticated and link-based) is held in memory, scanned, and written to storage only after a clean verdict. If the scanner detects malware, the upload is rejected with a 422 response and nothing is persisted. If the scanner is unreachable or returns an error, the upload is rejected with a 503 response so the client can retry.

  • New error responses. Two new error conditions are surfaced on intake upload endpoints:

    • 422 Unprocessable Entity - returned when malware is detected in the uploaded file. The response body indicates that the upload was rejected by the malware scan.

    • 503 Service Unavailable - returned when the upload scanner is unreachable. This is a transient condition and the upload can be retried.

  • Scan status on upload records. Upload records now carry a scan status that reflects whether the file was scanned. When scanning is enabled and the file passes, the status is clean. When scanning is not enabled, the status remains skipped (unchanged from previous behavior).

  • No change when scanning is not enabled. When the scanning infrastructure is not provisioned (the default), the upload path behaves exactly as before. No new error codes are returned, and uploads are persisted with a skipped scan status.

What you need to do:

  • Handle new error codes. If you submit files to the intake upload endpoints, update your error handling to account for 422 responses indicating malware rejection and 503 responses indicating scanner unavailability. The 503 case is transient and should be retried.

  • No action required if scanning is not enabled. The feature is off by default. Existing integrations continue to work without changes until your deployment enables scanning.

v0.9.354 - Platform API: Intake Upload Filename Removed from Event Payload (July 2026)

Intake Upload Filename Removed from Event Payload

The intake pipeline no longer includes the filename in the intake.file.received event payload or entity state. Filename is treated as protected health information (PHI) and is now stored exclusively in the intake uploads ledger, which is workspace-scoped and access-controlled.

What changed:

  • Filename removed from event payload. The filename field has been removed from the intake.file.received event data. The event still includes customer_slug, content_type, sha256, size_bytes, and volume_path.

  • Entity lookup reads from the intake ledger. The intake uploads lookup tool now reads file metadata (filename, content type, size) from the intake uploads ledger rather than from entity state. All existing filters (filename search, MIME type, date range) continue to work. Date filters now use calendar-day granularity against the received timestamp.

  • No change to lookup response shape. The fields returned by the intake uploads lookup (entity_id, filename, mime_type, size_bytes, uploaded_at) are unchanged. Only the backing data source has moved.

What you need to do:

  • No action required for lookup consumers. If you query intake uploads through the agent's entity lookup tools, the response shape and filters are unchanged.

  • Update event payload consumers. If you consume intake.file.received events directly and rely on the filename field, note that it is no longer present. File metadata including the filename is available through the intake uploads lookup tool.

v0.9.353 - Platform API: Outbound Calls Now Require Use Case ID (July 2026)

Outbound Calls Now Require Use Case ID

Outbound call creation now requires a use_case_id. The legacy phone_from field and direct caller-ID override path have been removed. All outbound calls are now routed through the channel manager, which selects the optimal outbound phone number bound to the specified use case.

What changed:

  • use_case_id is now required. The use_case_id field on the create outbound call request is no longer optional. Every outbound call must specify which use case to route through. The channel manager selects the outbound phone number based on the use case binding.

  • phone_from removed. The phone_from field has been removed from the create outbound call request. You can no longer specify a direct caller ID override. All caller-ID resolution flows through the channel manager via use_case_id.

  • Mutual exclusion validator removed. The previous validation that required exactly one of phone_from or use_case_id has been removed since use_case_id is now the only accepted field.

  • Legacy phone number management endpoints removed. The phone number CRUD endpoints on the agent engine (POST /phone-numbers, GET /phone-numbers, GET /phone-numbers/by-number, GET /phone-numbers/{id}, PATCH /phone-numbers/{id}, DELETE /phone-numbers/{id}) have been removed. Phone number management is handled entirely through the channel manager.

  • Legacy inbound webhook removed. The legacy POST /twilio-webhook endpoint (without a use case ID path parameter) has been removed. Inbound call routing now uses the use-case-scoped webhook path exclusively.

  • platform.phone_numbers no longer queryable. The platform.phone_numbers table has been removed from the data query registry. If you were querying this table through the data query API, those queries will no longer work.

What you need to do:

  • Update outbound call requests. If you are creating outbound calls with phone_from, switch to use_case_id. Create a channel use case with the appropriate phone number binding, then pass that use case ID when initiating outbound calls.

  • Stop using legacy phone number endpoints. If you were managing phone numbers through the agent engine API, migrate to the channel manager use case and setup endpoints.

  • Update inbound webhook URLs. If your telephony provider is configured to send inbound calls to the legacy webhook URL (without a use case ID), update the webhook URL to include the use case ID path parameter.

  • Update data queries. If you have data queries referencing platform.phone_numbers, remove or replace them. Phone number data is managed through channel use cases.

v0.9.352 - Platform API: Inbound SMS and iMessage Now Drive Agent Turns Automatically (July 2026)

Inbound SMS and iMessage Now Drive Agent Turns Automatically

Inbound SMS and iMessage messages now automatically trigger an agent turn when they are received. Previously, inbound messages were persisted but required separate orchestration to start an agent turn. The platform now drives the turn as part of the same inbound processing, so the agent responds without additional coordination.

What changed:

  • SMS inbound messages drive agent turns. When an inbound SMS is received and persisted, the platform immediately drives an agent turn for the associated use case. The sender's phone number and message body are forwarded to the agent. If the turn cannot be driven (for example, due to a transient error), the inbound message is not persisted - the upstream provider retries delivery, and the next attempt re-runs cleanly. This guarantees that every persisted inbound SMS has a corresponding agent turn.

  • iMessage inbound messages drive agent turns. When an inbound iMessage is received, the platform persists the message (including any media attachments), then drives an agent turn for the associated use case. Text content and media references are forwarded to the agent. If the turn cannot be driven, both the message row and any stored media are rolled back, so the upstream provider retries delivery cleanly. Duplicate deliveries are detected before media is re-fetched or the turn is re-driven - a duplicate is acknowledged with no side effects.

  • Idempotency for iMessage improved. Duplicate iMessage deliveries are now detected with an early check before any media fetch or turn processing. Previously, deduplication relied on a database constraint at insert time. The new approach avoids redundant media downloads and turn attempts on redeliveries.

What you need to do:

  • No action required. If you have active SMS or iMessage use cases, inbound messages now produce agent responses automatically. No configuration changes are needed.

v0.9.350 - Platform API: Patient Memory Layer Removed (July 2026)

Patient Memory Layer Removed

The legacy patient memory layer has been removed from the Platform API. All memory-related endpoints and settings endpoints have been retired.

What changed:

  • Memory endpoints removed. The following endpoints are no longer available:

    • GET /v1/{workspace_id}/memory/analytics - workspace-level memory analytics

    • GET /v1/{workspace_id}/memory/{entity_id}/dimensions - entity dimension scores

    • GET /v1/{workspace_id}/memory/{entity_id}/facts - entity memory facts

  • Memory settings endpoints removed. The following endpoints are no longer available:

    • GET /v1/{workspace_id}/settings/memory - get memory dimension settings

    • PUT /v1/{workspace_id}/settings/memory - update memory dimension settings

  • Memory dimensions no longer configurable. The six built-in memory dimensions (clinical, behavioral, operational, social, engagement, risk) and support for custom dimensions have been removed. Workspace settings no longer accept a memory configuration block.

  • Data access tools updated. The platform's data query tools and agent runtime no longer reference patient memory tables or memory-related functions. Agent context that previously included memory snapshot and dimension summary functions has been updated accordingly.

What you need to do:

  • Remove any integrations that call memory endpoints. If your application calls any of the memory or memory settings endpoints listed above, remove those calls. These endpoints now return errors.

  • Remove memory settings configuration. If you manage workspace settings programmatically and include a memory configuration block, remove it. The platform ignores memory settings.

  • Update any agent function references. If your agent configurations reference memory-related platform functions (such as patient memory snapshot or patient dimension summary), remove those references. These functions are no longer available.

v0.9.349 - Platform API: Email Channel Production Hardening (July 2026)

Email Channel Production Hardening

The email channel now includes production hardening for graceful shutdown, backlog observability, and dead-letter recovery.

What changed:

  • Graceful drain on shutdown. When a pod begins shutting down (rolling deploy, scaling event), the email turn consumer stops claiming new inbound turns and allows any in-flight turn to finish within a bounded drain window. Work that was popped but not yet started is re-queued so successor instances pick it up without waiting for a redelivery sweep. This eliminates the previous behavior where a shutdown could hard-cancel a turn mid-processing.

  • Backlog depth gauges. The platform now periodically emits two operational gauges: the count of queued turn wake signals and the count of sessions with in-progress or queued work. A rising value in either gauge indicates that inbound turns are arriving faster than they are being processed - a backlog condition that per-turn liveness heartbeats alone cannot detect.

  • Dead-letter redrive tooling. Turns that exhaust their retry budget are dead-lettered with a durable event record carrying the full routing context (service, use case, session, caller, subject, and message references). An operator recovery tool can read this record, reconstruct a fresh processing item with a clean retry budget, release the original ingest claim, and re-enqueue the turn. The tool defaults to dry-run mode and requires an explicit flag to apply changes.

  • Enriched dead-letter event payload. The dead-letter event now carries additional routing fields (service, use case, caller reference, subject, and parent outbound reference), making the event self-describing and enabling the redrive tool to reconstruct the turn without external lookups.

  • Front-door drop counters. The ingest endpoint now emits counters when the idempotency claim or the work-list enqueue fails at the front door. These drops were previously invisible because they occur before the turn reaches the consumer's own metric series.

What you need to do:

  • No action required. These are internal reliability improvements. If you operate email channel workloads, the new backlog gauges and dead-letter redrive capability provide additional operational visibility and recovery options. No changes to request format, response format, or API surface.

v0.9.348 - Platform API: Entity Resolver Serving-Layer Cutover (July 2026)

Entity Resolver Serving-Layer Cutover

The entity resolve endpoint (POST /v1/{workspace_id}/world/entities/resolve) now reads from the platform's optimized serving projections instead of the legacy entity store. The response contract is unchanged, but three summary fields are narrowed to fixed defaults and the external-ID resolution path now uses point reads against the canonical entity map.

What changed:

  • Serving-layer cutover. Entity resolution now reads from the platform's deduplicated serving projections. The canonical_id and external_id identifier arms resolve through the canonical entity map with bounded point reads before the main entity lookup, replacing the previous scan-based approach. All other identifier arms (phone, email, entity_id) continue to match against indexed entity columns.

  • External-ID resolution uses canonical key forms. External-ID lookups now probe the canonical entity map using structured key forms derived from the system and value ({system}:Patient:{value}, {system}:Practitioner:{value}, {system}:Organization:{value}, {system}:Appointment:{value}, plus the bare value). Legacy external-ID aliases that were never minted as canonical keys are no longer resolvable.

  • Phone matching simplified. The phone identifier arm now matches against the typed phone column only. The previous fallback to demographic data within the entity state has been removed. In production, all phone values were already projected into the typed column, so this change is lossless.

  • Summary field narrowing (wire-compatible). Three fields on EntityResolveSummary are now fixed defaults:

    • external_ids is always {} - external aliases are managed through the canonical entity map, not carried on the entity row.

    • tags is always [] - the serving projection does not include tags.

    • canonical_id returns the canonical-map value when the entity was resolved through the map, otherwise the entity's MRN.

  • All existing fields and defaults are preserved. The response schema is unchanged. Clients that consume external_ids, tags, or canonical_id will see the documented default values rather than populated data.

What you need to do:

  • Review any logic that depends on external_ids in resolve responses. If you inspect summary.external_ids from resolve matches, note that it now always returns an empty object. External aliases are still used for resolution (via the canonical entity map), but they are not surfaced in the summary.

  • Review any logic that depends on tags in resolve responses. The summary.tags field now always returns an empty list.

  • Update external-ID resolution expectations. External-ID lookups now resolve through structured canonical key forms. If you have external aliases that were stored only in the legacy format and never minted as canonical keys, they will no longer resolve. Contact support if you encounter missing resolutions.

  • No changes to request format. The EntityResolveRequest body is unchanged. All identifier fields (phone, email, canonical_id, external_id, entity_id) continue to work as before.

v0.9.347 - Platform API: Durable Conversation Turn Counts (July 2026)

Durable Conversation Turn Counts

Text conversations now persist a turn count on the durable conversation record. Each inbound user message increments the count, providing accurate activity tracking for conversation lifecycle management and list ordering.

What changed:

  • Turn count persisted on the conversation record. Every time the agent processes an inbound user message in a text conversation, the platform writes the updated turn count to the durable conversation record. The write is monotonic - the stored count can only increase, so signal retries or session resumptions cannot regress it.

  • Activity touch on every turn. Each turn count write also updates the conversation's last-activity timestamp, keeping conversation list ordering and active/dormant lifecycle tracking aligned with real conversation activity rather than session-level events alone.

  • Fail-open persistence. If the durable turn count write fails (for example, due to a transient storage error), the conversation turn proceeds normally. The failure is logged and metered, but the user's message is still processed and the agent responds. Turn count accuracy may lag temporarily, but conversation flow is never interrupted by a persistence failure.

  • Accurate turn counting from session state. When a session resumes from persisted state, the turn count is derived from the actual inbound user messages in the interaction log rather than the raw entry count. This prevents internal state entries (such as tool responses or state markers) from inflating the turn count.

What you need to do:

  • No action required. This is an internal improvement to conversation activity tracking. If you consume conversation list or detail responses, the ordering and activity timestamps now reflect per-turn granularity rather than session-level events only.

v0.9.346 - Platform API: MCP Token-Workspace Binding Enforcement (July 2026)

MCP Token-Workspace Binding Enforcement

The MCP server now enforces that token-based credentials match the workspace specified in the request. Previously, a valid token issued for one workspace could be presented with a different workspace identifier, and the request would be accepted. The server now rejects any request where the token's workspace scope does not match the requested workspace.

What changed:

  • Workspace claim validation on MCP requests. When the MCP server receives a token-authenticated request, it verifies that the workspace encoded in the token matches the X-Workspace-Id header. If they differ, the server returns 403 Forbidden with a message indicating the token does not belong to the requested workspace.

  • Unscoped tokens are rejected. Tokens that are not scoped to a specific workspace - such as bootstrap tokens that have not been activated - are rejected with 403 Forbidden and a message indicating the token is not scoped to a workspace.

  • API-key authentication is unchanged. This change applies only to token-based (JWT) authentication on the MCP server. API-key-based MCP requests continue to work as before.

What you need to do:

  • Ensure your MCP client sends the correct workspace ID. If you connect to the MCP server using token-based authentication, verify that the X-Workspace-Id header matches the workspace the token was issued for. Requests with a mismatched workspace ID that previously succeeded will now return 403.

  • No action needed for API-key authentication. If you use API keys to authenticate MCP requests, no changes are required.

v0.9.345 - Platform API: Optional Sender Display-Name Alias on Email Use Cases (July 2026)

Optional Sender Display-Name Alias on Email Use Cases

Email channel use cases now support an optional sender display-name alias. When set, outbound emails render the From header as Display Name <address> instead of a bare address. This gives workspaces control over how the sender name appears to recipients without changing the verified sender address.

What changed:

  • New sender_email_alias field on email use cases. The create use case request accepts a new sender_email_alias field (string, 4-40 characters, nullable). When provided, the alias is rendered as the display name in the From header of outbound emails. When null, the From header contains only the sender email address with no display name. The field is required-nullable - callers must include it in the request body with either a string value or an explicit null.

  • Unicode display names are supported. The alias accepts any Unicode characters within the 4-40 character range. Non-ASCII names are encoded automatically in the outbound email headers per RFC 2047, so names like "Renee Cafe" render correctly in recipient mail clients.

  • Alias is immutable after creation. Like sender_email_address and email_type, the alias cannot be changed after the use case is created. To use a different display name, create a new use case.

  • Alias appears in all use case responses. The sender_email_alias field is included in create, get, and list use case responses. Existing use cases created before this change return null for the field.

What you need to do:

  • Update create use case requests. If you create email use cases through the API, add sender_email_alias to your request body. Set it to a display name string (4-40 characters) or null if you want a bare sender address.

  • Handle the new field in responses. If your code deserializes use case responses, account for the new sender_email_alias field (type: string | null).

v0.9.344 - Platform API: Audit Events Now Include Agent Engine Activity (July 2026)

Audit Events Now Include Agent Engine Activity

The audit events API now returns all audit activity, including events originating from the agent engine. Previously, only events written by the core platform were visible through the API. Agent engine audit events are now included in list, count, and aggregate responses.

What changed:

  • Agent engine audit events are now API-visible. Audit event queries now return events from all platform components, including the agent engine. Previously, these events existed in the audit ledger but were filtered out of API responses.

  • resource_type is now nullable. The resource_type field on audit event responses is now string | null instead of string. Agent engine events may not reference a specific resource, so this field can be null. The service and action fields remain non-nullable - all audit events carry both.

  • No changes to other response fields. All other fields on the audit event response (id, workspace_id, timestamp, service, actor_entity_id, actor_credential_id, action, resource_id, resource_name, ip_address) are unchanged.

What you need to do:

  • Handle nullable resource_type. If your code assumes resource_type is always a non-null string, update it to handle null values. This applies to any client that deserializes audit event responses or filters on resource_type.

  • Expect more audit events in responses. List and count queries may return more results than before because agent engine events are now included. If you paginate through audit events, your total counts may increase.

v0.9.343 - Platform API: Workspace-Scoped Channel Resources (July 2026)

Workspace-Scoped Channel Resources

SES setups and channel use cases are now scoped to the workspace that created them. Previously, these resources were visible platform-wide to any caller with the appropriate permission. With this release, each resource is owned by its creating workspace, and all list, get, verify, and delete operations are restricted to the owning workspace.

What changed:

  • SES setups are workspace-owned. When you create an SES setup, the platform records the creating workspace as the owner. List responses return only the setups your workspace owns. Get, verify, and delete requests for a setup owned by a different workspace return 404 - the response is indistinguishable from a nonexistent resource, so no information about other tenants' setups is leaked.

  • Channel use cases are workspace-owned. The same ownership model applies to channel use cases. Creating a use case records your workspace as the owner. List, delete, and service binding operations are scoped to owned use cases only. Attempting to bind a service to a use case owned by another workspace returns 404.

  • Fail-closed tenancy. If the ownership record cannot be stored after a successful create (for example, due to a transient error), the resource exists but is owned by no workspace. An unowned resource is invisible to all tenants and never appears in any workspace's list - it cannot leak across tenants. These orphaned resources are reconcilable by platform operators.

  • No changes to request or response schemas. All SES setup and use case endpoints accept and return the same fields as before. The only behavioral change is the tenancy scoping described above.

What you need to do:

  • Review cross-workspace workflows. If you previously relied on one workspace seeing SES setups or use cases created by another workspace, those resources are no longer visible. Each workspace must create its own setups and use cases.

  • No request changes required. Existing API calls continue to work. The workspace is inferred from the authenticated context - no new parameters are needed.

v0.9.342 - Platform API: Durable Connector Outcome Events (July 2026)

Durable Connector Outcome Events

The connector runner now emits durable outcome events for both write-back attempts and sync runs, replacing the previous behavior where outcomes were tracked only in transient metrics and short-lived cache keys.

What changed:

  • Write-back outcome events. Every write-back attempt to an external system now produces a durable outcome event recording whether the attempt completed or failed. On failure, the event includes a classification (permanent or transient) and a PHI-safe error code - vendor error messages that may contain patient data are never included. Per-sink isolation ensures that a failure writing to one external system does not prevent outcome recording for other systems.

  • Sync run outcome events. Each connector sync run now emits a durable outcome event with status (success or error), record counts (fetched and emitted), and run duration. On failure, the same PHI-safe classification and error code are included. This makes the short-lived cache key a cache over a durable record rather than the only record of sync activity.

  • Permanent rejections now propagate. Write-back handlers that previously swallowed permanent vendor rejections (HTTP 400/422) now propagate them so the outcome event is recorded. Per-sink isolation in the subscriber ensures other write targets still proceed.

  • Fail-open emission. Outcome event emission is fail-open - a lost outcome event never breaks the write-back or sync path. Failures to emit are metered separately.

What you need to do:

  • No action required. These are internal durability improvements. Connector behavior is unchanged from an integration perspective - write-backs remain at-most-once with no automatic retry. The durable outcome events provide better observability for connector operations.

v0.9.341 - Platform API: Email Use Case Inbox Posture Flags (July 2026)

Email Use Case Inbox Posture Flags

Creating an email channel use case now requires two additional fields that control unsubscribe behavior and inbound email acceptance. These fields were already enforced by the underlying channel infrastructure, but the public API was not passing them through, causing all email use case creation requests to fail.

What changed:

  • Two new required fields on email use case creation. unsubscribable (boolean) and accepts_cold_inbound (boolean) are now required when creating an email use case. unsubscribable controls whether sends carry RFC 8058 unsubscribe headers and honor per-use-case unsubscribe lists. accepts_cold_inbound controls whether inbound email that does not reply to an outbound message is accepted after spam and authentication gates. Setting accepts_cold_inbound to false restricts the inbox to thread-only replies.

  • Marketing use cases must be unsubscribable. If email_type is marketing and unsubscribable is false, the request is rejected with a validation error. Transactional use cases may set unsubscribable to false for must-send flows.

  • Both fields are returned on use case responses. The use case object returned by create and list endpoints now includes unsubscribable and accepts_cold_inbound for email use cases. These fields are null for non-email channels (voice, iMessage).

  • Fixes email use case creation. Previously, email use case creation through the public API failed because the required inbox posture fields were not forwarded to the channel infrastructure. This release fixes that path.

What you need to do:

  • Update email use case creation requests. Add unsubscribable and accepts_cold_inbound to your email use case creation payloads. Both are required booleans. If you are creating marketing use cases, unsubscribable must be true.

  • Update response parsing if needed. The use case response object now includes two new optional fields (unsubscribable and accepts_cold_inbound). If your integration strictly validates response shapes, update your model to accept these fields.

v0.9.340 - Platform API: Outbound Task ISO Validation and Dispatch Observability (July 2026)

Outbound Task ISO Validation and Dispatch Observability

Outbound task creation now validates scheduling timestamps at the boundary, and the dispatch pipeline surfaces more detail when post-call event emission fails.

What changed:

  • Scheduling timestamp validation. The scheduled_at and next_attempt_at fields on outbound task creation are now validated as ISO-8601 datetimes before the task is accepted. Previously, a malformed value was passed through and projected as a null timestamp in the downstream scheduling query, causing the task to silently never dispatch. The task now fails immediately with an error identifying which field is invalid and the value that was rejected.

  • Improved dispatch failure observability. When an outbound call is successfully placed but the post-call event cannot be emitted, the platform now emits a dedicated metric for claim-extension failures in addition to the existing dispatch-emission-failed metric. Log messages in this failure path now reference a reconciliation runbook for faster operator triage. These are internal observability improvements - no changes to API behavior or response schemas.

  • No changes to request or response schemas. All outbound task endpoints accept and return the same fields as before. The only behavioral change is that previously-accepted malformed timestamps now return an error.

What you need to do:

  • Check your scheduling timestamp values. If your integration passes scheduled_at or next_attempt_at values that are not valid ISO-8601 datetimes (for example, bare dates like 2026-07-15 without a time component, or freeform strings), those requests will now be rejected. Update your integration to send full ISO-8601 datetime strings (e.g. 2026-07-15T14:30:00Z).

  • No action required for well-formed timestamps. If your timestamps already include date, time, and timezone information, this change has no effect.