API REFERENCE · Published 2026-10-27 · Updated 2026-10-27 · SecureSMTP

Integration endpoints

Six endpoints for automation tools: check a key, list templates and automations, and turn webhook triggers on and off.

Six endpoints for automation tools such as Zapier, n8n, Make, Pipedream and Activepieces. A tool uses them to check a key, fill its template and automation drop-downs, and turn triggers on and off. You can call them from your own code too.

For all six endpoints

Send the site’s API key in the x-securessmtp-api-key header. Bodies and answers are JSON. A good answer has "ok": true. An error has "ok": false and a reason.

Each site can make 120 calls a minute to these six endpoints together. Above that they answer 429 until the minute has passed. Calls that are refused count too, including 429 answers. Only calls refused because of the key or the site (401 and 403) do not count.

Headers

x-securessmtp-api-keystringrequired
The site’s API key (qcs_live_…). x-securesmtp-api-key and x-qcs-api-key are accepted too. See Sites and API keys.

Errors every endpoint can give

HTTPValueMeaningWhat to do
401missing_api_keyNo key header was sent.Send the key in the x-securessmtp-api-key header.
401invalid_api_keyNo site has this key. Keys stop working as soon as they are rotated.Copy the current key from the dashboard, or rotate it to get a new one.
403site_disabledThe site is disabled.Check GET /blocks/status. See Blocks.
403sending_pausedSending is paused on this site.Check your email, or contact [email protected].
429rate_limitedThe site made more than 120 calls in a minute. The answer has a Retry-After header (seconds).Wait the number of seconds in Retry-After, then try again.

GET /me

GEThttps://securessmtp.com/api/v1/me

Checks that the key works and says which site it belongs to. A tool calls it when someone connects, and names the connection after the site.

curl https://securessmtp.com/api/v1/me \
  -H "x-securessmtp-api-key: $SECURESSMTP_API_KEY"
200
{
  "ok": true,
  "site": {
    "id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
    "name": "Acme Store",
    "domain": "acme.example"
  },
  "plan": "free"
}
Response fields
okbooleanrequired
true.
site.idstringrequired
The site’s ID (UUID).
site.namestringrequired
The site’s name.
site.domainstringrequired
The domain registered for the site.
planstringrequired
The plan of the account that owns the site: free, starter, pro, business or ultima.

The answer never includes the API key.

GET /templates

GEThttps://securessmtp.com/api/v1/templates

Lists the templates saved by the account that owns the site, so a tool can fill a template drop-down. The starter templates from the gallery are not included.

curl https://securessmtp.com/api/v1/templates \
  -H "x-securessmtp-api-key: $SECURESSMTP_API_KEY"
200
{
  "ok": true,
  "templates": [
    {
      "id": "5c0f2e8a-3b7d-4a91-b6e4-9d2f1a7c8e03",
      "slug": "order-shipped",
      "name": "Order shipped",
      "subject": "Your order {{order_number}} has shipped",
      "variables": [
        "first_name",
        "order_number"
      ]
    }
  ]
}
Response fields
okbooleanrequired
true.
templatesobject[]required
One item per template. An empty array when the account has none.
templates[].idstringrequired
The template’s ID.
templates[].slugstringrequired
The template’s slug.
templates[].namestringrequired
The name shown in the dashboard.
templates[].subjectstringrequired
The template’s subject. It can contain {{variables}}.
templates[].variablesstring[]required
The names of the {{variables}} used in the subject, HTML and text. An empty array when the template has none.

To send one, give its id or slug as template to POST /mail/send, with a value for each variable in data. See Templates and variables.

GET /sequences

GEThttps://securessmtp.com/api/v1/sequences

Lists the automations (follow-up sequences) of the account that owns the site, so a tool can fill an automation drop-down.

curl https://securessmtp.com/api/v1/sequences \
  -H "x-securessmtp-api-key: $SECURESSMTP_API_KEY"
200
{
  "ok": true,
  "sequences": [
    {
      "id": "0b7e4c2a-9d1f-4e3b-8a6c-5f2d1e0c9b8a",
      "name": "Welcome series",
      "active": true
    }
  ]
}
Response fields
okbooleanrequired
true.
sequencesobject[]required
One item per sequence. An empty array when the account has none.
sequences[].idstringrequired
The sequence’s ID. Send it as sequence to POST /sequences/enroll.
sequences[].namestringrequired
The name shown in the dashboard.
sequences[].activebooleanrequired
Whether the sequence is turned on. Steps are sent only while it is.

POST /hooks

POSThttps://securessmtp.com/api/v1/hooks

Turns a trigger on. It creates a webhook for the site the key belongs to. From then on SecureSMTP posts every event of that kind to the address you gave. Switching the trigger off is DELETE /hooks/{id}.

Header
Content-Typestringrequired
application/json

Body

