Skip to main content
PUT

Path Parameters

string
required
The unique identifier of the agent (UUID format)

Request Body

All fields are optional. Only include the fields you want to update.
Reads and writes use different field names. GET /v1/agents/{id} returns the stored row with snake_case top-level keys (for example system_prompt), while this endpoint takes the camelCase names documented below (for example systemPrompt). Rename the top-level keys before sending a read back — see reservationConfig below for what happens otherwise; keys inside nested objects such as voiceSettings and config stay snake_case. email also changes shape: send it as an array of addresses, but GET returns it as the stored string.
string
Optional organization guard (UUID). When provided, the request is rejected with 404 unless the target agent already belongs to this organization. It does not move the agent between organizations — it only scopes the update so you cannot accidentally modify an agent in a sibling organization under the same account. Omit it to keep the default account-scoped behavior.

Basic Information

string
Display name of the agent (1-255 characters)
string
Description of what the agent does
string
Initial message the agent says when call starts
string
Greeting spoken when this agent places an outbound call (see Outbound Calls)
string
System prompt defining agent behavior and personality
string
Type of agent configuration.Supported values: simple, advanced, custom, appointment_scheduler, receptionist, message_taker, blank_slate, outbound, opentable_reservation, translator
object
Restaurant settings for an opentable_reservation agent, in the shape documented on Create Agent. Ignored by every other agent type.Sent as a whole object: the value replaces the stored settings rather than merging into them, so read the agent first and send back the full object with your change applied. Omitting the field leaves the stored settings untouched.
The read and the write use different key names. GET /v1/agents/{id} returns the stored row, where this object is called reservation_config (snake_case). This endpoint accepts only reservationConfig (camelCase), and rejects any top-level key it does not recognise.A literal read-modify-write therefore fails with 400 "Invalid request data", with a details entry whose code is unrecognized_keys, and nothing is saved:
The same asymmetry applies to amd_config / amdConfig.
Changing restaurant_url without also updating restaurant_id leaves the agent checking the previous restaurant’s availability and texting a link that books a table there. Resolve the new URL to its ID and send both together.
object
Interpreter settings for a translator agent, in the shape and with the rules documented on Create Agent. Validated and stored whenever sent, on any agent type; it only has an effect on a translator agent.The object is sent whole: its value replaces the stored settings rather than merging into them, and it is validated as a complete configuration. Read the agent first, then send back the full object with your change applied. Omitting interpreterConfig leaves the stored settings untouched.Sending interpreterConfig: null clears the stored settings on an agent that is not a translator. On a translator agent (or in a request that changes agentType to translator), null is rejected with required, at path: ["interpreterConfig"].
  • Changing agentType to translator needs valid settings, either in this request or already stored on the agent; if no settings are sent and none are stored, the request is rejected with required, at path: ["interpreterConfig"]. Settings that break a rule are rejected with that rule’s code, at that setting’s own path.
  • Changing agentType to translator also sets detached: true on the agent, the same as creating a translator does. Re-sending translator for an agent that already is one leaves detached as it is.
  • On a translator agent, and in a request that changes agentType to translator, the on/off settings a translator does not use are stored off whatever the request sends and whatever the agent had stored: ragEnabled, transferEnabled, warmTransferEnabled, webTransferEnabled, emailToolEnabled, echoDetection, detectAutomatedCallers, callDetection, screenshareEnabled, and background_audio_enabled, thinking_sounds_enabled and response_filler_enabled inside config (its other keys are kept). A Mobile_Call_Detection tool in extensions.tools is dropped; other tools are kept.
  • Changing agentType away from translator leaves the stored settings untouched and unused, and those on/off settings stay off until you turn them on.
  • Switching to translator on this endpoint gets none of the other template defaults a POST applies. If the agent’s stored ttsModel is not already cartesia, send ttsModel: "cartesia" in the same request, or it is rejected with voice_provider.
  • On a translator agent, when this request sends voiceSettings or ttsModel, or switches the agent to translator, a Cartesia voice model (voiceSettings.model) that is missing or outside the sonic-3 family (sonic-3 or sonic-3.6; anything else, for example the retired sonic-2 or sonic-3.5) is set to sonic-3 (and a missing voice_id gets the template voice), rather than the request being rejected.
  • A translator agent’s ttsModel must be cartesia; any other value is rejected with voice_provider, at path: ["ttsModel"] — not under interpreterConfig, because it validates ttsModel, not the interpreter settings.
  • On a translator agent, language is set to the Party A language whenever the agent’s interpreter settings are valid (the interpreterConfig in this request, or else the stored settings), even when the request also sends its own language. For an agent that is already a translator, if no interpreterConfig is sent and the stored settings no longer pass validation, language is not changed by them, and the request’s own language (if any) is saved. Switching an agent to translator with stored settings that no longer pass validation is rejected instead, as above.
