Overview
Send transactional and bulk email from your own domain with Helipod Email.
Helipod Email is a sending (and optional receiving) service for your Helipod projects. With an email API key you can send single and batch messages, manage templates, sending domains, contacts, segments, topics and broadcasts, read delivery logs and analytics, and receive events on your own webhook.
Base URL
https://mail.helipod.io/api/emailEvery path in this section is relative to that base URL. For example, POST /send means POST https://mail.helipod.io/api/email/send.
Authentication
Send your email API key as a Bearer token on every request:
Authorization: Bearer your_email_api_keyHow email API keys work:
- Created in the dashboard. Open your project, go to the Email section and create a key under API keys. The full key is shown once; store it in a secret manager.
- Format. Keys start with
hel_followed by 48 hexadecimal characters. The dashboard shows the first 12 characters (the key prefix) so you can tell keys apart. - Bound to one project. A key belongs to the email service of exactly one project. You never pass a project id: every request made with the key acts on that project's domains, templates, contacts and logs.
- Only its own project. Ids of another project (even one you own) answer
404, and job lists show only the project's own jobs. - Plans, with care. Keys can read the plan, buy, renew or change it and its inbox add-ons (also after the plan has ended), with
?dryRun=truefor the price and a requiredIdempotency-Keyon the real call. See Plan and add-ons. - Dashboard only. Creating or revoking email keys, cancelling a plan, the auto-renew and pay-as-you-go switches, and webmail passwords of mailboxes answer
403 KEY_NOT_ALLOWEDto a key. - No scopes. Within its project a key can use every endpoint documented here. Use separate keys per integration so you can revoke one without affecting the others.
- Optional expiry. A key can be created with an expiry (1 to 3650 days). Expired keys return
401 API_KEY_EXPIRED. Revoked keys return401 INVALID_API_KEY. - Or a Helipod API key. A Helipod API key with Email API enabled works too, and so does an AI tool signed in through the MCP server with it ticked. A key limited to one project acts on that project. A whole-account key names the project with an
X-Helipod-Project: <projectId>header, unless only one of your projects has email (400 PROJECT_REQUIREDotherwise). A Helipod key without the Email API answers403 SCOPE_NOT_ALLOWED. SMTP still needs an email API key.
Call the Email API from your server, never from a browser. An API key is a secret, and cross-origin browser requests are only allowed from Helipod's own sites, so a fetch from your web app is blocked by the browser.
An active email plan is required for every request, including the Free plan. Without one, calls return 402 NO_PLAN, except reading the status and plan and buying or renewing a plan (Plan and add-ons), so a key can always start or bring back its plan.
Response envelope
Every response uses the same envelope.
{ "success": true, "data": { } }{ "success": false, "error": "Human readable message", "code": "MACHINE_CODE" }Branch on code, not on the message text. Messages can change; codes do not. One exception adds a data field to a failure: a batch send in which every message failed (see Sending). The full list of codes is in Limits and errors.
Background jobs
Several operations run in the background and answer 202 Accepted with a jobId (for example adding a domain, creating a template, or sending). Poll the job to see how it ended.
/jobs/{jobId}curl https://mail.helipod.io/api/email/jobs/eml_8f21c0a94d7b4c2e9a1f \
-H "Authorization: Bearer your_email_api_key"{
"success": true,
"data": {
"jobId": "eml_8f21c0a94d7b4c2e9a1f",
"type": "verify_domain",
"status": "completed",
"result": { },
"errorMessage": null,
"attempts": 1,
"createdAt": "2026-10-16T09:14:03.221Z",
"startedAt": "2026-10-16T09:14:03.540Z",
"completedAt": "2026-10-16T09:14:05.102Z"
}
}Prop
Type
Returns 404 JOB_NOT_FOUND for an unknown id.
/jobsPagination
List endpoints that can grow large are cursor-paginated. Pass limit and, for the next page, the nextCursor from the previous response as cursor. nextCursor is null on the last page. Paginated lists nest the rows one level deeper:
{ "success": true, "data": { "data": [ ], "nextCursor": "2026-10-16T09:14:03.221544Z" } }Quick start
Get an API key
In the dashboard, open your project, go to Email, activate a plan (the Free plan is enough to start), then create an API key. Copy it once and keep it on your server.
export HELIPOD_EMAIL_KEY="your_email_api_key"Add and verify your sending domain
Add the domain you want to send from:
curl -X POST https://mail.helipod.io/api/email/domains \
-H "Authorization: Bearer $HELIPOD_EMAIL_KEY" \
-H "Content-Type: application/json" \
-d '{"domain":"example.com"}'Wait for the returned jobId to complete, then read the domain to get its DNS records:
curl https://mail.helipod.io/api/email/domains/3f2a9c4e-1b7d-4e0a-9c55-2d8f6b1a7e10 \
-H "Authorization: Bearer $HELIPOD_EMAIL_KEY"Publish every record in dnsRecords at your DNS provider, exactly as returned. Then ask Helipod to check them and poll until the domain status is verified:
curl -X POST https://mail.helipod.io/api/email/domains/3f2a9c4e-1b7d-4e0a-9c55-2d8f6b1a7e10/verify \
-H "Authorization: Bearer $HELIPOD_EMAIL_KEY"See Domains for the full flow.
Send your first email
curl -X POST https://mail.helipod.io/api/email/send \
-H "Authorization: Bearer $HELIPOD_EMAIL_KEY" \
-H "Content-Type: application/json" \
-d '{
"from": "Acme <[email protected]>",
"to": ["[email protected]"],
"subject": "Welcome to Acme",
"html": "<p>Thanks for signing up.</p>",
"text": "Thanks for signing up."
}'The API answers 202 with the email id. Delivery happens in the background; read GET /emails/{id} to follow it, or subscribe a webhook.