SendPost App

Introduction

The SendPost App for Flows enables you to connect your workflows to SendPost, a transactional email / email-infrastructure platform. SendPost is the developer-facing sending API from the SendX family: you send transactional mail over a REST API (or SMTP), and it gives you deliverability tooling on top — sending-domain authentication (DKIM / Return-Path / DMARC / tracking CNAME), suppression lists, dedicated IPs and IP pools with auto-warmup, per-sub-account statistics, message inspection and event webhooks.

What is SendPost?

SendPost is an email infrastructure platform that lets you send transactional email and manage sending domains, suppressions, sub-accounts, stats and webhooks through its API. Key features include:

  • Transactional email sending (direct HTML or template-based)
  • Sending-domain authentication (DKIM / Return-Path / DMARC / tracking CNAME)
  • Suppression list management
  • Multi-tenant sub-accounts, each with its own API key
  • Per-sub-account statistics (aggregate and daily)
  • Message inspection and event webhooks
  • Dedicated IPs and IP pools with auto-warmup

Getting Started

Prerequisites

Before using the SendPost App, you will need:

  • A SendPost account
  • Your SendPost Sub-Account API Key (required for sending email and managing that sub-account's domains/suppressions)
  • Your SendPost Account API Key (optional — only required for account-level endpoints: sub-accounts, statistics, message lookup, webhooks, IPs)

Available Stages

1. Send Email — POST /api/v1/subaccount/email/ Sub-Account key;

2. Send Email With Template — POST /api/v1/subaccount/email/template Sub-Account key;

3. List Domains — GET /api/v1/subaccount/domain Sub-Account key;

4. Create Domain — POST /api/v1/subaccount/domain Sub-Account key;

5. Get Domain — GET /api/v1/subaccount/domain/{domain_id} Sub-Account key;

6. Delete Domain — DELETE /api/v1/subaccount/domain/{domain_id} Sub-Account key;

7. List Suppressions — GET /api/v1/subaccount/suppression Sub-Account key;

8. Add Suppression — POST /api/v1/subaccount/suppression Sub-Account key;

9. Remove Suppression — DELETE /api/v1/subaccount/suppression Sub-Account key;

10. List Sub-Accounts — GET /api/v1/account/subaccount/ Account key;

11. Create Sub-Account — POST /api/v1/account/subaccount/ Account key;

12. Get Sub-Account — GET /api/v1/account/subaccount/{subaccount_id} Account key;

13. Get Aggregate Stats — GET /api/v1/account/subaccount/stat/{subaccount_id}/aggregate Account key;

14. List Daily Stats — GET /api/v1/account/subaccount/stat/{subaccount_id} Account key;

15. Get Message — GET /api/v1/account/message/{message_id} Account key;

16. List Webhooks — GET /api/v1/account/webhook Account key; 

17. Create Webhook — POST /api/v1/account/webhook Account key;

18. Delete Webhook — DELETE /api/v1/account/webhook/{webhook_id} Account key;

19. List IPs — GET /api/v1/account/ip/ Account key;


Why Two Keys

This is the single most important thing to get right about SendPost. The API has two independent, non-interchangeable API keys, and the URL path tells you which one applies:

Path prefixHeaderKeyScope
/api/v1/subaccount/...X-SubAccount-ApiKeySub-Account API KeyOne sending sub-account: send email, its sending domains, its suppression list
/api/v1/account/...X-Account-ApiKeyAccount API KeyThe whole account: create/list sub-accounts, statistics, message lookup, webhooks, IPs, IP pools

Using the wrong key (or omitting the header) returns HTTP 401 Unauthorized. Each sub-account has its own key, so a multi-tenant setup normally installs the app once per sub-account with a different Sub-Account API Key, while the Account API Key stays the same across them.

Note the counter-intuitive part: the statistics for a sub-account live under /api/v1/account/subaccount/stat/{subaccount_id} and therefore need the Account key, not the sub-account key. Likewise Get Message is an account-level lookup.


API Notes

ItemValue
Base URLhttps://api.sendpost.io/api/v1
Auth typeStatic API key in a custom header (no OAuth, no token refresh, no expiry)
Content-Typeapplication/json for every write
CasingRequest and response bodies are camelCase
Timestampscreated, submittedAt etc. are UNIX epoch NANOseconds (19 digits), not seconds or milliseconds. Divide by 1,000,000,000 before feeding them to @formatDate().
Date paramsfrom / to on the stats and suppression endpoints are calendar dates, YYYY-MM-DD
Date range capsSuppressions and daily stats: max 60 days. Aggregate stats: max 366 days.
Rate limitsNot documented by SendPost

Status codes

CodeMeaning
200 / 201Success
401Incorrect or missing API key header — you almost certainly used the account key where a sub-account key was needed, or vice versa
403Resource already exists (duplicate domain, duplicate sub-account name, duplicate webhook URL)
406Missing or non-existent resource id
422Malformed request body
500 / 503SendPost server error / maintenance

Known quirks handled in these blueprints

  • Send Email returns an ARRAY, one element per recipient, even for a single recipient. Flows cannot index into arrays, so both send endpoints loop the response with a ForEach and accumulate it with @arrayAdd into a Results array, while also lifting the single recipient's messageId into a flat MessageID output.
  • Delete Suppressions is a DELETE with a JSON body. This is the one place the house rule "no Content-Type and empty payload on GET/DELETE" is deliberately broken, because SendPost requires the {"suppressions":[...]} body. Delete Domain and Delete Webhook follow the normal rule (no body, no Content-Type).
  • Add Suppression keys the body by suppression type: {"manual":[{"email":"..."}]}. The type parameter is interpolated into the JSON key position rather than branching into four near-identical Call API stages.
  • HTML bodies are interpolated into a JSON payload. Keep htmlBody on a single line and use single quotes for HTML attributes (<a href='https://...'>). A raw double quote or a newline inside htmlBody or subject breaks the JSON payload and SendPost answers 422.
  • limit / offset / search on the list endpoints are hardcoded to limit=100&offset=0 rather than exposed as parameters, because {{var||default}} syntax is not supported in a Call API URL.

Parameter Descriptions

EndpointParameterRequiredNotes
Send EmailfromEmailYesSender address. Its domain must be a verified sending domain on the sub-account, otherwise the send is dropped.
Send EmailfromNameYesSender display name, e.g. Acme Support.
Send EmailtoEmailYesSingle recipient address.
Send EmailsubjectYesSubject line. Avoid raw double quotes.
Send EmailhtmlBodyYesHTML body, single line, single-quoted attributes.
Send EmailtrackOpensNo (default true)Literal true or false.
Send EmailtrackClicksNo (default true)Literal true or false. Click tracking also needs the track CNAME verified on the domain.
Send Email With TemplatetemplateNameYesName of the template as saved in the SendPost dashboard, e.g. Welcome Mail.
Send Email With TemplatetemplateVariablesNo (default {})Raw JSON object of merge values, e.g. {"firstName":"Gavin"}. Must be valid JSON or SendPost answers 422.
Create Domain / Get / Delete Domainname / domainIdYesname is a bare domain like mail.acme.com. domainId is the numeric id from List Domains.
List Suppressionsfrom, toYesYYYY-MM-DD. Max 60 days apart.
Add SuppressionemailYesAddress to suppress.
Add SuppressiontypeYes (default manual)One of manual, unsubscribe, hardBounce, spamComplaint. Anything else silently suppresses nothing.
Remove SuppressionemailYesAddress to un-suppress so it can receive mail again.
Create Sub-AccountnameYesDisplay name. Duplicate names return 403.
Get Sub-Account / statssubAccountIdYesNumeric sub-account id from List Sub-Accounts.
Get Aggregate Statsfrom, toYesYYYY-MM-DD, max 366 days apart.
List Daily Statsfrom, toYesYYYY-MM-DD, max 60 days apart.
Get MessagemessageIdYesThe messageId UUID returned by Send Email.
Create WebhookurlYesHTTPS endpoint that will receive events. Subscribes to all standard delivery and engagement events; fine-tune per event in the SendPost dashboard afterwards. Duplicate URL returns 403.
Delete WebhookwebhookIdYesNumeric webhook id from List Webhooks.

Response Descriptions

EndpointKey outputs
Send Email / Send Email With TemplateMessageID (UUID — feed it to Get Message), To, SubmittedAt, RecipientCount, Results (array of {To, MessageID, SubmittedAt})
List DomainsDomainCount, Domains array of {DomainID, Name, Verified, DkimVerified, ReturnPathVerified, TrackVerified, DmarcVerified, Created}
Create Domain / Get DomainDomainID, Name, Verified plus the DNS records to publish: DkimHost/DkimValue (TXT), ReturnPathHost/ReturnPathValue (CNAME), TrackHost/TrackValue (CNAME), DmarcHost/DmarcValue (TXT)
List Suppressions / Add SuppressionSuppressions array of {SuppressionID, Email, ReasonCode, Created}. ReasonCode: 0 manual, 1 unsubscribe, 2 hard bounce, 3 spam complaint
Get Aggregate StatsProcessed, Delivered, Dropped, HardBounced, SoftBounced, Unsubscribed, Spam
List Daily StatsDailyStats array of {Date, Processed, Delivered, Dropped, HardBounced, SoftBounced, Unsubscribed, Spam}, one object per day
List Sub-Accounts / Create Sub-AccountSubAccountID, Name, ApiKey — the ApiKey is that sub-account's Sub-Account API Key, i.e. what you paste into a new connection
Get MessageFull envelope of one sent message: MessageID, Subject, FromEmail, ToEmail, SubmittedAt, TrackOpens, TrackClicks, SubAccountID
List / Create / Delete WebhookWebhookID, Url, Enabled, Created
List IPsIPs array of {IPID, PublicIP, AutoWarmupEnabled, AutoWarmupStage, Created}

How to Connect

  1. Create a SendPost account at https://app.sendpost.io/register.
  2. In the dashboard open the sub-account you want to send from and copy its API key. Paste it into the Sub-Account API Key connection parameter.
  3. Only if you want the account-level endpoints (stats, sub-accounts, webhooks, IPs, message lookup): open Account Settings → API Keys, copy the account key and paste it into Account API Key. Leave it blank otherwise.
  4. Add and verify a sending domain before you send anything — see below.

How to Test

Step 1 — verify the connection. Run List Domains with no parameters. A 200 with an empty Domains array is a valid pass: it proves the Sub-Account API Key is accepted. A 401 means the key is wrong or you pasted the account key.

Step 2 — add a sending domain. Run Create Domain with name = a domain you control, e.g. mail.acme.com. Publish the returned records in your DNS:

  • DkimHost → TXT → DkimValue
  • ReturnPathHost → CNAME → ReturnPathValue
  • TrackHost → CNAME → TrackValue (needed for click tracking)
  • DmarcHost → TXT → DmarcValue

Re-run Get Domain with the returned DomainID until Verified is true. DNS propagation is usually minutes but can take hours.

Step 3 — send. Run Send Email:

  • fromEmail: [email protected] (must be on the verified domain)
  • fromName: Acme Support
  • toEmail: your own inbox
  • subject: SendPost test from Flows
  • htmlBody: <p>Hello from <b>Flows</b> - <a href='https://flows.world'>click me</a></p>
  • trackOpens / trackClicks: leave empty (both default to true)

Expect RecipientCount = 1 and a MessageID UUID. The mail should arrive within seconds.

Step 4 — inspect it. Paste that MessageID into Get Message (needs the Account API Key). You get the full envelope back.

Step 5 — stats. Run List Sub-Accounts to get your numeric SubAccountID, then Get Aggregate Stats with from = today minus 7 days, to = today (YYYY-MM-DD). Processed should include your test send. Note stats can lag a few minutes.

Step 6 — suppressions. Add Suppression with email = [email protected] and type left empty (defaults to manual), then List Suppressions with a from/to window covering today, then Remove Suppression for the same address.

Every endpoint carries a pink "How to test" note on its Designer canvas with concrete example values.


Use Cases

  • Transactional email from any flow — password resets, receipts, shipping notices, OTP mails, alerting. Send Email is the workhorse; Send Email With Template keeps the copy in SendPost so marketing can edit it without touching the flow.
  • Self-service tenant onboarding — Create Sub-Account returns that tenant's own API key, so a flow can provision an isolated sending identity per customer and store the key.
  • Automated domain onboarding — Create Domain returns the four DNS records; a flow can push them straight into a DNS provider and then poll Get Domain until Verified is true.
  • Suppression hygiene — pipe unsubscribes and complaints from your CRM into Add Suppression, and honour re-consent with Remove Suppression.
  • Deliverability monitoring — schedule Get Aggregate Stats daily and raise an alert when the hard-bounce or spam ratio crosses a threshold; List Daily Stats gives the per-day series for a chart or digest.
  • Event ingestion — Create Webhook points SendPost at a Flows webhook trigger, turning deliveries, opens, clicks, bounces and complaints into flow runs.

Troubleshooting

SymptomCauseFix
401 on every endpointWrong key for the path/subaccount/... needs Sub-Account API Key, /account/... needs Account API Key. They are not interchangeable.
401 only on stats / Get Message / webhooksAccount API Key left blankIt is optional at connection time but mandatory for these endpoints.
Send returns 200 but no mail arrivesSending domain not verified, or the recipient is suppressedCheck Verified via Get Domain; check List Suppressions for the recipient. A dropped send shows up under Dropped in stats.
422 on Send EmailBroken JSON payloadA raw double quote or newline in subject / htmlBody. Use single quotes in HTML attributes and keep the body on one line.
422 on Send Email With TemplatetemplateVariables is not valid JSONIt is injected raw. Send {"firstName":"Gavin"}, not firstName=Gavin. Leave empty for {}.
403 on Create Domain / Create Sub-Account / Create WebhookResource already existsDuplicate domain name, sub-account name or webhook URL. List first.
406Missing or non-existent idCheck domainId / subAccountId / webhookId came from the matching list endpoint.
Empty statsWrong date format or range too wideYYYY-MM-DD; max 60 days for daily stats and suppressions, 366 for aggregate.
Timestamps look absurdThey are UNIX nanosecondsDivide by 1,000,000,000 before formatting.
Click tracking not workingtrack CNAME not verifiedTrackVerified must be true on the domain.