The read and the write use different key names. GET /v1/agents/{id} returns this object as interpreter_config (snake_case). This endpoint accepts only interpreterConfig (camelCase) and rejects any top-level key it does not recognise, so sending interpreter_config back fails with 400 "Invalid request data", with a details entry whose code is unrecognized_keys. The keys inside the object are snake_case in both directions.
string
Agent activation status.Supported values:
  • active - Agent is available to receive calls
  • inactive - Agent is temporarily disabled
  • cancelled - Agent is permanently disabled
  • pending - Agent is pending activation
To switch between active and inactive on their own, use Update Agent Status — it takes just this field, so there is no risk of overwriting other configuration.

AI/Voice Model Configuration

string
AI model used for the agent. See List LLM Models for the full list with descriptions.Supported values: gpt-4.1 (recommended, can never be locked out), gpt-4o, gpt-4o-mini, gpt-4.1-mini, gpt-4.1-nano, grok-3-fast, moonshotai/Kimi-K2.6, google/gemma-4-31b-it, claude-sonnet-4-6A Partner or Reseller can lock individual models for an organization via Feature Administration. Switching model to one that is locked is rejected with 403 forbidden — but re-sending the agent’s current model always succeeds even if it has since become locked, so a plain read-modify-write round trip never breaks and an agent already on a since-locked model keeps running.
string
Voice model for real-time speech
string
Speech-to-text model.Supported values: deepgram
string
Text-to-speech model.Supported values: cartesia, minimax, inworldWhen Feature Administration is enabled, changing to a provider locked for the organization is rejected with 403 forbidden — but re-sending the agent’s current provider is always allowed, so a read-modify-write round trip keeps working. cartesia can never be locked.For inworld, set voiceSettings.voice_id to a full Inworld voice string, e.g. Inworld.TTS2.Ashley.
object
Voice configuration settings. Structure varies based on ttsModel:For Cartesia:
Cartesia voices also accept two optional fields:
A custom (cloned) voice_id runs on the sonic-3 family (sonic-3 or sonic-3.6). An omitted model counts as sonic-3, and a retired sonic-2 or sonic-3.5 is saved as sonic-3.
English Cartesia voices accept a model override but not a language override. Non-English voices (e.g. Spanish) require both:
For MiniMax:
Advanced Voice Timing (optional, applies to all TTS models):Example with advanced timing:

Call Features

boolean
Whether SIP call transfer is enabled. Supports:
  • SIP extensions: sip:extension@hostname
  • US phone numbers: Automatically formatted to tel:+1XXXXXXXXXX
