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
atlassession provider. The voice configuration now acceptsatlasas a session provider value alongside the existinginhouseand 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
atlasin 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
Reverted. This release was reverted in v0.9.395. Voice sessions now use the single-agent workflow model described above. The per-state gating behavior described below is no longer active.
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_transitionevent 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_startedandtool_call_completedevents 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 includeen,es,fr,de,pt,ar,zh,ja, andko. 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 forexternal_user.subject_keybindings - 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 theexternal_user.subject_keyattribute 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_valuesto 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
languageparameter 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 isen(English). Setting the value tomultilingualor an unmapped code removes the language restriction, allowing the agent to respond in multiple languages.Voice selection. Voice agents now accept a
voiceparameter 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
languagefield in the voice provider configuration to a supported language code.To change the agent's voice, set the
voicefield in the voice provider configuration.To enable multilingual responses, set
languagetomultilingualor 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, andage_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, andage_gated_contentto 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, andage_gated_content. Update your response parsing to handle these fields.
v0.9.387 - Platform API: SMS Opt-In Consent for US/CA Toll-Free Numbers (July 2026)
SMS Opt-In Consent for US/CA Toll-Free Numbers
The SMS opt-in and send flows now support US and Canadian toll-free numbers alongside the existing US A2P 10DLC long-code consent path. The opt-in endpoint sends from the matched compliance line rather than through the Messaging Service.
What changed:
Opt-in now supports toll-free numbers.
POST /v1/sms/opt-inresolves the opt-in copy and sender from whichever compliance artifact backs the SMS use case. If the use case has a verified A2P campaign with an assigned US long-code, the campaign's registered opt-in message is sent from that long-code. Otherwise, if the use case has an assigned US or Canadian toll-free number with an approved toll-free verification, the verification's opt-in confirmation message is sent from that toll-free line. If neither is present, the endpoint returns 422.Opt-in sends from the matched line. The opt-in message is now sent from the specific compliance line (
from_) rather than through the Messaging Service SID. This ensures the recipient sees the same number that will send future messages.Send gate expanded to toll-free.
POST /v1/sms/sendnow requires a recorded opt-in for US/CA toll-free sender pools in addition to US long-code pools. If the recipient has no opt-in record for the use case and the sender pool contains US/CA toll-free or US long-code numbers, the endpoint returns 422.Updated 422 descriptions. The 422 error descriptions for both endpoints now reflect the broader consent requirement covering both US/CA toll-free and US long-code sender pools.
What you need to do:
Send opt-in before messaging from toll-free numbers. If your SMS use case sends from US or Canadian toll-free numbers, call
POST /v1/sms/opt-infor each recipient before sending messages. This was previously only required for US long-code (A2P 10DLC) sender pools.No changes needed for existing A2P workflows. If you already send opt-in messages for US long-code use cases, those workflows continue to work as before.
No changes needed for international or Canadian long-code pools. Canadian long-codes and international numbers are not subject to the opt-in gate.
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 abusiness_typefield 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 everybusiness_typeexceptSOLE_PROPRIETOR, all three business registration fields are required.business_registration_numberis the legally recognized registration number (max 64 characters).business_registration_authorityis 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_countryis the ISO 3166-1 alpha-2 country code of registration.Conditional validation. Submitting a
business_typeother thanSOLE_PROPRIETORwithout 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, andbusiness_registration_country(null whenbusiness_typeisSOLE_PROPRIETOR).
What you need to do:
Add
business_typeto 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_typeis anything other thanSOLE_PROPRIETOR, includebusiness_registration_number,business_registration_authority, andbusiness_registration_countryin your submission.Update integrations that read verification responses. The response now includes
business_type,business_registration_number,business_registration_authority, andbusiness_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/filestoPOST /v1/{workspace_id}/intake/files/externalto 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 toPOST /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_provideron agents. Agent voice configuration now accepts an optionalsession_providerfield. Accepted values areinhouse(the default audio pipeline) andopenai_realtime(speech-to-speech runtime). When set, this overrides the global default for calls handled by that agent. Whennullor omitted, the agent inherits the global setting.New field:
voice_config.session_provideron services. Service voice configuration now accepts the same optionalsession_providerfield. This is the highest-precedence tier - when set, it overrides both the agent-level and global settings. Whennullor 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
nullor 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_providertoinhouseoropenai_realtimeon 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, orbusiness_contact_phone. Theadditional_informationfield 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_informationremains 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. TheIMPORTopt-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,000and10,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 either5,000,000or10,000,000+depending on your actual volume.No action needed for opt-in types unless you want to use the new
IMPORTopt-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 anopt_in_confirmation_messagefield (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_messagefield 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_messagein 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_messagefield.
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_outfield removed. The opt-in resend request no longer accepts thereverses_opt_outboolean field. Previously, setting this totrueallowed 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_outfrom opt-in resend requests. If your integration passesreverses_opt_outin the request body, remove it. The field is no longer accepted.Update opt-out handling workflows. If you relied on
reverses_opt_out=trueto 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:
temperaturefield on skills. Skills now accept an optionaltemperaturefield (number, 0-1) on create and update. Controls sampling temperature for the skill's model. Returned in skill responses.top_pfield on skills. Skills now accept an optionaltop_pfield (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
temperatureortop_p. If both are provided, the runtime keepstemperatureand dropstop_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
temperatureortop_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_keybinding. Custom token exchange integrations can now bind a declared auth parameter toexternal_user.subject_keyin addition to the existingprincipal.subject_keyandprincipal.subject_idpaths. 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_keyfield (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 aprincipal.*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_bindingsfield on custom token exchange auth configuration now acceptsexternal_user.subject_keyas a valid binding target alongside the existingprincipal.subject_keyandprincipal.subject_idvalues.
What you need to do:
To use the new binding: Update your integration's
identity_bindingsto map a declared param name toexternal_user.subject_key. Ensure that external-user session tokens are issued with a subject key (theexternal_subject_keyfield 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_outfield on opt-in request. The send opt-in message endpoint now requires areverses_opt_outboolean. Whentrueand the recipient has a live opt-out (a prior STOP), the opt-out is reversed before the opt-in message is sent. Whenfalseand 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_outis 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_outto opt-in requests. The field is required. Set it totruewhen you intend to re-subscribe a contact who previously sent STOP. Set it tofalseif 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_outwas 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_keyparameter 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_inremoved from submit request. The A2P campaign submit endpoint no longer acceptssubscriber_opt_inas a request field. The platform always sets subscriber opt-in to true when registering the campaign.subscriber_opt_inremoved from campaign response. The A2P campaign response no longer includessubscriber_opt_in. All campaigns are treated as having subscriber opt-in.opt_in_messageis always required. Theopt_in_messagefield was already required, but its role is now clearer: the platform sendsopt_in_messageto a recipient as the first message before any other message on the use case, so every campaign must carry it.opt_in_keywordsclarified. Theopt_in_keywordsfield 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_infrom campaign submit requests. If your integration sendssubscriber_opt_inwhen submitting A2P campaigns, remove it. The field is no longer accepted.Update response parsing. If your code reads
subscriber_opt_infrom 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:
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):
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
directionfield on each item. You can filter to one direction with the optionaldirection=inbound|outboundquery parameter. The separate/inboundlist 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/rawsub-resource endpoints now serve both inbound and outbound emails by ID. The/rawendpoint 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}/rawendpoints have been removed.Peer address filter. The
to_addressfilter on the list endpoint has been renamed topeer_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_idfilter 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 .../sendtoPOST .../on the email namespace. The iMessage send endpoint has similarly moved fromPOST .../sendtoPOST .../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}/rawendpoints with the corresponding unified endpoints. Use thedirectionquery parameter or thedirectionfield on the response to distinguish inbound from outbound.Update the
to_addressfilter. If you use theto_addressquery parameter on the email list endpoint, rename it topeer_address.Update send endpoint paths. If you call the email or iMessage send endpoints directly, update the path to remove the
/sendsuffix.Handle the discriminated response shape. The list and detail endpoints now return items with a
directionfield. 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
smsfor 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_textendpoint now acceptschannel_kind='imessage'. When set, the agent-initiated message is delivered through the channel's managed sender pool resolved from the use case. Theuse_case_idfield is required whenchannel_kindisimessage.Use case service binding channels expanded. Use case service bindings now accept
smsandimessageas binding channels, in addition to the existinginbound_voice,outbound_voice,ringless_voicemail, andemailchannels. 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
channelquery parameter on the list use cases endpoint now acceptssmsandimessageas filter values.
What you need to do:
To receive inbound iMessages, create a use case service binding with channel
imessagefor the relevant service. Inbound iMessages matching the bound use case will be routed to the agent automatically.To send proactive iMessages, call
/create_outbound_textwithchannel_kind='imessage'and include theuse_case_idof the use case whose sender pool should be used. Theservice_numberfield is not used for iMessage delivery.Update client models if needed. If your client validates the binding channel enum or the
channel_kindfield, addsmsandimessageas 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
mmsin their capabilities list when the underlying number supports MMS. Previously, onlyvoiceandsmswere tracked.Search by MMS capability. The list available phone numbers endpoint now accepts
mmsin thecapabilitiesfilter. When specified, only numbers that support MMS are returned.Capability set expanded. The phone number capability type now includes
mmsin addition tovoiceandsms. 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
mmscapability will appear on newly provisioned numbers that support it.To filter by MMS support, include
mmsin thecapabilitiesparameter when searching for available phone numbers.Update client models if needed. If your client strictly validates the capability enum, add
mmsas 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
filecontent part alongside any text body.bodyis 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_nameson inbound get-message response. The get-message response for inbound messages now includes anattachment_namesfield (array of strings) listing the filenames of any received media attachments.num_attachmentson inbound list-messages response. The list-messages response now includes anum_attachmentsfield 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_mmsfilter applies to inbound messages. Theis_mmsquery 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. Thebodyfield 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 theattachment_namesfield.
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 optionalmedia_attachments(up to 10 files per message). Including any media attachment sends the message as MMS. At least one ofmessage(text body) ormedia_attachmentsis required.bodyis now optional. Themessagefield on the send request is no longer required. You can send a media-only MMS with no text body. Thebodyfield in responses is now nullable (null for media-only messages).Attachment metadata on responses. The get-message response now includes an
attachment_namesfield (array of strings) listing the filenames of any media attachments on the message.num_attachmentson list responses. The list-messages response now includes anum_attachmentsfield (integer) on each outbound message, indicating how many media attachments are present.New
is_mmsquery filter. The list-messages endpoint accepts a newis_mmsboolean 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
bodyfield 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_attachmentsfield. 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}/approvalendpoint. 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 adecisionfield (approveorreject) and an optionalreason(1-512 characters). Returns 204 on success.New
conversations:approve_ownscope. 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_ownscope. 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
urlfield on surface responses. The GET surface response now includes aurlfield (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
urlfield is returned asnull.No changes to create or update. The
urlfield 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
urlfield 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 with422 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
422with 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
nameorexternal_namethat already exists in the workspace now consistently returns409 Conflict. Previously, certain database driver configurations could cause this to surface as a500instead 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 arole_idthat does not belong to the workspace consistently returns422 Unprocessable Entity. Previously, these could intermittently surface as500errors.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
500error. 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
500errors on role or grant creation and treats them as duplicates, you can now rely on409consistently.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-requestsendpoint. Submit a request for operator enablement of an internal-preview channel. The endpoint accepts achannelfield (one ofemail,sms,imessage,whatsapp) and an optionalnotefield for context (use case, volume, timeline). Returns202 Acceptedwith{"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.viewpermission, since requesting enablement is informational and provisions nothing.PHI safety. The
notefield 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 theChannel.viewpermission.
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_providerfield on voice settings. The voice settings request and response models now include anstt_providerfield. Accepted values are"deepgram","openai", and"cartesia". Setting the field tonull(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 setstt_providerto 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.CreateForPrincipalpermission. This permission is granted to admin and owner roles only. Credentials without this permission receive a403response.Audit logging. When a principal session is opened through this path, the platform records a
principal.session.openedaudit 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
403on 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_bindingson custom token exchange authentication, mapping exchange parameters to the verified principal's identity attributes (principal.subject_keyorprincipal.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_bindingsto your integration's auth configuration, mapping parameter names toprincipal.subject_keyorprincipal.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
400error witherror: "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
422response and nothing is persisted. If the scanner is unreachable or returns an error, the upload is rejected with a503response 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 remainsskipped(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
skippedscan 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
422responses indicating malware rejection and503responses indicating scanner unavailability. The503case 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
filenamefield has been removed from theintake.file.receivedevent data. The event still includescustomer_slug,content_type,sha256,size_bytes, andvolume_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.receivedevents directly and rely on thefilenamefield, 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_idis now required. Theuse_case_idfield 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_fromremoved. Thephone_fromfield 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 viause_case_id.Mutual exclusion validator removed. The previous validation that required exactly one of
phone_fromoruse_case_idhas been removed sinceuse_case_idis 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-webhookendpoint (without a use case ID path parameter) has been removed. Inbound call routing now uses the use-case-scoped webhook path exclusively.platform.phone_numbersno longer queryable. Theplatform.phone_numberstable 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 touse_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 analyticsGET /v1/{workspace_id}/memory/{entity_id}/dimensions- entity dimension scoresGET /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 settingsPUT /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
EntityResolveSummaryare now fixed defaults:external_idsis always{}- external aliases are managed through the canonical entity map, not carried on the entity row.tagsis always[]- the serving projection does not include tags.canonical_idreturns 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, orcanonical_idwill see the documented default values rather than populated data.
What you need to do:
Review any logic that depends on
external_idsin resolve responses. If you inspectsummary.external_idsfrom 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
tagsin resolve responses. Thesummary.tagsfield 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
EntityResolveRequestbody 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-Idheader. If they differ, the server returns403 Forbiddenwith 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 Forbiddenand 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-Idheader 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_aliasfield on email use cases. The create use case request accepts a newsender_email_aliasfield (string, 4-40 characters, nullable). When provided, the alias is rendered as the display name in the From header of outbound emails. Whennull, 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 explicitnull.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_addressandemail_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_aliasfield is included in create, get, and list use case responses. Existing use cases created before this change returnnullfor the field.
What you need to do:
Update create use case requests. If you create email use cases through the API, add
sender_email_aliasto your request body. Set it to a display name string (4-40 characters) ornullif 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_aliasfield (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_typeis now nullable. Theresource_typefield on audit event responses is nowstring | nullinstead ofstring. Agent engine events may not reference a specific resource, so this field can benull. Theserviceandactionfields 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 assumesresource_typeis always a non-null string, update it to handlenullvalues. This applies to any client that deserializes audit event responses or filters onresource_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) andaccepts_cold_inbound(boolean) are now required when creating an email use case.unsubscribablecontrols whether sends carry RFC 8058 unsubscribe headers and honor per-use-case unsubscribe lists.accepts_cold_inboundcontrols whether inbound email that does not reply to an outbound message is accepted after spam and authentication gates. Settingaccepts_cold_inboundtofalserestricts the inbox to thread-only replies.Marketing use cases must be unsubscribable. If
email_typeismarketingandunsubscribableisfalse, the request is rejected with a validation error. Transactional use cases may setunsubscribabletofalsefor must-send flows.Both fields are returned on use case responses. The use case object returned by create and list endpoints now includes
unsubscribableandaccepts_cold_inboundfor email use cases. These fields arenullfor 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
unsubscribableandaccepts_cold_inboundto your email use case creation payloads. Both are required booleans. If you are creating marketing use cases,unsubscribablemust betrue.Update response parsing if needed. The use case response object now includes two new optional fields (
unsubscribableandaccepts_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_atandnext_attempt_atfields 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_atornext_attempt_atvalues that are not valid ISO-8601 datetimes (for example, bare dates like2026-07-15without 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.

