Project API

Transactional API

Send receipts, alerts, and product messages from your application.

View as Markdown ↗

Project key. Acts in the project the key belongs to. An all-access key works too — name the project with an X-Project-Id header. How keys and scopes work.

Endpoint

POST/api/v1/emails

Authenticate every request with an Email Bump API key. The sender must use your shared testing domain or a verified sending domain.

Send an email

Body parameters

fromstringrequired

Sender, optionally with a display name: Acme <[email protected]>. Must be your shared or a verified domain.

tostringrequired

Recipient email address. A one-element array (["[email protected]"]) is accepted too, for clients ported from an API that takes a list.

subjectstringoptional

Subject line (or inherited from a template).

htmlstringoptional

HTML body.

textstringoptional

Plain-text body.

reply_tostringoptional

Reply-To address.

templateobjectoptional

Render a saved template: { "id", "variables" } instead of raw content.

template_idstringoptional

Flat alternative to template.id.

variablesobjectoptional

Flat alternative to template.variables. Values are readable both at the top level ({{ order_id }}) and under contact.

attachmentsarrayoptional

Files to send along. See Attachments.

scheduled_atstringoptional

RFC 3339 future time to send later instead of now.

streamstringoptional

transactional (default) or marketing. See Marketing over the API.

cURL
curl -X POST https://emailbump.com/api/v1/emails \
  -H "Authorization: Bearer ebk_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "from": "Acme <[email protected]>",
    "to": "[email protected]",
    "reply_to": "[email protected]",
    "subject": "Your order has shipped",
    "html": "<h1>On the way</h1><p>Tracking: EB-2048</p>",
    "text": "Your order is on the way. Tracking: EB-2048"
  }'

Provide html, text, or both. When only HTML is supplied, Email Bump creates a text version. When only text is supplied, it creates a minimal HTML part.

One recipient

This endpoint takes a single to address — there's no cc or bcc. Each send is metered, tracked and unsubscribed on its own, so a list of five addresses is five calls. Pass more than one and you'll get a 400 saying exactly that. For real cc/bcc, send over SMTP with the same key; to reach an audience in one request, use a campaign.

Marketing over the API

Add "stream": "marketing" to send a promotional one-off without building a campaign or flow — an announcement to one person, a hand-triggered win-back, your own sending logic driving the API. The message then carries what marketing mail must: the recipient is checked against their contact record and refused if they've unsubscribed or their address is suppressed, the marketing footer with its unsubscribe link is appended, one-click unsubscribe headers are set, and the send is classified under the marketing stream in analytics.

cURL
curl -X POST https://emailbump.com/api/v1/emails \
  -H "Authorization: Bearer ebk_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "from": "Acme <[email protected]>",
    "to": "[email protected]",
    "subject": "Something new for you",
    "html": "<p>We just launched…</p>",
    "stream": "marketing"
  }'

A recipient who isn't a contact yet is created as one, the same way the Events API does — the unsubscribe link needs a record to point at. scheduled_at isn't supported on this stream yet; to schedule marketing email, use a campaign. Transactional sends (the default) are unchanged: no footer, no consent gate — receipts and password resets go to unsubscribed recipients too, as they should.

What happened to it

GET/api/v1/emails/{id}

The id POST /v1/emails returned, and what became of the message:

cURL
curl https://emailbump.com/api/v1/emails/50b0b9a4-d447-480a-ad5b-3e1b999dd842 \
  -H "Authorization: Bearer ebk_your_key"
cURL
{
  "object": "email",
  "id": "50b0b9a4-…",
  "to": "[email protected]",
  "subject": "Your order has shipped",
  "status": "sent",
  "error": null,
  "events": [
    { "type": "send",     "occurred_at": "2026-08-03T01:27:57Z" },
    { "type": "delivery", "occurred_at": "2026-08-03T01:27:59Z" },
    { "type": "open",     "occurred_at": "2026-08-03T01:31:12Z", "machine_open": false }
  ]
}

status is our own record of the submission; events is what the provider reported afterwards. The distinction matters: "sent" means it was accepted for delivery, not that it arrived. A message to a domain with no MX record is "sent" and then bounces — the bounce event is where that shows up, usually within seconds.

Attachments

Send a receipt with its invoice, a report, a photo — anything, as base64. Up to 20 files totalling 25 MB per message.

Each attachment

filenamestringrequired

The name the recipient sees when they save it.

contentstringrequired

The file, base64-encoded. A whole data: URI works too, so a browser's FileReader result can be passed straight through.

content_typestringoptional

MIME type. Guessed from the filename when you leave it out.

content_idstringoptional

Set this to embed the file in the HTML instead of listing it at the bottom, and reference it as <img src="cid:the-id">.

cURL
curl -X POST https://emailbump.com/api/v1/emails \
  -H "Authorization: Bearer ebk_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "from": "Acme <[email protected]>",
    "to": "[email protected]",
    "subject": "Your invoice",
    "html": "<p>Thanks! Your invoice is attached.</p><img src=\"cid:logo\">",
    "attachments": [
      { "filename": "invoice-4821.pdf", "content": "JVBERi0xLjQK..." },
      { "filename": "logo.png", "content": "iVBORw0KGgo...", "content_id": "logo" }
    ]
  }'
Attachments make mail heavier, not more trusted

A PDF invoice is normal and fine. Executables, archives and macro-enabled documents are what spam filters look for — if a message must carry one, a link to it delivers far better than the file itself.

Schedule for later

Add scheduled_at (RFC 3339, must be in the future) to send at a specific time. The response comes back with status: "scheduled"; Email Bump delivers it when it comes due.

cURL
curl -X POST https://emailbump.com/api/v1/emails \
  -H "Authorization: Bearer ebk_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "from": "Acme <[email protected]>",
    "to": "[email protected]",
    "subject": "Your trial ends soon",
    "html": "<p>Just a heads up…</p>",
    "scheduled_at": "2026-08-01T09:00:00Z"
  }'

Use a template

Pass a saved template ID and variables instead of raw content. Variables are available at the top level and under contact.

JSON
{
  "from": "Acme <[email protected]>",
  "to": "[email protected]",
  "template": {
    "id": "9d7073b0-63b0-4ad0-925e-c43f04619ec2",
    "variables": {
      "first_name": "Jamie",
      "order_id": "EB-2048"
    }
  }
}

Response

200 response
{
  "id": "6dde5322-c940-43e5-84cc-97a2d8c69c08",
  "message_id": "provider-message-id",
  "to": "[email protected]",
  "from": "Acme <[email protected]>",
  "subject": "Your order has shipped",
  "status": "sent",
  "created_at": "2026-07-20T18:42:10Z"
}

Every accepted send is recorded in Developers → Transactional, including its rendered content, original payload, and event timeline.