boolean
Whether the agent can send emails during or after calls
string
Instructions for the agent on how and when to use the email tool
boolean
Mobile calls detection: look up whether the caller’s number is a mobile phone before the call starts. This is not answering machine detection — see amdConfig under Outbound Calling.
boolean
Let a caller on the web-embedded agent be transferred. Stored as false whenever transferEnabled is false. An update that turns transferEnabled on without sending this field turns web transfer on too; a GET-then-PUT that re-sends transferEnabled: true never overwrites a stored false.
boolean
Whether to enable echo detection during calls
boolean
Enable call recording. Recordings are saved to cloud storage and accessible via the Call Logs API.
Include a link to the call recording in the post-call summary notification. This is a sub-option of call recording — it requires recording to be enabled (enableRecording: true in this request, or already enabled on the agent). Sending true while recording is not enabled returns a 400. Note: the link is delivered via the call-summary email, so it is only actually sent when the agent also has an email recipient configured and a recording was produced; otherwise the flag is stored but has no effect.
string
Rules and conditions for call transfers. Describes when and where the agent should transfer calls.Example: "Transfer to +15551234567 if the caller asks for billing support. Transfer to +15559876543 for technical issues."
array
Array of email addresses used for notifications and the email tool.Example: ["[email protected]", "[email protected]"]Note that GET /v1/agents/{id} returns this field as the stored string, not an array.
string | null
UUID of the email server to use for this agent. Must belong to the same account. Pass null to revert to the account’s default email server.Use the List Email Servers endpoint to retrieve available IDs.
boolean
Whether this agent can ask a web-embedded caller to share their screen and reason about what it sees. See Screenshare. Ignored for SIP/PSTN calls, which have no browser to share.Only the off → on transition is gated: re-sending a stored true is never blocked, and turning it off always succeeds. Turning it on returns 403 forbidden when:
  • Screenshare is locked for the organization via Feature Administration,
  • the resulting model — this request’s model if given, otherwise the agent’s current one — cannot read images, or
  • the organization is flagged Healthcare, which can never opt in to Screenshare.
A model change on this same request is refused with the same error if it would leave an agent whose screenshare is (or is being set) on using a model that can’t read images, unless this same request also sets screenshareEnabled: false.

Localization

string
Agent language for speech recognition and responses.Supported values:
  • en-US - English (US)
  • es-US - Spanish (US)
  • multi - Multilingual (English, Spanish, French, German, Hindi, Russian, Portuguese, Japanese, Italian, Dutch)
string
Agent timezone in IANA format. Used for date/time operations and calendar scheduling.Example: "America/New_York", "Europe/London", "Asia/Tokyo"

Knowledge Base

Array of URLs the agent can reference for knowledge. The content at these URLs is ingested and made available to the agent during conversations.Example: ["https://example.com/faq", "https://example.com/pricing"]

RAG Knowledge Base

boolean
Enable live vector search during calls. The account and the agent’s organization must both have Knowledge Base (RAG) enabled, otherwise the API returns 403 forbidden.
string | null
Organization-level knowledge base ID for the agent to search. The knowledge base must belong to the same organization as the agent. Set to null to remove the assignment.Use List Knowledge Bases to retrieve available IDs.
object
RAG retrieval configuration. Unknown keys are rejected.

Business (Google Place)

string | null
Google Place ID linking the agent to a Google Business Profile listing. The platform fetches the listing’s details (hours, location, phone, website, services, ratings) and the agent uses them as verified facts when answering callers.
  • Set to a Place ID to link (or relink) the agent’s business.
  • Set to null or "" to unlink.
  • Changing or clearing the id also clears the cached listing data (google_place_data, google_place_context, google_place_fetched_at), so details from the previously linked business are never served while the new listing is fetched. Re-sending the already-stored id is a no-op and keeps the cache.
Example: "ChIJVS6XxJPFU4gRoE8c8ql2lCQ"

Warm Transfer

boolean
Enable warm transfer routing for this agent.
string
What the AI says to the human agent on the consult leg of a warm transfer. Blank uses the built-in briefing. See Warm Transfer.
string
Plain-language rules for when and where to warm transfer. Example: "If the caller asks for billing, confirm first and warm transfer to pbx:1234."
string
Public URL of the hold-music file played during warm transfer. The easiest way to set this is Upload Hold Music, which saves the URL for you. Leave empty for built-in hold music.
boolean
Whether the original caller’s number is passed to the transfer destination. Defaults to true.

