Reference
AI Setter
AI Setter: 9 operations (setter.knowledge.list, setter.knowledge.create, setter.booking.preview, setter.connections.get, setter.knowledge.update, setter.knowledge.delete, setter.persona.get, setter.persona.set, setter.test).
| Method | Path | Operation |
|---|---|---|
GET | /v1/reps/{rep_id}/setter/knowledge | setter.knowledge.list |
POST | /v1/reps/{rep_id}/setter/knowledge | setter.knowledge.create |
GET | /v1/setter/booking-preview | setter.booking.preview |
GET | /v1/setter/connections | setter.connections.get |
PATCH | /v1/setter/knowledge/{knowledge_id} | setter.knowledge.update |
DELETE | /v1/setter/knowledge/{knowledge_id} | setter.knowledge.delete |
GET | /v1/setter/persona | setter.persona.get |
PUT | /v1/setter/persona | setter.persona.set |
POST | /v1/setter/test | setter.test |
setter.knowledge.list
GET/v1/reps/{rep_id}/setter/knowledge
List a rep's AI Setter knowledge entries, oldest first.
| Operation id | setter.knowledge.list |
| Scopes | setter:read |
| Rate class | `read` |
| Idempotency | Not applicable |
| Keys | Developer keys |
| Reps | A key restricted to reps sees only data of its own reps |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
rep_id | string | yes |
Response 200
| Field | Type | Required | Description |
|---|---|---|---|
data | object[] | yes |
Errors
| Status | Code | When |
|---|---|---|
| 404 | `REP_NOT_FOUND_404` | A rep does not exist in this workspace, is archived, or is outside the key's rep restriction. |
Every operation can also answer the shared errors: authentication, scopes, rate limits and validation.
Example
curl "https://api.dmhero.ai/v1/reps/string/setter/knowledge" \
-H "Authorization: Bearer $DMHERO_API_KEY"JSON Schema
{
"type": "object",
"properties": {
"data": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"rep_id": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"title": {
"type": "string"
},
"content": {
"type": "string"
},
"created_at": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"
},
"updated_at": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"
}
},
"required": [
"id",
"rep_id",
"title",
"content",
"created_at",
"updated_at"
],
"additionalProperties": false
}
}
},
"required": [
"data"
],
"additionalProperties": false
}setter.knowledge.create
POST/v1/reps/{rep_id}/setter/knowledge
Add a knowledge entry the rep's AI Setter may answer from.
The setter reads every entry of the rep on every reply. The same limits as the app's editor: a title of 1 to 120 characters after trimming, content up to 8000 characters.
| Operation id | setter.knowledge.create |
| Scopes | setter:write |
| Rate class | `write` |
| Idempotency | `Idempotency-Key` accepted |
| Keys | Developer keys |
| Reps | A key restricted to reps sees only data of its own reps |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
rep_id | string | yes |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
content | string | yes | Up to 8000 characters.. at most 8000 characters |
title | string | yes | 1 to 120 characters after trimming. |
Response 201
| Field | Type | Required | Description |
|---|---|---|---|
content | string | yes | |
created_at | date-time | yes | |
id | uuid | yes | |
rep_id | uuid | yes | |
title | string | yes | |
updated_at | date-time | yes |
Errors
| Status | Code | When |
|---|---|---|
| 400 | `VALIDATION_FAILED_400` | A field is missing or malformed; fields names each one. |
| 404 | `REP_NOT_FOUND_404` | A rep does not exist in this workspace, is archived, or is outside the key's rep restriction. |
Every operation can also answer the shared errors: authentication, scopes, rate limits and validation.
Example
curl -X POST "https://api.dmhero.ai/v1/reps/string/setter/knowledge" \
-H "Authorization: Bearer $DMHERO_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"title": "string",
"content": "string"
}'JSON Schema
{
"type": "object",
"properties": {
"title": {
"type": "string",
"description": "1 to 120 characters after trimming."
},
"content": {
"type": "string",
"maxLength": 8000,
"description": "Up to 8000 characters."
}
},
"required": [
"title",
"content"
]
}{
"type": "object",
"properties": {
"id": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"rep_id": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"title": {
"type": "string"
},
"content": {
"type": "string"
},
"created_at": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"
},
"updated_at": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"
}
},
"required": [
"id",
"rep_id",
"title",
"content",
"created_at",
"updated_at"
],
"additionalProperties": false
}setter.booking.preview
GET/v1/setter/booking-preview
The free meeting times a variant's saved booking rules would offer a new prospect right now.
Reads the workspace's Google Calendar free/busy under the variant's SAVED booking rules and writes nothing. block is the text the setter's model reads. A calendar that is not connected, revoked, or refused by Google is not an error: available is false and reason says why.
| Operation id | setter.booking.preview |
| Scopes | setter:read |
| Rate class | `heavy` |
| Idempotency | Not applicable |
| Keys | Developer keys |
| Reps | A key restricted to reps sees only data of its own reps |
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
variant_id | string | yes | |
lang | "pl" | "en" | no | Language of block. Default pl. |
Response 200
| Field | Type | Required | Description |
|---|---|---|---|
available | boolean | yes | |
beyond_horizon | boolean | null | yes | |
block | string | null | yes | |
empty | boolean | null | yes | |
first_available_date | string | null | yes | |
owner_tz | string | null | yes | |
prospect_tz | string | null | yes | |
reason | string | null | yes | Why no times could be read, when available is false. |
Errors
| Status | Code | When |
|---|---|---|
| 403 | `GOOGLE_CALENDAR_NOT_ENABLED_403` | Google Calendar booking is not enabled for this organization yet. |
| 404 | `SETTER_VARIANT_NOT_FOUND_404` | The setter variant does not exist, or belongs to a rep outside the key's reps. |
Every operation can also answer the shared errors: authentication, scopes, rate limits and validation.
Example
curl "https://api.dmhero.ai/v1/setter/booking-preview?variant_id=string" \
-H "Authorization: Bearer $DMHERO_API_KEY"JSON Schema
{
"type": "object",
"properties": {
"available": {
"type": "boolean"
},
"reason": {
"description": "Why no times could be read, when `available` is false.",
"type": [
"string",
"null"
]
},
"block": {
"type": [
"string",
"null"
]
},
"empty": {
"type": [
"boolean",
"null"
]
},
"beyond_horizon": {
"type": [
"boolean",
"null"
]
},
"first_available_date": {
"type": [
"string",
"null"
]
},
"owner_tz": {
"type": [
"string",
"null"
]
},
"prospect_tz": {
"type": [
"string",
"null"
]
}
},
"required": [
"available",
"reason",
"block",
"empty",
"beyond_horizon",
"first_available_date",
"owner_tz",
"prospect_tz"
],
"additionalProperties": false
}setter.connections.get
GET/v1/setter/connections
Whether the workspace's Google Calendar and Calendly are connected, for the setter's booking goal.
Status only: the state of each connection, the Google account and its calendars (to pick a target calendar for a variant's booking rules), the Calendly scheduling link. Never a token.
| Operation id | setter.connections.get |
| Scopes | setter:read |
| Rate class | `read` |
| Idempotency | Not applicable |
| Keys | Developer keys |
Response 200
| Field | Type | Required | Description |
|---|---|---|---|
calendly | object | yes | |
google_calendar | object | yes |
Errors
Every operation can also answer the shared errors: authentication, scopes, rate limits and validation.
Example
curl "https://api.dmhero.ai/v1/setter/connections" \
-H "Authorization: Bearer $DMHERO_API_KEY"JSON Schema
{
"type": "object",
"properties": {
"google_calendar": {
"type": "object",
"properties": {
"enabled": {
"type": "boolean",
"description": "Google Calendar booking is available to this organization."
},
"connected": {
"type": "boolean"
},
"status": {
"anyOf": [
{
"type": "string",
"enum": [
"active",
"incomplete",
"revoked"
]
},
{
"type": "null"
}
]
},
"email": {
"type": [
"string",
"null"
]
},
"owner_timezone": {
"type": [
"string",
"null"
]
},
"missing_scopes": {
"type": "array",
"items": {
"type": "string"
}
},
"calendars": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"summary": {
"type": "string"
},
"primary": {
"type": "boolean"
},
"time_zone": {
"type": [
"string",
"null"
]
},
"access_role": {
"type": "string"
}
},
"required": [
"id",
"summary",
"primary",
"time_zone",
"access_role"
],
"additionalProperties": false
}
},
"calendars_fetched_at": {
"anyOf": [
{
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"
},
{
"type": "null"
}
]
},
"connected_at": {
"anyOf": [
{
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"
},
{
"type": "null"
}
]
}
},
"required": [
"enabled",
"connected",
"status",
"email",
"owner_timezone",
"missing_scopes",
"calendars",
"calendars_fetched_at",
"connected_at"
],
"additionalProperties": false
},
"calendly": {
"type": "object",
"properties": {
"connected": {
"type": "boolean"
},
"scheduling_url": {
"type": [
"string",
"null"
]
},
"has_webhook": {
"type": "boolean"
}
},
"required": [
"connected",
"scheduling_url",
"has_webhook"
],
"additionalProperties": false
}
},
"required": [
"google_calendar",
"calendly"
],
"additionalProperties": false
}setter.knowledge.update
PATCH/v1/setter/knowledge/{knowledge_id}
Change a knowledge entry's title, content, or both.
Only the fields sent change. At least one of title and content is required.
| Operation id | setter.knowledge.update |
| Scopes | setter:write |
| Rate class | `write` |
| Idempotency | Not applicable |
| Keys | Developer keys |
| Reps | A key restricted to reps sees only data of its own reps |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
knowledge_id | string | yes |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
content | string | no | Up to 8000 characters.. at most 8000 characters |
title | string | no | 1 to 120 characters after trimming. |
Response 200
| Field | Type | Required | Description |
|---|---|---|---|
content | string | yes | |
created_at | date-time | yes | |
id | uuid | yes | |
rep_id | uuid | yes | |
title | string | yes | |
updated_at | date-time | yes |
Errors
| Status | Code | When |
|---|---|---|
| 400 | `VALIDATION_FAILED_400` | A field is missing or malformed; fields names each one. |
| 404 | `KNOWLEDGE_NOT_FOUND_404` | The knowledge entry does not exist, or belongs to a rep outside the key's reps. |
Every operation can also answer the shared errors: authentication, scopes, rate limits and validation.
Example
curl -X PATCH "https://api.dmhero.ai/v1/setter/knowledge/string" \
-H "Authorization: Bearer $DMHERO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "string",
"content": "string"
}'JSON Schema
{
"type": "object",
"properties": {
"title": {
"type": "string",
"description": "1 to 120 characters after trimming."
},
"content": {
"type": "string",
"maxLength": 8000,
"description": "Up to 8000 characters."
}
}
}{
"type": "object",
"properties": {
"id": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"rep_id": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
"title": {
"type": "string"
},
"content": {
"type": "string"
},
"created_at": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"
},
"updated_at": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"
}
},
"required": [
"id",
"rep_id",
"title",
"content",
"created_at",
"updated_at"
],
"additionalProperties": false
}setter.knowledge.delete
DELETE/v1/setter/knowledge/{knowledge_id}
Delete a knowledge entry.
| Operation id | setter.knowledge.delete |
| Scopes | setter:write |
| Rate class | `write` |
| Idempotency | Not applicable |
| Keys | Developer keys |
| Destructive | Yes: it removes or stops something that cannot be restored by repeating the call |
| Reps | A key restricted to reps sees only data of its own reps |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
knowledge_id | string | yes |
Response 204
No body.
Errors
| Status | Code | When |
|---|---|---|
| 404 | `KNOWLEDGE_NOT_FOUND_404` | The knowledge entry does not exist, or belongs to a rep outside the key's reps. |
Every operation can also answer the shared errors: authentication, scopes, rate limits and validation.
Example
curl -X DELETE "https://api.dmhero.ai/v1/setter/knowledge/string" \
-H "Authorization: Bearer $DMHERO_API_KEY"setter.persona.get
GET/v1/setter/persona
Read the persona (name, role, tone, style, language) of one or more reps.
The persona lives on each rep's live setter variant, the same record the app's Settings and AI Setter editor show. With several reps, mixed lists the fields they disagree on.
| Operation id | setter.persona.get |
| Scopes | setter:read |
| Rate class | `read` |
| Idempotency | Not applicable |
| Keys | Developer keys |
| Reps | A key restricted to reps sees only data of its own reps |
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
rep_ids | string[] | yes | The reps in scope: repeated, or as one comma-separated value. Every id must be one of the key's reps.. 1 to 50 items |
Response 200
| Field | Type | Required | Description |
|---|---|---|---|
mixed | ("rep_name" | "rep_role" | "tone_text" | "style_text" | "language_text")[] | yes | Fields whose value differs across the reps in scope. |
rep_count | integer | yes | -9007199254740991 to 9007199254740991 |
rep_ids | uuid[] | yes | |
unconfigured_count | integer | yes | Reps in scope with no live setter variant yet.. -9007199254740991 to 9007199254740991 |
values | object | yes | Per field: the value the reps share, or the first rep's value when they differ. |
Errors
| Status | Code | When |
|---|---|---|
| 400 | `VALIDATION_FAILED_400` | A field is missing or malformed; fields names each one. |
| 404 | `REP_NOT_FOUND_404` | A rep does not exist in this workspace, is archived, or is outside the key's rep restriction. |
Every operation can also answer the shared errors: authentication, scopes, rate limits and validation.
Example
curl "https://api.dmhero.ai/v1/setter/persona?rep_ids=%5B%22string%22%5D" \
-H "Authorization: Bearer $DMHERO_API_KEY"JSON Schema
{
"type": "object",
"properties": {
"rep_ids": {
"type": "array",
"items": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
}
},
"values": {
"type": "object",
"properties": {
"rep_name": {
"type": "string"
},
"rep_role": {
"type": "string"
},
"tone_text": {
"type": "string"
},
"style_text": {
"type": "string"
},
"language_text": {
"type": "string"
}
},
"required": [
"rep_name",
"rep_role",
"tone_text",
"style_text",
"language_text"
],
"additionalProperties": false,
"description": "Per field: the value the reps share, or the first rep's value when they differ."
},
"mixed": {
"type": "array",
"items": {
"type": "string",
"enum": [
"rep_name",
"rep_role",
"tone_text",
"style_text",
"language_text"
]
},
"description": "Fields whose value differs across the reps in scope."
},
"rep_count": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"unconfigured_count": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "Reps in scope with no live setter variant yet."
}
},
"required": [
"rep_ids",
"values",
"mixed",
"rep_count",
"unconfigured_count"
],
"additionalProperties": false
}setter.persona.set
PUT/v1/setter/persona
Write persona fields onto the live setter variant of each named rep.
Only the fields sent are written, onto every rep in rep_ids, so a field left out keeps each rep's own value. A rep with no live variant gets one created and published, as in the app. Every rep id is checked before anything is written: one foreign id and nothing changes.
| Operation id | setter.persona.set |
| Scopes | setter:write |
| Rate class | `write` |
| Idempotency | Not applicable |
| Keys | Developer keys |
| Reps | A key restricted to reps sees only data of its own reps |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
rep_ids | string[] | yes | The reps in scope: repeated, or as one comma-separated value. Every id must be one of the key's reps.. 1 to 50 items |
language_text | string | no | Up to 4000 characters. |
rep_name | string | no | Up to 4000 characters. |
rep_role | string | no | Up to 4000 characters. |
style_text | string | no | Up to 4000 characters. |
tone_text | string | no | Up to 4000 characters. |
Response 200
| Field | Type | Required | Description |
|---|---|---|---|
affected_count | integer | yes | -9007199254740991 to 9007199254740991 |
created_count | integer | yes | Reps that had no live variant and got a new published one.. -9007199254740991 to 9007199254740991 |
mixed | ("rep_name" | "rep_role" | "tone_text" | "style_text" | "language_text")[] | yes | Fields whose value differs across the reps in scope. |
rep_count | integer | yes | -9007199254740991 to 9007199254740991 |
rep_ids | uuid[] | yes | |
unconfigured_count | integer | yes | Reps in scope with no live setter variant yet.. -9007199254740991 to 9007199254740991 |
values | object | yes | Per field: the value the reps share, or the first rep's value when they differ. |
Errors
| Status | Code | When |
|---|---|---|
| 400 | `VALIDATION_FAILED_400` | A field is missing or malformed; fields names each one. |
| 404 | `REP_NOT_FOUND_404` | A rep does not exist in this workspace, is archived, or is outside the key's rep restriction. |
Every operation can also answer the shared errors: authentication, scopes, rate limits and validation.
Example
curl -X PUT "https://api.dmhero.ai/v1/setter/persona" \
-H "Authorization: Bearer $DMHERO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"rep_ids": [
"3f6c2a9e-8b1d-4c7a-9e2f-5d4b3a2c1e0f"
],
"tone_text": "Warm and direct, never pushy."
}'JSON Schema
{
"type": "object",
"properties": {
"rep_ids": {
"minItems": 1,
"maxItems": 50,
"type": "array",
"items": {
"type": "string"
},
"description": "The reps in scope: repeated, or as one comma-separated value. Every id must be one of the key's reps."
},
"rep_name": {
"type": "string",
"description": "Up to 4000 characters."
},
"rep_role": {
"type": "string",
"description": "Up to 4000 characters."
},
"tone_text": {
"type": "string",
"description": "Up to 4000 characters."
},
"style_text": {
"type": "string",
"description": "Up to 4000 characters."
},
"language_text": {
"type": "string",
"description": "Up to 4000 characters."
}
},
"required": [
"rep_ids"
]
}{
"type": "object",
"properties": {
"rep_ids": {
"type": "array",
"items": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
}
},
"values": {
"type": "object",
"properties": {
"rep_name": {
"type": "string"
},
"rep_role": {
"type": "string"
},
"tone_text": {
"type": "string"
},
"style_text": {
"type": "string"
},
"language_text": {
"type": "string"
}
},
"required": [
"rep_name",
"rep_role",
"tone_text",
"style_text",
"language_text"
],
"additionalProperties": false,
"description": "Per field: the value the reps share, or the first rep's value when they differ."
},
"mixed": {
"type": "array",
"items": {
"type": "string",
"enum": [
"rep_name",
"rep_role",
"tone_text",
"style_text",
"language_text"
]
},
"description": "Fields whose value differs across the reps in scope."
},
"rep_count": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"unconfigured_count": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "Reps in scope with no live setter variant yet."
},
"affected_count": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"created_count": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "Reps that had no live variant and got a new published one."
}
},
"required": [
"rep_ids",
"values",
"mixed",
"rep_count",
"unconfigured_count",
"affected_count",
"created_count"
],
"additionalProperties": false
}setter.test
POST/v1/setter/test
Run the AI Setter on a typed thread with an inline configuration and get its next reply.
The Test Chat sandbox: nothing is saved, nothing is sent, no DM limit is used. The reply runs through the same reaction gate as the live setter; with goal_tool google_calendar it reads the workspace's free/busy and answers what the reply's booking would have done, marked simulated (no event, no hold). Each call is one or two model calls and is metered like the app's Test Chat. At most 30 calls a minute per key. A thread needs at least one prospect message.
| Operation id | setter.test |
| Scopes | setter:write |
| Rate class | `heavy` |
| Idempotency | Not applicable |
| Keys | Developer keys |
| Reps | A key restricted to reps sees only data of its own reps |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
rep_id | string | yes | The rep whose knowledge base and timezone the turn uses. |
thread | object[] | yes | 1 to 100 items |
config | object | no | The same fields as a setter variant, validated by the app's editor rules. Omitted fields take the defaults. |
lead | object | no |
Response 200
| Field | Type | Required | Description |
|---|---|---|---|
bubbles | string[] | yes | |
message | string | yes | The reply text, exactly what the live setter would send. |
proposed_reaction | string | null | yes | |
reaction | object | null | yes | |
reaction_blocked_by | string | null | yes | |
calendar | object | no | Only with goal_tool google_calendar. |
Errors
| Status | Code | When |
|---|---|---|
| 400 | `VALIDATION_FAILED_400` | A field is missing or malformed; fields names each one. |
| 403 | `GOOGLE_CALENDAR_NOT_ENABLED_403` | Google Calendar booking is not enabled for this organization yet. |
| 404 | `REP_NOT_FOUND_404` | A rep does not exist in this workspace, is archived, or is outside the key's rep restriction. |
| 409 | `CALENDAR_NOT_CONNECTED_409` | goal_tool is google_calendar and the workspace has no healthy Google Calendar connection. |
| 429 | `SETTER_TEST_RATE_LIMITED_429` | More than 30 Test Chat calls in a minute for this key (rotations share the count). |
| 502 | `SETTER_TEST_FAILED_502` | The reply could not be generated: a model, calendar or storage call failed while answering the turn. Retry later. |
Every operation can also answer the shared errors: authentication, scopes, rate limits and validation.
Example
curl -X POST "https://api.dmhero.ai/v1/setter/test" \
-H "Authorization: Bearer $DMHERO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"rep_id": "string",
"thread": [
{
"from_prospect": true,
"text": "string"
}
]
}'JSON Schema
{
"type": "object",
"properties": {
"rep_id": {
"type": "string",
"description": "The rep whose knowledge base and timezone the turn uses."
},
"config": {
"type": "object",
"properties": {
"goal_text": {
"type": "string"
},
"goal_link": {
"type": [
"string",
"null"
]
},
"goal_tool": {
"description": "manual, calendly, link or google_calendar.",
"type": "string"
},
"goal_link_status": {
"type": "string"
},
"key_elements_text": {
"type": "string"
},
"avoid_text": {
"type": "string"
},
"offer_text": {
"type": "string"
},
"icp_text": {
"type": "string"
},
"qualifying_text": {
"type": "string"
},
"disqualify_text": {
"type": "string"
},
"tone_text": {
"type": "string"
},
"style_text": {
"type": "string"
},
"language_text": {
"type": "string"
},
"phrases_text": {
"type": "string"
},
"rep_name": {
"type": "string"
},
"rep_role": {
"type": "string"
},
"message_style": {
"type": "string"
},
"objection_mode": {
"type": "string"
},
"few_shot": {
"type": "array",
"items": {
"type": "object",
"properties": {
"prospect": {
"type": "string"
},
"reply": {
"type": "string"
}
},
"required": [
"prospect",
"reply"
]
}
},
"objections": {
"type": "array",
"items": {
"type": "object",
"properties": {
"objection": {
"type": "string"
},
"approach": {
"type": "string"
}
},
"required": [
"objection",
"approach"
]
}
},
"reaction_frequency": {
"type": "string"
},
"reaction_emojis": {
"type": "array",
"items": {
"type": "string"
}
},
"reaction_rules": {
"type": "array",
"items": {
"type": "object",
"properties": {
"emoji": {
"type": "string"
},
"when": {
"type": "string"
}
},
"required": [
"emoji",
"when"
]
}
},
"booking_config": {
"type": "object",
"properties": {
"duration_min": {
"type": "number"
},
"buffer_min": {
"type": "number"
},
"working_hours": {
"description": "Per weekday, up to 4 [\"HH:MM\", \"HH:MM\"] intervals.",
"type": "object",
"properties": {
"mon": {
"type": "array",
"items": {
"type": "array",
"prefixItems": [
{
"type": "string"
},
{
"type": "string"
}
],
"items": false,
"minItems": 2,
"maxItems": 2
}
},
"tue": {
"type": "array",
"items": {
"type": "array",
"prefixItems": [
{
"type": "string"
},
{
"type": "string"
}
],
"items": false,
"minItems": 2,
"maxItems": 2
}
},
"wed": {
"type": "array",
"items": {
"type": "array",
"prefixItems": [
{
"type": "string"
},
{
"type": "string"
}
],
"items": false,
"minItems": 2,
"maxItems": 2
}
},
"thu": {
"type": "array",
"items": {
"type": "array",
"prefixItems": [
{
"type": "string"
},
{
"type": "string"
}
],
"items": false,
"minItems": 2,
"maxItems": 2
}
},
"fri": {
"type": "array",
"items": {
"type": "array",
"prefixItems": [
{
"type": "string"
},
{
"type": "string"
}
],
"items": false,
"minItems": 2,
"maxItems": 2
}
},
"sat": {
"type": "array",
"items": {
"type": "array",
"prefixItems": [
{
"type": "string"
},
{
"type": "string"
}
],
"items": false,
"minItems": 2,
"maxItems": 2
}
},
"sun": {
"type": "array",
"items": {
"type": "array",
"prefixItems": [
{
"type": "string"
},
{
"type": "string"
}
],
"items": false,
"minItems": 2,
"maxItems": 2
}
}
}
},
"min_notice_min": {
"type": "number"
},
"allow_same_day": {
"type": "boolean"
},
"horizon_days": {
"type": "number"
},
"max_per_day": {
"type": [
"number",
"null"
]
},
"meeting_form": {
"type": "string",
"enum": [
"meet",
"phone"
]
},
"event_title": {
"type": "string"
},
"event_description": {
"type": "string"
},
"prospect_tz_mode": {
"type": "string",
"enum": [
"campaign",
"fixed"
]
},
"prospect_tz": {
"type": [
"string",
"null"
]
},
"target_calendar_id": {
"type": "string"
},
"busy_calendar_ids": {
"type": "array",
"items": {
"type": "string"
}
}
},
"description": "Read only when goal_tool is google_calendar. Omitted fields take the defaults."
}
},
"description": "The same fields as a setter variant, validated by the app's editor rules. Omitted fields take the defaults."
},
"thread": {
"minItems": 1,
"maxItems": 100,
"type": "array",
"items": {
"type": "object",
"properties": {
"from_prospect": {
"type": "boolean"
},
"text": {
"type": "string",
"maxLength": 4000
},
"our_reaction": {
"description": "A reaction an earlier answer approved on this prospect bubble.",
"type": [
"string",
"null"
]
},
"proposals": {
"description": "On our bubble: the times an earlier answer proposed.",
"maxItems": 5,
"type": "array",
"items": {
"type": "object",
"properties": {
"starts_at": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"
},
"label": {
"type": "string"
}
},
"required": [
"starts_at",
"label"
]
}
}
},
"required": [
"from_prospect",
"text"
]
}
},
"lead": {
"type": "object",
"properties": {
"name": {
"anyOf": [
{
"type": "string",
"maxLength": 200
},
{
"type": "null"
}
]
},
"niche": {
"anyOf": [
{
"type": "string",
"maxLength": 200
},
{
"type": "null"
}
]
},
"handle": {
"anyOf": [
{
"type": "string",
"maxLength": 100
},
{
"type": "null"
}
]
}
}
}
},
"required": [
"rep_id",
"thread"
]
}{
"type": "object",
"properties": {
"message": {
"type": "string",
"description": "The reply text, exactly what the live setter would send."
},
"bubbles": {
"type": "array",
"items": {
"type": "string"
}
},
"reaction": {
"anyOf": [
{
"type": "object",
"properties": {
"emoji": {
"type": "string"
},
"target_index": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
}
},
"required": [
"emoji",
"target_index"
],
"additionalProperties": false
},
{
"type": "null"
}
]
},
"reaction_blocked_by": {
"type": [
"string",
"null"
]
},
"proposed_reaction": {
"type": [
"string",
"null"
]
},
"calendar": {
"description": "Only with goal_tool google_calendar.",
"type": "object",
"properties": {
"scheduling": {
"type": "object",
"properties": {
"phase": {
"type": "string"
},
"tz": {
"type": [
"string",
"null"
]
}
},
"required": [
"phase",
"tz"
],
"additionalProperties": false
},
"ranges_block": {
"type": [
"string",
"null"
]
},
"proposals": {
"type": "array",
"items": {
"type": "object",
"properties": {
"starts_at": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"
},
"label": {
"type": "string"
},
"valid": {
"type": "boolean"
}
},
"required": [
"starts_at",
"label",
"valid"
],
"additionalProperties": false
}
},
"booking": {
"anyOf": [
{
"type": "object",
"properties": {
"label": {
"type": "string"
},
"email": {
"type": "string"
},
"simulated": {
"type": "boolean",
"const": true
},
"valid": {
"type": "boolean"
},
"reason": {
"anyOf": [
{
"type": "string",
"enum": [
"outside_rules",
"invalid_email",
"calendar_unavailable"
]
},
{
"type": "null"
}
]
}
},
"required": [
"label",
"email",
"simulated",
"valid",
"reason"
],
"additionalProperties": false
},
{
"type": "null"
}
]
},
"directives_malformed": {
"type": "boolean"
},
"calendar_unavailable": {
"type": [
"string",
"null"
]
}
},
"required": [
"scheduling",
"ranges_block",
"proposals",
"booking",
"directives_malformed",
"calendar_unavailable"
],
"additionalProperties": false
}
},
"required": [
"message",
"bubbles",
"reaction",
"reaction_blocked_by",
"proposed_reaction"
],
"additionalProperties": false
}