Reference
Templates
Templates: 9 operations (templates.list, templates.create, templates.get, templates.update, templates.delete, templates.stats, templates.versions.list, templates.spintax.propose, templates.validate).
| Method | Path | Operation |
|---|---|---|
GET | /v1/templates | templates.list |
POST | /v1/templates | templates.create |
GET | /v1/templates/{template_id} | templates.get |
PATCH | /v1/templates/{template_id} | templates.update |
DELETE | /v1/templates/{template_id} | templates.delete |
GET | /v1/templates/{template_id}/stats | templates.stats |
GET | /v1/templates/{template_id}/versions | templates.versions.list |
POST | /v1/templates/spintax-proposals | templates.spintax.propose |
POST | /v1/templates/validate | templates.validate |
templates.list
GET/v1/templates
List the workspace's message templates, newest first.
| Operation id | templates.list |
| Scopes | templates:read |
| Rate class | `read` |
| Idempotency | Not applicable |
| Keys | Developer keys |
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
limit | integer | no | 1 to 200, default 50 |
cursor | string | no | 1 to 2048 characters |
category | "first_touch" | "follow_up_1" | "follow_up_2" | "follow_up_3" | "breakup" | no |
Response 200
| Field | Type | Required | Description |
|---|---|---|---|
data | object[] | yes | |
has_more | boolean | yes | |
next_cursor | string | null | yes |
Errors
Every operation can also answer the shared errors: authentication, scopes, rate limits and validation.
Example
curl "https://api.dmhero.ai/v1/templates" \
-H "Authorization: Bearer $DMHERO_API_KEY"JSON Schema
{
"type": "object",
"properties": {
"data": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"category": {
"type": "string",
"enum": [
"first_touch",
"follow_up_1",
"follow_up_2",
"follow_up_3",
"breakup"
]
},
"content": {
"type": "string"
},
"variant": {
"anyOf": [
{
"type": "string",
"enum": [
"A",
"B"
]
},
{
"type": "null"
}
]
},
"platform": {
"type": "string"
},
"version": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"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",
"name",
"category",
"content",
"variant",
"platform",
"version",
"created_at",
"updated_at"
],
"additionalProperties": false
}
},
"has_more": {
"type": "boolean"
},
"next_cursor": {
"type": [
"string",
"null"
]
}
},
"required": [
"data",
"has_more",
"next_cursor"
],
"additionalProperties": false
}templates.create
POST/v1/templates
Create a message template.
The content may carry placeholders ({{first_name}}, {{custom.<key>}}) and version groups ({{option|option}}); check it first with POST /v1/templates/validate. Every template targets Instagram.
| Operation id | templates.create |
| Scopes | templates:write |
| Rate class | `write` |
| Idempotency | `Idempotency-Key` accepted |
| Keys | Developer keys |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
category | "first_touch" | "follow_up_1" | "follow_up_2" | "follow_up_3" | "breakup" | yes | |
content | string | yes | |
name | string | yes | |
variant | "A" | "B" | null | no |
Response 201
| Field | Type | Required | Description |
|---|---|---|---|
category | "first_touch" | "follow_up_1" | "follow_up_2" | "follow_up_3" | "breakup" | yes | |
content | string | yes | |
created_at | date-time | yes | |
id | string | yes | |
name | string | yes | |
platform | string | yes | |
updated_at | date-time | yes | |
variant | "A" | "B" | null | yes | |
version | integer | yes | -9007199254740991 to 9007199254740991 |
Errors
| Status | Code | When |
|---|---|---|
| 400 | `TEMPLATE_SPINTAX_INVALID_400` | A {{option|option}} group in the content does not parse (unclosed, nested or with an empty option). |
| 400 | `VALIDATION_FAILED_400` | A field is out of range: name 1 to 80 characters, content 1 to 2000 characters after trimming. |
Every operation can also answer the shared errors: authentication, scopes, rate limits and validation.
Example
curl -X POST "https://api.dmhero.ai/v1/templates" \
-H "Authorization: Bearer $DMHERO_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"name": "string",
"category": "first_touch",
"content": "string"
}'JSON Schema
{
"type": "object",
"properties": {
"name": {
"type": "string"
},
"category": {
"type": "string",
"enum": [
"first_touch",
"follow_up_1",
"follow_up_2",
"follow_up_3",
"breakup"
]
},
"content": {
"type": "string"
},
"variant": {
"anyOf": [
{
"type": "string",
"enum": [
"A",
"B"
]
},
{
"type": "null"
}
]
}
},
"required": [
"name",
"category",
"content"
]
}{
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"category": {
"type": "string",
"enum": [
"first_touch",
"follow_up_1",
"follow_up_2",
"follow_up_3",
"breakup"
]
},
"content": {
"type": "string"
},
"variant": {
"anyOf": [
{
"type": "string",
"enum": [
"A",
"B"
]
},
{
"type": "null"
}
]
},
"platform": {
"type": "string"
},
"version": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"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",
"name",
"category",
"content",
"variant",
"platform",
"version",
"created_at",
"updated_at"
],
"additionalProperties": false
}templates.get
GET/v1/templates/{template_id}
Read one template.
| Operation id | templates.get |
| Scopes | templates:read |
| Rate class | `read` |
| Idempotency | Not applicable |
| Keys | Developer keys |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
template_id | string | yes | 1 to 64 characters |
Response 200
| Field | Type | Required | Description |
|---|---|---|---|
category | "first_touch" | "follow_up_1" | "follow_up_2" | "follow_up_3" | "breakup" | yes | |
content | string | yes | |
created_at | date-time | yes | |
id | string | yes | |
name | string | yes | |
platform | string | yes | |
updated_at | date-time | yes | |
variant | "A" | "B" | null | yes | |
version | integer | yes | -9007199254740991 to 9007199254740991 |
Errors
| Status | Code | When |
|---|---|---|
| 404 | `TEMPLATE_NOT_FOUND_404` | No template with this id exists in the key's workspace. |
Every operation can also answer the shared errors: authentication, scopes, rate limits and validation.
Example
curl "https://api.dmhero.ai/v1/templates/string" \
-H "Authorization: Bearer $DMHERO_API_KEY"JSON Schema
{
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"category": {
"type": "string",
"enum": [
"first_touch",
"follow_up_1",
"follow_up_2",
"follow_up_3",
"breakup"
]
},
"content": {
"type": "string"
},
"variant": {
"anyOf": [
{
"type": "string",
"enum": [
"A",
"B"
]
},
{
"type": "null"
}
]
},
"platform": {
"type": "string"
},
"version": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"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",
"name",
"category",
"content",
"variant",
"platform",
"version",
"created_at",
"updated_at"
],
"additionalProperties": false
}templates.update
PATCH/v1/templates/{template_id}
Change a template's name, category, content or variant.
Send only the fields to change; variant null clears it. A content change snapshots the previous content into the version history and bumps version.
| Operation id | templates.update |
| Scopes | templates:write |
| Rate class | `write` |
| Idempotency | Not applicable |
| Keys | Developer keys |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
template_id | string | yes | 1 to 64 characters |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
category | "first_touch" | "follow_up_1" | "follow_up_2" | "follow_up_3" | "breakup" | no | |
content | string | no | |
name | string | no | |
variant | "A" | "B" | null | no |
Response 200
| Field | Type | Required | Description |
|---|---|---|---|
category | "first_touch" | "follow_up_1" | "follow_up_2" | "follow_up_3" | "breakup" | yes | |
content | string | yes | |
created_at | date-time | yes | |
id | string | yes | |
name | string | yes | |
platform | string | yes | |
updated_at | date-time | yes | |
variant | "A" | "B" | null | yes | |
version | integer | yes | -9007199254740991 to 9007199254740991 |
Errors
| Status | Code | When |
|---|---|---|
| 400 | `TEMPLATE_SPINTAX_INVALID_400` | A {{option|option}} group in the content does not parse (unclosed, nested or with an empty option). |
| 400 | `VALIDATION_FAILED_400` | A field is out of range: name 1 to 80 characters, content 1 to 2000 characters after trimming. |
| 404 | `TEMPLATE_NOT_FOUND_404` | No template with this id exists in the key's workspace. |
Every operation can also answer the shared errors: authentication, scopes, rate limits and validation.
Example
curl -X PATCH "https://api.dmhero.ai/v1/templates/string" \
-H "Authorization: Bearer $DMHERO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "string",
"category": "first_touch",
"content": "string",
"variant": "A"
}'JSON Schema
{
"type": "object",
"properties": {
"name": {
"type": "string"
},
"category": {
"type": "string",
"enum": [
"first_touch",
"follow_up_1",
"follow_up_2",
"follow_up_3",
"breakup"
]
},
"content": {
"type": "string"
},
"variant": {
"anyOf": [
{
"type": "string",
"enum": [
"A",
"B"
]
},
{
"type": "null"
}
]
}
}
}{
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"category": {
"type": "string",
"enum": [
"first_touch",
"follow_up_1",
"follow_up_2",
"follow_up_3",
"breakup"
]
},
"content": {
"type": "string"
},
"variant": {
"anyOf": [
{
"type": "string",
"enum": [
"A",
"B"
]
},
{
"type": "null"
}
]
},
"platform": {
"type": "string"
},
"version": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"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",
"name",
"category",
"content",
"variant",
"platform",
"version",
"created_at",
"updated_at"
],
"additionalProperties": false
}templates.delete
DELETE/v1/templates/{template_id}
Delete a template and its version history.
Campaign steps that used the template keep their place with no template, and sent messages keep their text.
| Operation id | templates.delete |
| Scopes | templates: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 |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
template_id | string | yes | 1 to 64 characters |
Response 204
No body.
Errors
| Status | Code | When |
|---|---|---|
| 404 | `TEMPLATE_NOT_FOUND_404` | No template with this id exists in the key's workspace. |
Every operation can also answer the shared errors: authentication, scopes, rate limits and validation.
Example
curl -X DELETE "https://api.dmhero.ai/v1/templates/string" \
-H "Authorization: Bearer $DMHERO_API_KEY"templates.stats
GET/v1/templates/{template_id}/stats
Sends and replies of one template.
total_sent counts every DM sent through the template, follow-ups included; leads_reached the distinct leads they went to; total_replied those of them who answered after the first DM or were marked replied or converted. reply_rate is total_replied / leads_reached as a percentage with one decimal. Inbound leads are left out.
| Operation id | templates.stats |
| Scopes | templates:read |
| Rate class | `read`, costs 5 per call |
| Idempotency | Not applicable |
| Keys | Developer keys |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
template_id | string | yes | 1 to 64 characters |
Response 200
| Field | Type | Required | Description |
|---|---|---|---|
leads_reached | integer | yes | -9007199254740991 to 9007199254740991 |
reply_rate | number | yes | |
template_id | string | yes | |
total_replied | integer | yes | -9007199254740991 to 9007199254740991 |
total_sent | integer | yes | -9007199254740991 to 9007199254740991 |
Errors
| Status | Code | When |
|---|---|---|
| 404 | `TEMPLATE_NOT_FOUND_404` | No template with this id exists in the key's workspace. |
Every operation can also answer the shared errors: authentication, scopes, rate limits and validation.
Example
curl "https://api.dmhero.ai/v1/templates/string/stats" \
-H "Authorization: Bearer $DMHERO_API_KEY"JSON Schema
{
"type": "object",
"properties": {
"template_id": {
"type": "string"
},
"total_sent": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"leads_reached": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"total_replied": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"reply_rate": {
"type": "number"
}
},
"required": [
"template_id",
"total_sent",
"leads_reached",
"total_replied",
"reply_rate"
],
"additionalProperties": false
}templates.versions.list
GET/v1/templates/{template_id}/versions
List a template's earlier contents, newest version first.
The current content is on the template itself, not in this list.
| Operation id | templates.versions.list |
| Scopes | templates:read |
| Rate class | `read` |
| Idempotency | Not applicable |
| Keys | Developer keys |
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
template_id | string | yes | 1 to 64 characters |
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
limit | integer | no | 1 to 200, default 50 |
cursor | string | no | 1 to 2048 characters |
Response 200
| Field | Type | Required | Description |
|---|---|---|---|
data | object[] | yes | |
has_more | boolean | yes | |
next_cursor | string | null | yes |
Errors
| Status | Code | When |
|---|---|---|
| 404 | `TEMPLATE_NOT_FOUND_404` | No template with this id exists in the key's workspace. |
Every operation can also answer the shared errors: authentication, scopes, rate limits and validation.
Example
curl "https://api.dmhero.ai/v1/templates/string/versions" \
-H "Authorization: Bearer $DMHERO_API_KEY"JSON Schema
{
"type": "object",
"properties": {
"data": {
"type": "array",
"items": {
"type": "object",
"properties": {
"version": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"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))$"
}
},
"required": [
"version",
"content",
"created_at"
],
"additionalProperties": false
}
},
"has_more": {
"type": "boolean"
},
"next_cursor": {
"type": [
"string",
"null"
]
}
},
"required": [
"data",
"has_more",
"next_cursor"
],
"additionalProperties": false
}templates.spintax.propose
POST/v1/templates/spintax-proposals
Propose version groups for a template body (AI).
Returns the body with proposed {{option|option}} groups. Nothing is saved: send the content to templates.create or templates.update to keep it. Ten proposals per minute per key creator, shared with the app. A replay of an Idempotency-Key answers { replayed: true } without the proposal, which is never stored. A 422 is stored against its Idempotency-Key like every refusal of the handler, so a retry after it needs a new key; a 429 and a 502 release the key, so the same key may be retried after Retry-After.
| Operation id | templates.spintax.propose |
| Scopes | templates:write |
| Rate class | `heavy` |
| Idempotency | `Idempotency-Key` accepted |
| Keys | Developer keys |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
content | string | yes | at most 20000 characters |
Response 200
| Field | Type | Required | Description |
|---|---|---|---|
combinations | integer | yes | -9007199254740991 to 9007199254740991 |
content | string | yes | |
groups | integer | yes | -9007199254740991 to 9007199254740991 |
Errors
| Status | Code | When |
|---|---|---|
| 400 | `TEMPLATE_SPINTAX_INVALID_400` | A {{option|option}} group in the content does not parse (unclosed, nested or with an empty option). |
| 400 | `VALIDATION_FAILED_400` | A field is out of range: name 1 to 80 characters, content 1 to 2000 characters after trimming. |
| 422 | `TEMPLATE_SPINTAX_EMPTY_422` | Nothing in the body can be safely varied. |
| 422 | `TEMPLATE_SPINTAX_REFUSED_422` | The model declined to vary this body. |
| 429 | `TEMPLATE_SPINTAX_RATE_LIMITED_429` | More than ten proposals in a minute for the key's creator, counted together with the app. |
| 502 | `TEMPLATE_SPINTAX_FAILED_502` | The model call failed, ran past 110 seconds, or its answer could not be read. 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/templates/spintax-proposals" \
-H "Authorization: Bearer $DMHERO_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"content": "string"
}'JSON Schema
{
"type": "object",
"properties": {
"content": {
"type": "string",
"maxLength": 20000
}
},
"required": [
"content"
]
}{
"type": "object",
"properties": {
"content": {
"type": "string"
},
"groups": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"combinations": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
}
},
"required": [
"content",
"groups",
"combinations"
],
"additionalProperties": false
}templates.validate
POST/v1/templates/validate
Check a template body before saving it.
valid says whether templates.create would accept the content. unknown_custom_fields lists {{custom.<key>}} tokens naming a field the workspace has not defined: such a template saves, but every lead is withheld from sending until the field exists and has a value. spintax is null when the body has no version groups or they do not parse.
| Operation id | templates.validate |
| Scopes | templates:read |
| Rate class | `read` |
| Idempotency | Not applicable |
| Keys | Developer keys |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
content | string | yes | at most 20000 characters |
Response 200
| Field | Type | Required | Description |
|---|---|---|---|
custom_field_keys | string[] | yes | |
errors | object[] | yes | |
placeholders | string[] | yes | |
spintax | object | null | yes | |
unknown_custom_fields | string[] | yes | |
valid | boolean | yes |
Errors
Every operation can also answer the shared errors: authentication, scopes, rate limits and validation.
Example
curl -X POST "https://api.dmhero.ai/v1/templates/validate" \
-H "Authorization: Bearer $DMHERO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "string"
}'JSON Schema
{
"type": "object",
"properties": {
"content": {
"type": "string",
"maxLength": 20000
}
},
"required": [
"content"
]
}{
"type": "object",
"properties": {
"valid": {
"type": "boolean"
},
"errors": {
"type": "array",
"items": {
"type": "object",
"properties": {
"code": {
"type": "string"
},
"message": {
"type": "string"
}
},
"required": [
"code",
"message"
],
"additionalProperties": false
}
},
"placeholders": {
"type": "array",
"items": {
"type": "string"
}
},
"custom_field_keys": {
"type": "array",
"items": {
"type": "string"
}
},
"unknown_custom_fields": {
"type": "array",
"items": {
"type": "string"
}
},
"spintax": {
"anyOf": [
{
"type": "object",
"properties": {
"groups": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"combinations": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
}
},
"required": [
"groups",
"combinations"
],
"additionalProperties": false
},
{
"type": "null"
}
]
}
},
"required": [
"valid",
"errors",
"placeholders",
"custom_field_keys",
"unknown_custom_fields",
"spintax"
],
"additionalProperties": false
}