Pronunciations

array
Custom pronunciation rules for specific words and names in IPA format. Replaces the entire pronunciations list for the agent.
Custom pronunciations are supported on Inworld voices, Cartesia voices using the sonic-3 or sonic-3.6 model, and MiniMax voices on English agents only. They are not supported on Cartesia sonic-2, nor on MiniMax when the effective language is es-US or fr-FR — MiniMax accepts pronunciation phonemes for English only and mis-renders Spanish and French. A non-empty pronunciations array is rejected with 400 unless the agent’s effective voice is ttsModel: minimax, ttsModel: inworld, or ttsModel: cartesia with a sonic-3-family voiceSettings.model (taking either the values in this request or the agent’s existing settings; an unset model does not count). A retired sonic-2 sent in this request is saved as sonic-3 first and is accepted; a sonic-2 already stored on the agent is not. Send an empty array [] to clear rules on any voice.You store each pronunciation once and it works on any supported voice, provided it was generated with Apply — the phonemes must be IPA in Cartesia’s <<…>> form. Hand-typed free-text phonemes work on Cartesia only and are silently ignored on MiniMax and Inworld, and rules generated for a Spanish or French voice are ignored on MiniMax. Multi-word entries such as New York work on Cartesia but are ignored on MiniMax and Inworld, whose syntax covers a single word each.Each entry also accepts an optional lang (en | es | fr) recording which language the phonemes were written for. It decides whether MiniMax can speak the row — MiniMax accepts English phonemes only. Omit it and the agent’s language is used as the fallback.
Each entry is an object with:
  • word — The word or name (1–100 characters)
  • phonetic (optional) — A plain-English respelling of how the word should sound (e.g., jay-kob-sen). Used by the dashboard’s “Apply” helper to generate the IPA phonemes; not used directly by the agent.
  • phonemes — The IPA phoneme string
  • lang (optional) — en | es | fr. Which language the phonemes were written for, recorded when they are generated. Decides whether MiniMax can speak the row (MiniMax accepts English phonemes only); omit it and the agent’s language is used as the fallback.
Pass an empty array [] to clear all pronunciation rules.Example:

Advanced Configuration

Outbound Calling

These fields apply to agents that place calls. See Outbound Calls. Each object is sent whole and replaces the stored value; omit a field to leave it unchanged. contactPolicy is the exception: its keys merge into the stored policy, and contactPolicy: null clears it.
string
A fixed line spoken word for word before the outbound greeting — for warnings or advisories that the AI must never rephrase. Leave it empty and the agent starts from its greeting or instructions.
boolean | object
Answering Machine Detection. true enables it with the defaults, false disables it, an object tunes it. Unrelated to callDetection.Unknown keys are rejected. GET /v1/agents/{id} returns this as amd_config — rename it to amdConfig before sending it back.
string
Spoken after the beep when detection reaches a voicemail box and on_machine is leave_voicemail. Empty means hang up without leaving a message.
string
Pre-recorded voicemail audio, played instead of speaking voicemailMessage when set. If it cannot be fetched on the call, the text is spoken instead.
boolean | object
IVR Menu Navigation. true enables it with the defaults, an object tunes it: enabled, target_intent (reach_human, reach_department, custom), target_department (max 200), spoken_keywords (up to 20 strings), max_attempts (1–10), max_duration_ms (up to 600000), fallback_action (press_zero, hang_up, wait_for_human), hold_max_wait_ms (up to 1800000).Requires detection: a request that would leave navigation on while amdConfig is off is refused with 400, in either direction — send both fields to change them together. dtmf_transport is not accepted (the DTMF method is a trunk-level setting). Returned by GET as ivr_navigation.
string | null
The retry policy every call this agent places follows, unless the trigger request sends its own retry_policy_id. Must belong to the account.
object | null
Compliance controls for this agent. null or omitted means none: nothing is required and nothing is refused. Unknown keys are rejected.
  • require_consent_basis (boolean) — every trigger must send a consent_basis or is refused with 400 consent_required
  • calling_windows (object) — start_local and end_local as 24-hour HH:MM on the callee’s clock (end exclusive, no wrapping midnight), timezone_source (callee_npanxx, agent_timezone, explicit) and timezone (required for explicit)
  • abandon_rate_alert_threshold (number 0–1) — the abandon rate above which GET /v1/metrics flags this agent. Defaults to 0.03
