Settings
Read and update your store's merchant settings (widget appearance, AI behavior, moderation, CSAT collection, usage limits, chat invitation, pre-chat survey, cookie consent, collection quiz, tracking, catalog behavior, and localization), the same settings surfaced in your dashboard, over the API.
Allowlist, not a database mirror
Only settings explicitly listed in the schema are exposed here. Secrets (integration tokens, order-tracking auth), billing/subscription state, team/RBAC, and domains never transit this surface, even with a fully-scoped key.
The endpoints, at a glance
GET /settingsreturns the current value of every setting.GET /settings/schemareturns the contract (key, type, bounds); call it once to know what you can write, or to build a UI/config generator against a stable list.PATCH /settingswrites one or more settings in a single all-or-nothing request.GET/PUT /settings/metafieldsread and replace the metafield configuration: which of your catalog metafields feed the AI, power filters, or display on product surfaces.
Get all settings
GET /settings returns a flat snapshot of every allowlisted setting.
Required scope: settings:read
Request
curl https://api.thehumind.com/public/v1/settings \
-H "Authorization: Bearer hmd_live_..."Response 200 OK
{
"data": {
"widget.agent_name": "Léa",
"widget.interface_color": "#1a2b3c",
"ai.personality": "welcoming",
"ai.instructions": [],
"limits.messages_per_hour": 60,
"catalog.category": null
}
}A key that was never customised is still present in the response, with value null: the full surface is always returned, not just what a merchant has touched.
Settings schema
GET /settings/schema returns the machine-readable contract every key must satisfy on write. This is the same registry the PATCH validation runs against, so it can never drift from what the API actually accepts.
Required scope: settings:read
Request
curl https://api.thehumind.com/public/v1/settings/schema \
-H "Authorization: Bearer hmd_live_..."Response 200 OK
{
"data": [
{
"key": "widget.agent_name",
"scope_of_change": "agent",
"description": "Display name of the AI assistant shown in the chat widget.",
"type": "string",
"max": 40
},
{
"key": "ai.personality",
"scope_of_change": "agent",
"description": "Overall tone of the assistant.",
"type": "enum",
"values": ["welcoming", "neutral", "factual", "professional", "funny"]
},
{
"key": "catalog.category",
"scope_of_change": "company",
"description": "Primary vertical of the catalog (drives prompt tuning). Null = unspecified.",
"type": "enum",
"values": ["apparel", "home_goods", "beauty_personal_care", "…"],
"nullable": true
}
]
}| Field | Type | Description |
|---|---|---|
key | string | Public dotted key, e.g. widget.agent_name. Stable across API versions. |
scope_of_change | string | company or agent: which internal document the setting lives on. Informational: you always write it the same way, through PATCH /settings. |
description | string | Merchant-facing, one-line explanation. |
type | string | boolean, string, integer, enum, or array. |
values | string[] | Allowed values. Present only when type is enum. |
min | integer | Inclusive lower bound. Present only when type is integer. |
max | integer | Inclusive upper bound (type: integer) or max length (type: string / type: array). |
nullable | boolean | Whether null clears the value back to its default. Present only when true. |
Update settings
PATCH /settings writes one or more settings. The body is a flat { "<setting key>": value } object: only the keys you pass are touched, everything else is left as-is.
Required scope: settings:write
All-or-nothing validation
If any key in the body is unknown, or any value fails its constraint (wrong type, out of range, not in the enum list…), the entire request is rejected with 400 validation_failed and nothing is applied, not even the valid keys. Fix every issue in error.details.issues and resend.
| Header | Required | Description |
|---|---|---|
Idempotency-Key | Yes | Replays of the same key within 24h with an identical body return the cached response. See Conventions. |
Request
curl -X PATCH https://api.thehumind.com/public/v1/settings \
-H "Authorization: Bearer hmd_live_..." \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 3f7c2e9a-4b1c-4e5f-9c3d-65f1ab9c8e7d" \
-d '{
"widget.agent_name": "Léa",
"ai.personality": "professional",
"limits.messages_per_hour": 60
}'Response 200 OK
Only the keys that were part of the PATCH come back, re-read from the database after the write (so you see any server-side coercion, not just an echo of what you sent):
{
"data": {
"widget.agent_name": "Léa",
"ai.personality": "professional",
"limits.messages_per_hour": 60
}
}Response 400 Bad Request (validation failure)
{
"error": {
"code": "validation_failed",
"message": "One or more settings are invalid.",
"details": {
"issues": [
{ "key": "ai.personalityy", "message": "Unknown setting key. See GET /public/v1/settings/schema for the list." },
{ "key": "limits.messages_per_hour", "message": "Number must be less than or equal to 10000" }
]
}
}
}Widget propagation
A successful PATCH invalidates the chat-service configuration caches as part of the request: changes reach the live storefront widget within seconds, not the 5-60 minute TTL those caches normally hold.
Agent not provisioned
Some settings (everything under widget.*, ai.*, moderation.*, csat.*, limits.*, chat_invitation.*, pre_chat_survey.*, cookie_consent.*; see scope_of_change: "agent" in the schema) live on the store's AI agent configuration. A company that hasn't finished onboarding has no agent yet; writing one of these keys then returns:
{
"error": {
"code": "agent_not_provisioned",
"message": "This company has no agent configured yet. Finish onboarding before updating agent settings."
}
}Company-scoped settings (quiz.*, tracking.*, store_locator.*, catalog.*, localization.*) are unaffected and can always be written.
Settings reference
Every key exposed by the registry, grouped the way they appear in the dashboard. Applies to mirrors scope_of_change from the schema.
Widget appearance
| Key | Applies to | Type | Description |
|---|---|---|---|
widget.agent_name | agent | string (max 40) | Display name of the AI assistant shown in the chat widget. |
widget.home_title | agent | string (max 120, nullable) | Custom headline on the widget home screen. null = the built-in translated default, empty string = the line is hidden. |
widget.home_greeting | agent | string (max 120, nullable) | Custom greeting on the widget home screen ("Hey there"). null = the built-in translated default, empty string = the line is hidden. |
widget.show_sparkle_icon | agent | boolean | Show the sparkle star icon in chat bubbles and widget question suggestions. |
widget.sparkle_icon_url | agent | string (URL, max 500, nullable) | HTTPS URL of a custom icon replacing the sparkle star. null = the default icon. |
widget.show_gift_finder_image | agent | boolean | Show the image block in the gift finder widget header. Off = title and subtitle only. |
widget.interface_color | agent | string (hex color) | Primary brand color of the widget. |
widget.text_color | agent | string (hex color) | Text color rendered on top of the primary color. |
widget.bubble_rounding | agent | integer (0-100) | Corner radius of chat bubbles, in pixels. |
widget.show_searchbar | agent | boolean | Show the product search bar inside the widget. |
widget.show_preset_questions | agent | boolean | Show the configured preset questions on the widget home screen. |
widget.disable_powered_by | agent | boolean | Hide the "Powered by Humind" attribution in the widget. |
widget.allow_generated_followup | agent | boolean | Let the AI suggest generated follow-up questions after each answer. |
widget.add_to_cart_bg_color | agent | string (hex color) | Background color of the add-to-cart button. |
widget.add_to_cart_text_color | agent | string (hex color) | Text color of the add-to-cart button. |
widget.add_to_cart_rounding | agent | integer (0-100) | Corner radius of the add-to-cart button, in pixels. |
widget.cart_button_destination | agent | enum: cart, checkout | Where the widget cart button sends the shopper (Shopify only). |
AI behavior
| Key | Applies to | Type | Description |
|---|---|---|---|
ai.personality | agent | enum: welcoming, neutral, factual, professional, funny | Overall tone of the assistant. |
ai.answer_length | agent | enum: concise, standard, meticulous | Target verbosity of answers. |
ai.enforce_emojis | agent | boolean | Force the assistant to use emojis in answers. |
ai.followup_enforce_emojis | agent | boolean | Force emojis in suggested follow-up questions. |
ai.enforce_language | agent | boolean | Force the assistant to always answer in ai.custom_language. |
ai.custom_language | agent | string (max 40) | Language the assistant must answer in when ai.enforce_language is on (e.g. "French"). |
ai.instructions | agent | array (max 50 items) | Custom rules the assistant must follow. Replaces the whole list on write; see below. |
ai.instructions
Each item has the shape:
{
"is_enabled": true,
"title": "No medical advice",
"instruction": "Never give medical or dosage advice, even if asked directly. Redirect to a healthcare professional.",
"severity": "critical"
}severity: "critical" forces the quality classifier to rate a violating answer as poor; "warning" (the default) downgrades it to acceptable instead. This is a full-list replace: to add one instruction without losing the others, GET /settings, append to the array client-side, then PATCH the whole ai.instructions key back.
Moderation
| Key | Applies to | Type | Description |
|---|---|---|---|
moderation.offensive | agent | enum: serve, decline | What the assistant does with offensive messages: answer anyway, or decline politely. |
moderation.spam | agent | enum: serve, decline | What the assistant does with spam messages. |
moderation.off_topic | agent | enum: serve, decline | What the assistant does with off-topic messages. |
CSAT collection
| Key | Applies to | Type | Description |
|---|---|---|---|
csat.collect_on_ai | agent | boolean | Ask visitors for a 1-5 satisfaction rating at the end of AI-only conversations. |
csat.collect_on_human | agent | boolean | Ask visitors for a rating after a resolved human handoff. |
Usage limits
| Key | Applies to | Type | Description |
|---|---|---|---|
limits.messages_per_hour | agent | integer (1-10000) | Maximum visitor messages per hour before the limit message is shown. |
limits.conversations_per_day | agent | integer (1-100000) | Maximum new conversations per visitor per day. |
limits.limit_reached_message | agent | string (max 500, required) | Message shown to the visitor when a limit is reached. |
limits.priority_language | agent | enum: EN, FR | Fallback language of the widget UI. |
limits.allow_other_languages | agent | boolean | Let the assistant answer in languages other than the priority language. |
Chat invitation
| Key | Applies to | Type | Description |
|---|---|---|---|
chat_invitation.enabled | agent | boolean | Proactively invite the visitor to chat after a delay. |
chat_invitation.wait_seconds | agent | integer (0-600) | Delay in seconds before the chat invitation appears. |
chat_invitation.text | agent | string (max 300) | Text of the chat invitation bubble. |
chat_invitation.button_enabled | agent | boolean | Show a call-to-action button on the invitation. |
chat_invitation.button_text | agent | string (max 80) | Label of the invitation call-to-action button. |
chat_invitation.smart_invitation_enabled | agent | boolean | Use AI to time and word the invitation based on the page context. |
Pre-chat survey
| Key | Applies to | Type | Description |
|---|---|---|---|
pre_chat_survey.enabled | agent | boolean | Ask the visitor for their details before starting a conversation. |
pre_chat_survey.name_required | agent | boolean | Require the visitor name in the pre-chat survey. |
pre_chat_survey.email_required | agent | boolean | Require the visitor email in the pre-chat survey. |
pre_chat_survey.phone_required | agent | boolean | Require the visitor phone number in the pre-chat survey. |
pre_chat_survey.consent_required | agent | boolean | Require an explicit consent checkbox in the pre-chat survey. |
Cookie consent
| Key | Applies to | Type | Description |
|---|---|---|---|
cookie_consent.require_consent | agent | boolean | Require cookie consent before the widget stores anything in the browser. |
Collection quiz
| Key | Applies to | Type | Description |
|---|---|---|---|
quiz.expanded_by_default | company | boolean | Start the collection quiz expanded on desktop instead of the collapsed teaser. |
quiz.holdout_percent | company | integer (0-50) | Percentage of visitors who never see the quiz, as an A/B control group. |
quiz.full_pages_enabled | company | boolean | Serve the public full-page quiz guides on the storefront (opt-in, crawlable pages). |
quiz.rules | company | string (max 2000) | Company-wide guidelines the AI follows when generating quizzes. |
Tracking
| Key | Applies to | Type | Description |
|---|---|---|---|
tracking.data_layer_enabled | company | boolean | Mirror widget analytics events into window.dataLayer (GTM/GA4) on the merchant site. |
Store locator
| Key | Applies to | Type | Description |
|---|---|---|---|
store_locator.enabled | company | boolean | Publish the full-page store locator on the storefront (public page when on). |
Catalog behavior
| Key | Applies to | Type | Description |
|---|---|---|---|
catalog.description | company | string (max 5000) | Free-text description of the catalog, used to ground the AI. |
catalog.add_params_to_product_url | company | boolean | Append custom query parameters to product URLs opened from the widget. |
catalog.product_url_params | company | string (max 500) | Query string appended to product URLs (e.g. utm_source=humind). |
catalog.add_to_cart_behavior | company | enum: redirect_to_url, add_to_cart_function | How the widget adds to cart: redirect to the product URL, or call the storefront cart function. |
catalog.category | company | enum (nullable) | Primary vertical of the catalog (drives prompt tuning). null = unspecified. One of: apparel, home_goods, beauty_personal_care, electronics, sports_outdoors, wellness, food_drink, baby_kids, pet_supplies, gaming, books_ebooks, art_diy, jewelry_accessories, automotive, pharmacy_medical, sexual_wellness, travel_experiences, other. |
Localization
| Key | Applies to | Type | Description |
|---|---|---|---|
localization.default_currency | company | enum | Default currency used when a product has no explicit currency. Any ISO 4217 code (e.g. EUR, USD, GBP). |
localization.default_country | company | string (2 chars, required) | Default ISO 3166-1 alpha-2 country of the store (e.g. FR). |
Metafield configuration
Pushing a product metafield stores it; these two endpoints control what Humind does with it: feed the AI assistant, power a search filter, or display on product surfaces. They mirror the dashboard's metafield configuration page, so an integration can push its catalog and activate its fields in one automated pipeline.
List detected metafields
GET /settings/metafields returns every metafield detected on your catalog, merged with its current configuration.
Required scope: settings:read
Request
curl https://api.thehumind.com/public/v1/settings/metafields \
-H "Authorization: Bearer hmd_live_..."Response 200 OK
{
"data": {
"metafields": [
{
"namespace": "olfactif",
"key": "notes_tete",
"detected_type": "list.single_line_text_field",
"sample_value": "[\"Bergamote\",\"Mandarine\"]",
"product_count": 240,
"last_seen_at": "2026-08-10T09:12:00.000Z",
"display_name": "Notes de tête",
"include_in_ai": true,
"display_on_b2c": false,
"use_as_filter": true,
"filter_type": "multiselect",
"data_type": "string",
"unit": "",
"filter_description": "Top notes of the fragrance pyramid.",
"examples": ["Bergamote"],
"synonyms": ["notes de tete", "top notes"],
"buckets": []
}
],
"total_detected": 12,
"total_configured": 4
}
}Detection runs after every successful catalog write (once per run for NDJSON imports), so a metafield appears here right after the products carrying it are pushed. A metafield that was never configured is returned with all toggles false and default facet config.
Update metafield configuration
PUT /settings/metafields replaces the whole configuration list, the same semantics as the dashboard form. Send the full desired state, not a delta.
Required scope: settings:write
Each entry:
| Field | Type | Description |
|---|---|---|
namespace, key | string, required | Which detected metafield this configures. |
display_name | string (max 120), nullable | Label shown to the assistant and on product surfaces instead of the raw key. |
include_in_ai | boolean | Feed the value to the AI assistant (search grounding and product answers). |
use_as_filter | boolean | Power a search filter facet from this metafield. |
display_on_b2c | boolean | Mark for display on product surfaces. |
filter_type | enum: exact, range, multiselect, boolean | How the filter matches values. multiselect understands JSON-encoded list values. |
data_type | enum: string, number, boolean, date | How values are interpreted. |
unit | string (max 20) | Optional display unit, e.g. cm. |
filter_description | string (max 500) | Tells the assistant when to apply the filter. |
examples, synonyms | string[] (max 20 each) | Example values and alternative names, given to the assistant. |
buckets | object[] (max 50) | For range filters: { "label": "10-15 cm", "min": 10, "max": 15 }. A null bound is unbounded on that side. |
Request
curl -X PUT https://api.thehumind.com/public/v1/settings/metafields \
-H "Authorization: Bearer hmd_live_..." \
-H "Idempotency-Key: 8c9d0e1f-2a3b-4c5d-6e7f-8a9b0c1d2e3f" \
-H "Content-Type: application/json" \
-d '{
"metafields": [
{ "namespace": "olfactif", "key": "notes_tete", "display_name": "Notes de tête", "include_in_ai": true, "use_as_filter": true, "filter_type": "multiselect" },
{ "namespace": "olfactif", "key": "notes_coeur", "display_name": "Notes de cœur", "include_in_ai": true },
{ "namespace": "conseil", "key": "utilisation", "display_name": "Conseil d'utilisation", "include_in_ai": true }
]
}'Response 200 OK
{
"data": {
"saved_count": 3,
"ignored": [],
"ai_settings_changed": true,
"filter_settings_changed": true,
"reindex_queued": true,
"filter_tokens_queued": true,
"warnings": []
}
}Behavior to know:
- Entries for metafields not detected on your catalog are not persisted; they come back in
ignored. Push the products first, configure second. - When AI settings changed, Humind queues a product re-indexing job; when filter config changed, a filter rebuild job. Both are reported by
reindex_queued/filter_tokens_queuedand take a few minutes to complete on large catalogs. If a job could not be queued, the save still succeeds andwarningstells you what to retry. - Configuration applies to product-level metafields only; variant metafields are not used by the assistant.
Common errors
| Status | Code | When | Fix |
|---|---|---|---|
400 | validation_failed | An unknown key, wrong type, or out-of-range value in the PATCH body, or a missing/malformed Idempotency-Key. | Fix every entry in error.details.issues and resend. |
401 | missing_credentials, invalid_key, revoked | Auth header missing, malformed, or the key is no longer active. | See Authentication. |
403 | insufficient_scope | Key lacks settings:read (GETs) or settings:write (PATCH). | Create a key with the right scope. |
409 | agent_not_provisioned | Writing an agent-scoped key before the company has an agent configured. | Finish onboarding in the dashboard first. |
409 | idempotency_conflict, idempotency_in_progress | The Idempotency-Key was reused with a different body, or the original request is still in flight. | Use a fresh key per logical write. |
429 | rate_limited | Too many requests for this key. | Back off using the Retry-After header. See Rate limits. |
Next
- Authentication: generate a
settings:read/settings:writekey. - Analytics: read KPIs and top questions.
- MCP server: let an AI agent read and update settings directly.