API reference · Bots
Update bot
- Authentication
- Bearer token
- Retries
- Idempotency-Key
- Body
- application/json
- Version
- 2026-09-03
Path parameters
bot_idstringrequired
Headers
Idempotency-KeystringA unique key of your choosing, so this request can be retried safely. The first request with a given key executes; every replay returns that first response unchanged, with
Idempotent-Replay: trueset.Generate one key per action, not per session - reusing a key with a different body is refused with 422 rather than silently replaying the wrong answer. Keys are remembered for 24 hours. A request that failed releases its key, so a retry after fixing the payload runs normally.
Up to 255 characters
Request body
application/json · required
BotUpdate
allowed_domainsarray of string | nullUp to 50 items
api_keystring | nullUp to 500 characters
contact_fields_configarray of ContactFieldDef | nullUp to 20 items
4 fields · ContactFieldDef
keystringrequired1–40 characters·Pattern: ^[a-z][a-z0-9_]*$
labelstringrequired1–100 characters
optionsarray of string | nullUp to 30 items
typestringOne of: text, email, phone, select, number·Default: text
custom_endpoint_configCustomEndpointConfig | null5 fields · CustomEndpointConfig
endpoint_urlstringrequired8–1000 characters
auth_header_namestring | nullUp to 100 characters
auth_header_valuestring | nullUp to 2000 characters
modelstring | nullUp to 128 characters
response_pathstring | nullUp to 200 characters
descriptionstring | nullUp to 2000 characters
directory_configDirectoryConfig | nullGeneric routing table: category + choice resolves to a link.
Replaces the previous hard-coded
doctors_config. A clinic reads it as branch/doctor/appointment link, a dealership as city/showroom/booking link, a university as campus/department/enquiry form - same code, no per-vertical branches.7 fields · DirectoryConfig
category_fieldstringDefault: branch·Up to 40 characters
category_labelstringDefault: Location·Up to 60 characters
choice_fieldstringDefault: preferred_specialist·Up to 40 characters
choice_labelstringDefault: Specialist·Up to 60 characters
enabledbooleanDefault: false
entriesarray of DirectoryEntryUp to 500 items
4 fields · DirectoryEntry
namestringrequired1–150 characters
categorystringDefault: ·Up to 100 characters
linkstringDefault: ·Up to 1000 characters
metadataobject
result_fieldstringDefault: booking_link·Up to 40 characters
fallback_messagestring | nullUp to 1000 characters
handoff_configobject | nullhandoff_enabledboolean | nullis_publicboolean | nulllanguagestring | nullUp to 16 characters
lead_capture_configLeadCaptureConfig | null6 fields · LeadCaptureConfig
enabledbooleanDefault: false
fieldsarray of LeadCaptureFieldUp to 10 items
5 fields · LeadCaptureField
keystringrequired1–40 characters·Pattern: ^[a-z][a-z0-9_]*$
labelstringrequired1–100 characters
placeholderstring | nullUp to 120 characters
requiredbooleanDefault: false
typestringOne of: text, email, phone, select, number·Default: text
introstring | nullUp to 300 characters
titlestring | nullUp to 120 characters
triggerstringOne of: before_chat, after_n_messages, manual·Default: manual
trigger_valueinteger | nullDefault: 2·≥ 1 and ≤ 50
llm_providerLLMProviderType | nullplatformuses the credentials this deployment is configured with;byok("bring your own key") uses the tenant's own Anthropic key;customposts to an owner-supplied OpenAI-compatible endpoint.One of: platform, byok, custom
max_tokensinteger | null≥ 64 and ≤ 32768
modelstring | nullUp to 128 characters
monthly_message_capinteger | null≥ 0
namestring | null1–255 characters
rate_limit_per_minuteinteger | null≥ 1 and ≤ 1000
starter_questionsarray of string | nullUp to 6 items
statusBotStatus | nullOne of: draft, active, paused, archived
strict_kb_modeboolean | nullsystem_promptstring | nullUp to 20000 characters
temperaturenumber | null≥ 0 and ≤ 2
thinking_budget_tokensinteger | null≥ 1024 and ≤ 32000
thinking_enabledboolean | nullwelcome_messagestring | nullUp to 1000 characters
widget_themeWidgetTheme | nullWidget appearance. Extra keys are kept so the dashboard can add controls without a migration; the widget ignores what it does not recognise.
-------------------------------------------------------------------- Contrast is enforced, and enforced differently for the two callers --------------------------------------------------------------------
A tenant editing colours by hand is rejected, with the measured ratio and a hex that would pass, because they can see the result and are entitled to choose which colour moves.
A theme produced by the one-prompt generator is repaired before it reaches this class - see
generation_service._readable_theme. Failing an entire bot generation because a model picked a hex nobody asked for, and which the customer will never see, would be an absurd way to lose a signup.Two policies, one definition of readable, which is why the definition lives in
app.platform.contrastand not here.39 fields · WidgetTheme
accent_colorstring | nullPattern: ^#[0-9A-Fa-f]{6}$
avatar_urlstring | nullUp to 1000 characters
border_colorstringDefault: #E2E8F0·Pattern: ^#[0-9A-Fa-f]{6}$
bot_bubble_bgstringDefault: #FFFFFF·Pattern: ^#[0-9A-Fa-f]{6}$
bot_bubble_textstringDefault: #0F172A·Pattern: ^#[0-9A-Fa-f]{6}$
bubble_radiusintegerDefault: 16·≥ 0 and ≤ 28
bubble_radius_cornersarray of integer | null4–4 items
bubble_textstring | nullUp to 100 characters
custom_cssstring | nullUp to 8000 characters
darkDarkPalette | nullThe second palette, used when the visitor's system is set to dark.
Not the tenant's preference - the visitor's. A tenant previewing on a light laptop is not the person the choice is for, and a widget that stays bright white on a dark site reads as broken rather than as branded.
Every field is optional. A tenant who sets none gets a palette derived from their light one at render time, which is a better default than forcing them through a second colour picker they did not ask for.
7 fields · DarkPalette
border_colorstring | nullPattern: ^#[0-9A-Fa-f]{6}$
bot_bubble_bgstring | nullPattern: ^#[0-9A-Fa-f]{6}$
bot_bubble_textstring | nullPattern: ^#[0-9A-Fa-f]{6}$
messages_bgstring | nullPattern: ^#[0-9A-Fa-f]{6}$
panel_bgstring | nullPattern: ^#[0-9A-Fa-f]{6}$
primary_colorstring | nullPattern: ^#[0-9A-Fa-f]{6}$
user_bubble_textstring | nullPattern: ^#[0-9A-Fa-f]{6}$
fontstring | nullDefault: system
header_subtitlestring | nullUp to 100 characters
header_textstringDefault: #FFFFFF·Pattern: ^#[0-9A-Fa-f]{6}$
header_titlestring | nullUp to 60 characters
inline_targetstring | nullUp to 100 characters
launcher_animationstringOne of: none, fade, rise, pulse·Default: fade
launcher_labelstring | nullUp to 28 characters
launcher_shapestringOne of: circle, rounded, square·Default: circle
launcher_sizestringOne of: sm, md, lg·Default: md
launcher_stylestringOne of: icon, pill·Default: icon
layoutstringOne of: floating, sidebar, inline, fullscreen·Default: floating
messages_bgstringDefault: #F8FAFC·Pattern: ^#[0-9A-Fa-f]{6}$
offset_xintegerDefault: 20·≥ 0 and ≤ 120
offset_yintegerDefault: 20·≥ 0 and ≤ 120
panel_bgstringDefault: #FFFFFF·Pattern: ^#[0-9A-Fa-f]{6}$
panel_heightintegerDefault: 640·≥ 360 and ≤ 900
panel_radiusintegerDefault: 20·≥ 0 and ≤ 32
panel_widthintegerDefault: 380·≥ 300 and ≤ 520
positionstringOne of: bottom-right, bottom-left·Default: bottom-right
primary_colorstringDefault: #4F46E5·Pattern: ^#[0-9A-Fa-f]{6}$
primary_gradientGradient | nullA two-stop linear gradient for the launcher and header.
3 fields · Gradient
from_colorstringrequiredPattern: ^#[0-9A-Fa-f]{6}$
to_colorstringrequiredPattern: ^#[0-9A-Fa-f]{6}$
angleintegerDefault: 135·≥ 0 and ≤ 360
proactivearray of ProactiveTriggerUp to 5 items
5 fields · ProactiveTrigger
messagestringrequired1–300 characters
typestringrequiredOne of: time_on_page, exit_intent, scroll_depth, url_pattern, return_visitor, idle
open_panelbooleanDefault: false
thresholdinteger | null≥ 1 and ≤ 3600
url_patternstring | nullUp to 200 characters
proactive_cooldown_daysintegerDefault: 7·≥ 0 and ≤ 90
show_brandingbooleanDefault: true
show_citationsbooleanDefault: true
theme_modestringOne of: auto, light, dark·Default: auto
theme_versionintegerDefault: 2·≥ 1 and ≤ 99
typing_indicatorstringOne of: dots, pulse, wave, none·Default: dots
user_bubble_textstringDefault: #FFFFFF·Pattern: ^#[0-9A-Fa-f]{6}$
Responses
- 200OKapplication/json
BotRead
allowed_domainsarray of string | nullrequiredcontact_fields_configarray of anyrequiredcreated_atstring (date-time)requireddescriptionstring | nullrequireddirectory_configobject | nullrequiredfallback_messagestring | nullrequiredhandoff_enabledbooleanrequiredidstringrequiredindexed_chunk_countintegerrequiredis_publicbooleanrequiredlanguagestringrequiredlast_errorstring | nullrequiredlead_capture_configobject | nullrequiredllm_providerLLMProviderTyperequiredplatformuses the credentials this deployment is configured with;byok("bring your own key") uses the tenant's own Anthropic key;customposts to an owner-supplied OpenAI-compatible endpoint.One of: platform, byok, custom
max_tokensintegerrequiredmodelstring | nullrequiredmonthly_message_capinteger | nullrequirednamestringrequiredorg_idstringrequiredpublic_keystringrequiredrate_limit_per_minuteintegerrequiredstarter_questionsarray of stringrequiredstatusBotStatusrequiredOne of: draft, active, paused, archived
strict_kb_modebooleanrequiredsystem_promptstringrequiredtemperaturenumberrequiredthinking_enabledbooleanrequiredtotal_conversationsintegerrequiredtotal_messagesintegerrequiredupdated_atstring (date-time)requiredwelcome_messagestring | nullrequiredwidget_themeobjectrequiredcustom_endpoint_configobject | nullhas_api_keybooleanDefault: false
5 response headers
- RateLimit-Limit
Requests permitted in the current window.
- RateLimit-Remaining
Requests left in the current window. Back off before it reaches 0.
- RateLimit-Reset
Seconds until the current window resets.
- X-API-Version
The dated version of the API contract that served this response, e.g.
2026-09-03. Pin against it; it changes only when a response shape changes incompatibly.- X-Request-ID
Quote this in a support request to identify the call.
- 422Validation error
The shared error envelope, served as
application/problem+jsonwitherror.codeset to validation_error. Its details name each field that failed and why.
Example request
curl -X PATCH "https://api.integrable.cloud/api/bots/$BOT_ID" \
-H "Authorization: Bearer $INTEGRABLE_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"allowed_domains": [
"https://example.com"
]
}'Set INTEGRABLE_API_KEY and the path variables first. The same call from the TypeScript or Python SDK takes the same fields.
Example response
{
"allowed_domains": [
"https://example.com"
],
"contact_fields_config": [
"string"
],
"created_at": "2026-09-03T09:30:00Z",
"custom_endpoint_config": {},
"description": "string",
"directory_config": {},
"fallback_message": "string",
"handoff_enabled": true,
"has_api_key": false,
"id": "01a0652b-3713-7ea1-a6c9-2e895389ec34",
"indexed_chunk_count": 20,
"is_public": true,
"language": "string",
"last_error": "string",
"lead_capture_config": {},
"llm_provider": "platform",
"max_tokens": 0,
"model": "string",
"monthly_message_cap": 0,
"name": "string",
"org_id": "01a0652b-3713-7ea1-a6c9-2e895389ec34",
"public_key": "string",
"rate_limit_per_minute": 20,
"starter_questions": [
"string"
],
"status": "draft",
"strict_kb_mode": true,
"system_prompt": "string",
"temperature": 0,
"thinking_enabled": true,
"total_conversations": 0,
"total_messages": 0,
"updated_at": "2026-09-03T09:30:00Z",
"welcome_message": "string",
"widget_theme": {}
}Generated from the schema above — the shape is exact, the values are placeholders.
Errors
Failures use one envelope on every endpoint, described in Retries, versioning and limits. The codes you are most likely to meet here:
validation_error· 422 — The payload was well-formed JSON but failed schema validation.unauthenticated· 401 — The request carried no API key, or one the API could not verify.forbidden· 403 — The key is valid, but it is not allowed to do this — either the scope is missing or the resource belongs to another workspace.idempotency_key_reused· 422 — This `Idempotency-Key` was used before, for a request with a different body.rate_limited· 429 — Too many requests in the current window. The limit is per workspace, and some endpoints add a per-bot limit on top.
More Bots endpoints
- get/api/botsList bots
- post/api/botsCreate bot
- post/api/bots/generateGenerate bot
- get/api/bots/modelsAvailable models
- post/api/bots/onboarding/rehearseRehearse blueprint
- post/api/bots/onboarding/scanScan website
- post/api/bots/onboarding/variantsGenerate variants
- get/api/bots/{bot_id}Get bot
- delete/api/bots/{bot_id}Delete bot
- post/api/bots/{bot_id}/duplicateDuplicate bot
- get/api/bots/{bot_id}/embedGet embed
- get/api/bots/{bot_id}/funnelGet funnel
- post/api/bots/{bot_id}/rotate-keyRotate key
- post/api/bots/{bot_id}/suggest-improvementsSuggest improvements
- post/api/bots/{bot_id}/testTest message
- post/api/bots/{bot_id}/theme/avatarUpload avatar
- delete/api/bots/{bot_id}/theme/avatarDelete avatar
- post/api/bots/{bot_id}/theme/generateGenerate theme
- get/api/bots/{bot_id}/versionsList versions
- post/api/bots/{bot_id}/versions/{version}/restoreRestore version
Something here wrong or missing? Tell us — the documentation and the API are maintained by the same person, so a correction is a fix rather than a ticket.