Distinct from a retry policy’s contact_policy, which holds per-number attempt caps. Returned by GET as contact_policy.
object
General configuration object.Common properties:
object
Extensions configuration for webhooks and MCP servers.Webhook structure:
MCP server objects (mcp_servers):Same request validation as Create Agent — MCP request body: name and url are both required on each entry; transport_type, auth_headers (array of {key, value}), initialization_options (object), and allowed_tool_names (array of tool names the agent may use from that server; omitted or empty means every tool) are optional. Because extensions is replaced in full, an update that sends an MCP entry without allowed_tool_names removes that connection’s tool limit — resend the list to keep it. (Exception: on an OpenTable reservation agent’s StayAPI connection, leaving it out gives the 8 OpenTable tools, never StayAPI’s other tools.) Names must match the server’s tool names exactly. When the server can be reached, names it doesn’t publish are removed and reported in warnings, and a list in which no name matches is rejected with 400. pre_answer_calls (tools the platform calls while the phone is ringing — see Pre-Answer) is also optional and follows the same full-replace rule: an MCP entry sent without it has no pre-answer tools, so resend the list to keep them. The platform transforms each entry on write (name → connection_name, url → mcp_endpoint_url) so the stored shape differs from the request shape — see Get Agent — Stored MCP Connection Shape.Webhook conditions:
  • before_call - Execute before the agent answers
  • during_call - Execute while call is active
  • after_call - Execute after call ends
See Webhooks documentation for complete details and examples.Listings Search tool (type: "listings_search"). Lets the agent search a listings page during a call; see Listings Search. An agent can have one.
All parameters values are strings. Keys you leave out take their defaults. The stored tool always carries all ten keys, and name, friendlyName and condition are always stored as shown above, so a GET returns the tool in this full form.Adding or changing the source means adding the tool, changing its canonical listings_url, or turning fetch_detail_pages from "false" to "true" on an AppFolio page. Only that needs attested_by, sets a new attested_at, and is checked against the Listings Search gate (403). Any public https:// listings page can be saved this way once attested; a non-AppFolio page needs no extra step. Re-sending the tool unchanged (a different URL casing, a trailing / or a query string on an AppFolio address counts as unchanged) keeps the stored attested_by and attested_at whatever you send, but the tool is still validated against the rules below.enabled: false is refused: to switch Listings Search off, remove the tool. Another tool in extensions.tools whose function name is search_listings or send_listing_link is refused too, because Listings Search registers those names.An invalid tool is rejected with 400 Invalid request data, and details names the problem:Because extensions is replaced as a whole, leaving the listings_search tool out of extensions.tools removes it from the agent. To keep it, send it back as GET returned it.

Integrations

object
Third-party integration configurations. Supported provider keys: modmed, googleCalendar, outlookCalendar, twilio, netsapiens. Unknown provider keys are stored as-is.Update semantics — unlike extensions (which is a full replace), integrations uses a field-level merge per provider:
  • Only the fields you send change; omitted fields and omitted providers are preserved.
  • Set a field to null to clear that field.
  • Set a whole provider to null to remove the provider.
