Menu

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).

MethodPathOperation
GET/v1/templatestemplates.list
POST/v1/templatestemplates.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}/statstemplates.stats
GET/v1/templates/{template_id}/versionstemplates.versions.list
POST/v1/templates/spintax-proposalstemplates.spintax.propose
POST/v1/templates/validatetemplates.validate

templates.list

GET/v1/templates

List the workspace's message templates, newest first.

Operation idtemplates.list
Scopestemplates:read
Rate class`read`
IdempotencyNot applicable
KeysDeveloper keys

Query parameters

NameTypeRequiredDescription
limitintegerno1 to 200, default 50
cursorstringno1 to 2048 characters
category"first_touch" | "follow_up_1" | "follow_up_2" | "follow_up_3" | "breakup"no

Response 200

FieldTypeRequiredDescription
dataobject[]yes
has_morebooleanyes
next_cursorstring | nullyes

Errors

Every operation can also answer the shared errors: authentication, scopes, rate limits and validation.

Example

bash
curl "https://api.dmhero.ai/v1/templates" \
  -H "Authorization: Bearer $DMHERO_API_KEY"
JSON Schema
Response 200
{
  "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 idtemplates.create
Scopestemplates:write
Rate class`write`
Idempotency`Idempotency-Key` accepted
KeysDeveloper keys

Request body

FieldTypeRequiredDescription
category"first_touch" | "follow_up_1" | "follow_up_2" | "follow_up_3" | "breakup"yes
contentstringyes
namestringyes
variant"A" | "B" | nullno

Response 201

FieldTypeRequiredDescription
category"first_touch" | "follow_up_1" | "follow_up_2" | "follow_up_3" | "breakup"yes
contentstringyes
created_atdate-timeyes
idstringyes
namestringyes
platformstringyes
updated_atdate-timeyes
variant"A" | "B" | nullyes
versionintegeryes-9007199254740991 to 9007199254740991

Errors

StatusCodeWhen
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

bash
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
Request body
{
  "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"
  ]
}
Response 201
{
  "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 idtemplates.get
Scopestemplates:read
Rate class`read`
IdempotencyNot applicable
KeysDeveloper keys

Path parameters

NameTypeRequiredDescription
template_idstringyes1 to 64 characters

Response 200

FieldTypeRequiredDescription
category"first_touch" | "follow_up_1" | "follow_up_2" | "follow_up_3" | "breakup"yes
contentstringyes
created_atdate-timeyes
idstringyes
namestringyes
platformstringyes
updated_atdate-timeyes
variant"A" | "B" | nullyes
versionintegeryes-9007199254740991 to 9007199254740991

Errors

StatusCodeWhen
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

bash
curl "https://api.dmhero.ai/v1/templates/string" \
  -H "Authorization: Bearer $DMHERO_API_KEY"
JSON Schema
Response 200
{
  "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 idtemplates.update
Scopestemplates:write
Rate class`write`
IdempotencyNot applicable
KeysDeveloper keys

Path parameters

NameTypeRequiredDescription
template_idstringyes1 to 64 characters

Request body

FieldTypeRequiredDescription
category"first_touch" | "follow_up_1" | "follow_up_2" | "follow_up_3" | "breakup"no
contentstringno
namestringno
variant"A" | "B" | nullno

Response 200

FieldTypeRequiredDescription
category"first_touch" | "follow_up_1" | "follow_up_2" | "follow_up_3" | "breakup"yes
contentstringyes
created_atdate-timeyes
idstringyes
namestringyes
platformstringyes
updated_atdate-timeyes
variant"A" | "B" | nullyes
versionintegeryes-9007199254740991 to 9007199254740991

Errors

StatusCodeWhen
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

bash
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
Request body
{
  "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"
        }
      ]
    }
  }
}
Response 200
{
  "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 idtemplates.delete
Scopestemplates:write
Rate class`write`
IdempotencyNot applicable
KeysDeveloper keys
DestructiveYes: it removes or stops something that cannot be restored by repeating the call

Path parameters

NameTypeRequiredDescription
template_idstringyes1 to 64 characters

Response 204

No body.

Errors

StatusCodeWhen
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

bash
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 idtemplates.stats
Scopestemplates:read
Rate class`read`, costs 5 per call
IdempotencyNot applicable
KeysDeveloper keys

Path parameters

NameTypeRequiredDescription
template_idstringyes1 to 64 characters

Response 200

FieldTypeRequiredDescription
leads_reachedintegeryes-9007199254740991 to 9007199254740991
reply_ratenumberyes
template_idstringyes
total_repliedintegeryes-9007199254740991 to 9007199254740991
total_sentintegeryes-9007199254740991 to 9007199254740991

Errors

StatusCodeWhen
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

bash
curl "https://api.dmhero.ai/v1/templates/string/stats" \
  -H "Authorization: Bearer $DMHERO_API_KEY"
JSON Schema
Response 200
{
  "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 idtemplates.versions.list
Scopestemplates:read
Rate class`read`
IdempotencyNot applicable
KeysDeveloper keys

Path parameters

NameTypeRequiredDescription
template_idstringyes1 to 64 characters

Query parameters

NameTypeRequiredDescription
limitintegerno1 to 200, default 50
cursorstringno1 to 2048 characters

Response 200

FieldTypeRequiredDescription
dataobject[]yes
has_morebooleanyes
next_cursorstring | nullyes

Errors

StatusCodeWhen
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

bash
curl "https://api.dmhero.ai/v1/templates/string/versions" \
  -H "Authorization: Bearer $DMHERO_API_KEY"
JSON Schema
Response 200
{
  "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 idtemplates.spintax.propose
Scopestemplates:write
Rate class`heavy`
Idempotency`Idempotency-Key` accepted
KeysDeveloper keys

Request body

FieldTypeRequiredDescription
contentstringyesat most 20000 characters

Response 200

FieldTypeRequiredDescription
combinationsintegeryes-9007199254740991 to 9007199254740991
contentstringyes
groupsintegeryes-9007199254740991 to 9007199254740991

Errors

StatusCodeWhen
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

bash
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
Request body
{
  "type": "object",
  "properties": {
    "content": {
      "type": "string",
      "maxLength": 20000
    }
  },
  "required": [
    "content"
  ]
}
Response 200
{
  "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 idtemplates.validate
Scopestemplates:read
Rate class`read`
IdempotencyNot applicable
KeysDeveloper keys

Request body

FieldTypeRequiredDescription
contentstringyesat most 20000 characters

Response 200

FieldTypeRequiredDescription
custom_field_keysstring[]yes
errorsobject[]yes
placeholdersstring[]yes
spintaxobject | nullyes
unknown_custom_fieldsstring[]yes
validbooleanyes

Errors

Every operation can also answer the shared errors: authentication, scopes, rate limits and validation.

Example

bash
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
Request body
{
  "type": "object",
  "properties": {
    "content": {
      "type": "string",
      "maxLength": 20000
    }
  },
  "required": [
    "content"
  ]
}
Response 200
{
  "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
}
Templates | DM Hero Developers