API reference

Checks

Run the pre-send checks from your own editor, read them on campaigns and templates, and react to campaign.failed

Kula runs pre-send checks on campaigns, flow emails and transactional templates: variables, size, images, links. If your users write emails in your own product, call the checks from your editor and show the findings there: they never see the Kula dashboard.

Check an email

POST /v1/checks

Runs the checks on a subject and a content. Nothing is created or sent. Works with a sending access key.

content
string required
Markdown, or HTML with contentFormat: "HTML".
subject
string
The subject line.
preheader
string
The preview text.
contentFormat
string
MARKDOWN (default) or HTML.
listId
string
The list the email goes to: missing data is counted among its subscribers. Without it, among the active contacts of the space.
segmentId
string
Narrows the list.
transactional
boolean
A transactional email: data.* variables are allowed, no contacts are counted.
curl -X POST https://api.kulamail.com/v1/checks \
  -H "Authorization: Bearer ml_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{ "subject": "New post", "content": "Hi {{ contact.first_name }}, read it on <https://bit.ly/x>", "listId": "5a8e2c1f-0b3d-4e6a-9f7c-2d1e8b4a6c3f" }'
200 OK
{
  "checks": [
    {
      "code": "missing_variable_data",
      "level": "WARNING",
      "message": "412 of 3980 recipients have no first name: {{ contact.first_name }} will be empty for them. Add a default, such as {{ contact.first_name | default: \"there\" }}.",
      "detail": { "variable": "contact.first_name", "missing": 412, "total": 3980 }
    },
    {
      "code": "link_shortener",
      "level": "WARNING",
      "message": "This link goes through a public link shortener (bit.ly), which spam filters distrust. Use the full address: https://bit.ly/x",
      "detail": { "url": "https://bit.ly/x" }
    }
  ],
  "checkedAt": "2026-10-19T09:12:04Z",
  "warnings": 2,
  "blocked": false,
  "linksNotChecked": 0
}

Links are requested to find broken ones (30 at most, results kept an hour), so the call can take a few seconds.

Codes

message is written for a person, in English. To translate, use code and detail.

CodeLeveldetail
missing_variable_dataWARNINGvariable, missing, total
unknown_variableWARNINGvariable
broken_tagWARNINGtag
gmail_clippingWARNINGbytes, limit
image_onlyWARNINGimages, textLength
missing_altWARNINGcount, src (first image)
subject_missing, subject_capsWARNING
subject_longWARNINGlength
subject_punctuationWARNINGfound
broken_linkWARNINGurl, status (null: the domain doesn't exist)
link_shortener, ip_link, insecure_linkWARNINGurl
misleading_linkWARNINGurl, shown
blocklisted_linkBLOCKurl, threats
render_failedWARNING

Checks on campaigns and templates

A blocklisted_link refuses scheduling and publishing with 409 content_blocked, and the message names the link. A scheduled campaign is checked again when it leaves: if a link turned dangerous meanwhile, the campaign becomes FAILED and the campaign.failed webhook says why.