This example updates only Twilio’s fromNumber and removes the ModMed integration — everything else is untouched:
Provider fields (required when creating a new provider entry; partial updates only need to leave the stored object valid):Behavior notes:
  • Configs are stored as-is — credentials are not validated against the provider. ModMed/NetSapiens entries written without valid tokens will not function at runtime until tokens are supplied or the integration is connected via the Dashboard.
  • Writing twilio here does not add the send_sms_via_twilio tool to extensions (Connect does when an agent’s From Number is saved; the Dashboard does not) — add the tool yourself if you want the agent to send SMS.
  • Twilio credentials are not set on an agent. An organization has one Twilio connection, set in the Dashboard or Connect, and every agent in the organization uses it. A request whose twilio block sets or changes accountSid, authToken, apiKeySid or apiKeySecret is rejected with 400. Sending back the values a GET returned is not a change, so a GET → modify → PUT round-trip still succeeds. The same rule applies to a Twilio (capital T) block. Sending null for a credential field that is stored counts as a change and is rejected; to remove the agent’s whole Twilio block, including fromNumber, send "twilio": null. If the agent’s own credentials were removed between your GET and your PUT, they are gone, so echoing them is a change and is rejected — GET again first. fromNumber (the number this agent texts from when it has no Send SMS function with its own From Number) is still accepted.
  • Secret fields (passwords, client_secret, access/refresh tokens) are write-only: they are accepted on PUT but never returned by any agent endpoint. The merge semantics make this safe — a GET → modify → PUT round-trip won’t wipe stored secrets.
400 — Twilio credentials sent on an agent
MCP can be set in the Dashboard or via extensions.mcp_servers here (see Create Agent — MCP request body); persisted shape on read is documented under Get Agent.
MCP servers are auto-tested on save. Each entry in extensions.mcp_servers is tested when you update the agent: reachable servers are stored with a fingerprint and discovered tools (green Connected badge in the Portal); unreachable servers are still stored but without a fingerprint (yellow Not tested badge), and the response includes a non-fatal warnings array ([{ "connection_name": "...", "message": "..." }]). Re-testing on update means an MCP server you keep in the payload retains its verified status instead of being reset.To validate a configuration before assigning it, use Test MCP Connection.
Secrets are never returned. Responses from this and every other agent endpoint omit secret fields: integration passwords, twilio.authToken and twilio.apiKeySecret (on agents that still carry their own Twilio credentials), netsapiens.client_secret, calendar access/refresh tokens, and the SIP password inside sip_registration_data. Non-secret metadata (provider keys, usernames, accountSid, connected_at, calendar names) is still returned so you can see what’s configured.

Update Behavior

  • Only provided fields are updated; omitted fields retain their current values
  • The updated_at timestamp is automatically set to the current time
  • The provider field cannot be changed after creation

Feature Administration gating