urlstringrequired
Where to send the events. It must start with http:// or https:// and be at most 2,048 characters. The host must resolve only to public addresses. Loopback, private, link-local and reserved addresses are refused, and so are SecureSMTP’s own servers.
eventstringrequired
One event name from the Event catalogue. The tools use form.submitted, email.delivered, email.bounced and email.unsubscribed. One hook takes one event. For several events, make several hooks.
sourcestringoptional
The tool that makes the hook: zapier, n8n, make, pipedream, activepieces or api. Anything else, or nothing, is saved as api.

Request

curl -X POST https://securessmtp.com/api/v1/hooks \
  -H "x-securessmtp-api-key: $SECURESSMTP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "url": "https://hooks.zapier.com/hooks/standard/123456/abcdef/",
  "event": "email.delivered",
  "source": "zapier"
}'

Response

201 — a new hook
{
  "ok": true,
  "id": "8e3c5a1f-72d4-4b6a-9f10-c4a2e7d9b563",
  "secret": "whsec_Zk3q9v1XbT7m2LwR8nYc5HaJdE4uPfGs"
}
200 — the hook already existed
{
  "ok": true,
  "id": "8e3c5a1f-72d4-4b6a-9f10-c4a2e7d9b563"
}
Response fields
okbooleanrequired
true.
idstringrequired
The hook’s ID. Keep it: it is what you give to DELETE /hooks/{id}.
secretstringoptional
Only in the 201 answer. It signs every delivery in the X-QCS-Signature header, so keep it to check that an event came from SecureSMTP. It cannot be fetched again.

Errors

HTTPValueMeaningWhat to do
400invalid_payloadThe body is not valid JSON, or url or event is missing or too long.Send a JSON body with url and event.
400bad_eventevent is not a webhook event name.Use a name from the Event catalogue.
400bad_urlurl is not a valid web address.Send a full address such as https://example.com/hook.
400bad_schemeurl does not start with http:// or https://.Use an http or https address.
400url_not_allowedThe host cannot be resolved, or it resolves to a loopback, private, link-local or reserved address, or to SecureSMTP’s own servers.Use a public address.
409too_many_hooksThe site already has 50 webhooks. Paused ones and ones made in the dashboard count too.Delete a hook you no longer use, here or under Webhooks in the dashboard.

Notes

  • Calling it again with the same url and event, for example after a timeout, does not make a second hook. You get 200 with the existing id and no secret. Only an active hook made through this endpoint is matched. A paused hook, or one made in the dashboard with the same address, is left alone and a new hook is made.
  • Hooks made here show under Webhooks in the dashboard with “Added by Zapier” (or the tool’s name) beside them. They can be paused or deleted there.
  • The address is checked again before every delivery, and the connection is made only to the addresses that passed the check. If its host now resolves to a private address, nothing is sent and the hook’s last error reads url_not_allowed. If the host cannot be looked up, the delivery is tried again like any other failed delivery, and the last error reads dns lookup failed.
  • Deliveries to these hooks do not follow redirects. An answer with a 3xx status counts as a failed delivery.
  • If the address answers 410 Gone, SecureSMTP turns the hook off. Zapier answers 410 when a Zap is deleted.
  • Events arrive in the usual envelope with the X-QCS-Signature header. See Webhooks for how to check it.

DELETE /hooks/{id}

DELETEhttps://securessmtp.com/api/v1/hooks/{id}

Turns a trigger off by deleting the hook. Only hooks of the site the key belongs to can be deleted. This includes hooks made in the dashboard.

Path
idstringrequired
The id from the POST /hooks answer.
curl -X DELETE https://securessmtp.com/api/v1/hooks/HOOK_ID \
  -H "x-securessmtp-api-key: $SECURESSMTP_API_KEY"
200
{
  "ok": true
}
HTTPValueMeaningWhat to do
404not_foundThis site has no hook with this id. A hook of another site gives the same answer, and is left alone.Check the id. If the hook is already gone, there is nothing more to do.

GET /hooks/sample

GEThttps://securessmtp.com/api/v1/hooks/sample

Returns an example event in the same format a real one arrives in, so a person can map its fields while setting up a trigger. The values are made up. The same example comes back every time.

Query
eventstringrequired
One event name from the Event catalogue.
curl https://securessmtp.com/api/v1/hooks/sample?event=email.delivered \
  -H "x-securessmtp-api-key: $SECURESSMTP_API_KEY"
200
{
  "ok": true,
  "samples": [
    {
      "id": "00000000-0000-4000-8000-000000000002",
      "type": "email.delivered",
      "created_at": "2026-10-26T12:00:00.000Z",
      "site_id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
      "data": {
        "message_id": "<[email protected]>",
        "to": "[email protected]",
        "subject": "Your order has shipped"
      }
    }
  ]
}
Response fields
okbooleanrequired
true.
samplesobject[]required
One event: id, type, created_at, site_id (your site’s ID) and data.
  • form.submitted, email.delivered, email.bounced and email.unsubscribed come with example values in data. Any other valid event name returns the envelope with an empty dataobject.
  • Every field in data can be missing in a real event. For example, a bounce that cannot be matched to a logged email has only to and detail.
HTTPValueMeaningWhat to do
400bad_eventevent is missing or is not a webhook event name.Use a name from the Event catalogue.