When Feature Administration is enabled, updates are validated against the feature gates of the agent’s organization — including locks inherited from its reseller or partner. The API returns 403 forbidden when the request:
  • configures an integration under integrations (e.g. googleCalendar, twilio) that is locked for the organization — clearing one (setting it to null) is always allowed;
  • sets ragEnabled: true while Knowledge Base (RAG) is locked;
  • sets warmTransferEnabled: true while Warm Transfer is locked;
  • newly selects a cloned voice in voiceSettings.voice_id while Custom Voices is locked — an agent already using a clone keeps it, and you can still switch away from it;
  • sets a different googlePlaceId while Business Listing (Google Places) is locked. Re-sending the agent’s current Place ID is not blocked, so reading an agent and writing the whole object back keeps working for a locked organization;
  • changes agentType to receptionist, appointment_scheduler, message_taker, blank_slate, outbound, opentable_reservation or translator while the matching Template is locked. Re-sending the agent’s current agentType is not blocked, so a read-modify-write round trip still works. Values of simple, advanced and custom are never gated — simple is the stored type for the Support Agent (CRM) templates and the schema default, so it cannot be attributed to a single template;
  • changes ttsModel to a text-to-speech provider that is locked for the organization. Re-sending the agent’s current provider is never blocked, so a read-modify-write round trip keeps working, and switching away from a locked provider always succeeds onto an available one. cartesia is never gated — it cannot be locked, so an agent can always be moved to a working voice;
  • arms screenshareEnabled (absent/false → true) while Screenshare is locked for the organization. Only the arming transition is gated: re-sending a stored true is never blocked, and turning it off always succeeds;
  • adds the ns_reset_password tool to extensions.tools while NS Password Reset is locked. Only the addition is gated: re-saving an agent that already has the tool is not blocked, and removing it always succeeds;
  • adds a listings_search tool to extensions.tools, or changes its listings_url, or switches its fetch_detail_pages from "false" to "true", while Listings Search is locked. The error is Feature(s) not available for this organization: listings_search, and it is returned even when the tool is also invalid. Re-sending the tool unchanged is never blocked by the lock, and removing it always succeeds;
  • adds a UCaaS function to extensions.tools while that function — or the Netsapiens integration itself — is locked. Each function has its own gate: A Chat Notification tool is recognised by more than its name: any tool with type: "notification" counts if its name begins ns_chat/NS_Chat, if it carries a {"key": "type", "value": "ns_chat"} parameter, or if its notification parameter contains "type": "ns_chat". Those are the same shapes the agent runtime accepts, so a payload that would start a chat is gated whatever it is called. Only the addition is gated: re-sending tools the agent already has is not blocked, and removing one always succeeds — a lock can never strand a UCaaS function on an agent. Netsapiens is checked as well as the function’s own feature, so withdrawing the integration blocks all seven at once; when both are locked the error names the integration.
    You can build that request from a GET response: tools[].type accepts the internal types a GET returns, including the netsapiens type these UCaaS tools carry, so an agent’s existing extensions.tools can be sent back. Two things to know:
    • Tool parameters must be an array of {"key": ..., "value": ...} strings. The other shapes the Dashboard templates store — the Zendesk template’s parameters object, and the Freshdesk template’s numeric values with a type key — are accepted only when that whole tool is sent back exactly as GET returned it, so those tools cannot be edited through this endpoint. Parameters in any other shape are rejected with 400, including {"name": ..., "value": ...} items and flow-builder custom function tools.
    • A payment tool is rejected with 400. Because extensions is replaced as a whole, removing the payment tool from tools turns card payments off. Re-enable them afterwards with PUT /v1/agents/{agentId}/payments/tool, re-sending success_url, max_single_charge_cents, max_per_call_cents and max_attempts_per_call — read them first from GET /v1/agents/{agentId}/payments/readiness — or they reset to their defaults.
Only a genuine change is gated. Clearing a value is never blocked — sending googlePlaceId: null, ragEnabled: false, warmTransferEnabled: false, screenshareEnabled: false or integrations.<name>: null always succeeds — so a lock can never leave an agent with configuration you cannot remove, nor stop you editing an agent’s other fields. Agents created before a template was locked stay fully editable for the same reason.
The Screenshare model check is independent of Feature Administration, and can also fire on a plain model change. Arming screenshareEnabled — or simply changing model on an agent whose screenshare is already on — returns 403 forbidden when the resulting model cannot read images, whether or not Feature Administration is enabled or Screenshare itself is locked. The one exception: a request that changes model and also sets screenshareEnabled: false in the same call is never blocked on this ground, since screenshare is being turned off at the same time. See screenshareEnabled above.
The Screenshare Healthcare refusal is independent of Feature Administration too. A Healthcare-flagged organization can never opt in to Screenshare, so arming an agent there returns 403 forbidden whether or not Feature Administration is enabled and whether or not Screenshare itself is locked. Turning screenshare off is still never blocked.
The /v1/knowledge-bases endpoints apply the same gate and return 403 forbidden when Knowledge Base is locked for the organization. POST /v1/custom-voices returns 403 when Custom Voices is locked, and GET /v1/places/search returns 403 when Business Listing is locked for the account.