Every API here is available over the APIs.io API and to AI agents over MCP.
MCP server
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
Tools for apis
7 MCP tools reach this
find_apisBrowse and filter every API in the catalog.
get_api_artifactsOne API's artifacts, grouped by type.
get_openapiThe primary OpenAPI for this API.
find_similar_apisAPIs that look like this one.
apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
resolveTurn a domain, URL or GitHub org into the provider it belongs to.
find_cohortsEvery scored population of providers in the catalog.
All 92 tools →
Call it yourself
curl for this page
This API
curl "https://apis.io/api/v1/apis/eusend-dev:eusend-dev-broadcasts-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"
Discovery needs no key. Ratings and market analysis are Pro.
Get an API key
Free tier, no form to fill in. Signing in shares your email address with us — we
store it to create your key and to recognise you if you sign in with another
provider. See our Privacy Policy and
Terms.
A second provider on the same verified email joins the account you already have.
openapi: 3.2.0
info:
title: eusend Broadcasts API
version: 1.0.0
summary: EU-native transactional and marketing email API.
description: 'eusend sends transactional and marketing email from infrastructure that stays inside the European Union — processing, storage and delivery alike.
**When to use this API.** Reach for eusend to send application email from server-side code: password resets, receipts, verification codes, notifications, and opt-in marketing broadcasts to a list you own. It is a good fit when GDPR or EU data residency is a requirement, when you are migrating off Resend, SendGrid, Mailgun, Postmark or SES, or when you need SMTP relay rather than an HTTP call. It is not a fit for inbox hosting, for reading a user’s mailbox, or for sending to purchased or scraped lists.
**Getting started.** Create an account, verify a sending domain by publishing the DNS records the domain endpoints hand back, then `POST /emails`. A key prefixed `eu_test_` exercises the whole pipeline without delivering anything.
**Authentication.** Every authenticated endpoint takes `Authorization: Bearer `. Keys are `eu_live_…` or `eu_test_…`, and carry either `full_access` or the send-only `sending_access` permission.
**Errors.** Non-2xx responses are always `{ "error": string, "code": string }`. Branch on `code`; the list is enumerated on the `Error` schema.
**Conventions.** Request bodies use snake_case and reject unknown properties. Response bodies use camelCase, except the pagination cursor and a handful of endpoints noted inline. List endpoints are cursor-paginated, newest first. Every response carries `X-Request-Id`.'
termsOfService: https://eusend.dev/legal/terms
contact:
name: eusend support
email: support@eusend.dev
url: https://eusend.dev/support
license:
name: Proprietary
url: https://eusend.dev/legal/terms
servers:
- url: https://api.eusend.dev
description: Production
security:
- bearerAuth: []
tags:
- name: Broadcasts
description: One message sent to a whole audience.
paths:
/broadcasts:
post:
operationId: createBroadcast
summary: Create a broadcast
description: Creates it as a draft. Nothing is sent until the send endpoint is called.
tags:
- Broadcasts
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateBroadcastRequest'
responses:
'201':
description: Created as a draft.
content:
application/json:
schema:
$ref: '#/components/schemas/Broadcast'
'400':
description: The request body or query failed validation (`VALIDATION_ERROR`).
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'401':
description: Missing, malformed, or revoked API key (`UNAUTHORIZED`).
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'403':
description: The key exists but may not reach this resource — a `sending_access` key outside the send paths, a test-mode key writing live state, or an account on hold (`FORBIDDEN`, `ACCOUNT_RESTRICTED`).
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
description: No such resource on this organization (`NOT_FOUND`).
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'429':
description: Rate limit exceeded (`RATE_LIMITED`).
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'500':
description: Unexpected server error (`INTERNAL_ERROR`). Carries `request_id`.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
get:
operationId: listBroadcasts
summary: List broadcasts
description: Newest first, with recipient and sent counts.
tags:
- Broadcasts
responses:
'200':
description: The broadcasts.
content:
application/json:
schema:
$ref: '#/components/schemas/ListBroadcastsResponse'
'401':
description: Missing, malformed, or revoked API key (`UNAUTHORIZED`).
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'403':
description: The key exists but may not reach this resource — a `sending_access` key outside the send paths, a test-mode key writing live state, or an account on hold (`FORBIDDEN`, `ACCOUNT_RESTRICTED`).
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'429':
description: Rate limit exceeded (`RATE_LIMITED`).
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'500':
description: Unexpected server error (`INTERNAL_ERROR`). Carries `request_id`.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/broadcasts/{id}:
get:
operationId: getBroadcast
summary: Get a broadcast
description: The broadcast with per-status recipient counts in `stats`.
tags:
- Broadcasts
parameters:
- name: id
in: path
required: true
description: The broadcast id.
schema:
type: string
format: uuid
responses:
'200':
description: The broadcast.
content:
application/json:
schema:
$ref: '#/components/schemas/BroadcastDetail'
'401':
description: Missing, malformed, or revoked API key (`UNAUTHORIZED`).
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'403':
description: The key exists but may not reach this resource — a `sending_access` key outside the send paths, a test-mode key writing live state, or an account on hold (`FORBIDDEN`, `ACCOUNT_RESTRICTED`).
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
description: No such resource on this organization (`NOT_FOUND`).
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'429':
description: Rate limit exceeded (`RATE_LIMITED`).
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'500':
description: Unexpected server error (`INTERNAL_ERROR`). Carries `request_id`.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
patch:
operationId: updateBroadcast
summary: Update or schedule a broadcast
description: Editable while draft or scheduled. Setting `scheduled_at` schedules it; setting it to null unschedules it back to draft. An update that leaves the broadcast scheduled runs the same checks as `POST /broadcasts/{id}/send`.
tags:
- Broadcasts
parameters:
- name: id
in: path
required: true
description: The broadcast id.
schema:
type: string
format: uuid
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/UpdateBroadcastRequest'
responses:
'200':
description: Updated.
content:
application/json:
schema:
$ref: '#/components/schemas/Broadcast'
'400':
description: The request body or query failed validation (`VALIDATION_ERROR`).
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'401':
description: Missing, malformed, or revoked API key (`UNAUTHORIZED`).
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'403':
description: The key exists but may not reach this resource — a `sending_access` key outside the send paths, a test-mode key writing live state, or an account on hold (`FORBIDDEN`, `ACCOUNT_RESTRICTED`).
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
description: No such resource on this organization (`NOT_FOUND`).
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'409':
description: The broadcast is in a state that cannot be edited, or was changed concurrently (`CONFLICT`).
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'429':
description: Rate limit exceeded (`RATE_LIMITED`).
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'500':
description: Unexpected server error (`INTERNAL_ERROR`). Carries `request_id`.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
delete:
operationId: deleteBroadcast
summary: Delete a broadcast
description: Only a draft or cancelled broadcast can be deleted.
tags:
- Broadcasts
parameters:
- name: id
in: path
required: true
description: The broadcast id.
schema:
type: string
format: uuid
responses:
'200':
description: Deleted.
content:
application/json:
schema:
$ref: '#/components/schemas/EmptyResponse'
'401':
description: Missing, malformed, or revoked API key (`UNAUTHORIZED`).
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'403':
description: The key exists but may not reach this resource — a `sending_access` key outside the send paths, a test-mode key writing live state, or an account on hold (`FORBIDDEN`, `ACCOUNT_RESTRICTED`).
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
description: No such resource on this organization (`NOT_FOUND`).
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'409':
description: Only draft or cancelled broadcasts can be deleted (`CONFLICT`).
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'429':
description: Rate limit exceeded (`RATE_LIMITED`).
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'500':
description: Unexpected server error (`INTERNAL_ERROR`). Carries `request_id`.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/broadcasts/{id}/send:
post:
operationId: sendBroadcast
summary: Send, schedule, or resume a broadcast
description: Fans the broadcast out to its audience. Omit `scheduled_at` to start now. Requires a paid plan and a live API key; use the test endpoint on the free plan.
tags:
- Broadcasts
parameters:
- name: id
in: path
required: true
description: The broadcast id.
schema:
type: string
format: uuid
requestBody:
required: false
content:
application/json:
schema:
$ref: '#/components/schemas/SendBroadcastRequest'
responses:
'200':
description: Sending or scheduled.
content:
application/json:
schema:
$ref: '#/components/schemas/SendBroadcastResponse'
'400':
description: The request body or query failed validation (`VALIDATION_ERROR`).
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'401':
description: Missing, malformed, or revoked API key (`UNAUTHORIZED`).
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'403':
description: 'Refused: broadcasts need a paid plan (`PLAN_LIMIT_EXCEEDED`), the sending domain is unverified (`DOMAIN_NOT_VERIFIED`), the account is suspended or on hold (`SENDING_SUSPENDED`, `ACCOUNT_RESTRICTED`, `SERVICE_PAUSED`), the workspace has no live subscription (`WORKSPACE_INACTIVE`), or the broadcast is held for review (`BROADCAST_HELD`).'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
description: No such resource on this organization (`NOT_FOUND`).
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'409':
description: The broadcast is not in a sendable state (`CONFLICT`).
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'429':
description: Rate limit exceeded (`RATE_LIMITED`).
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'500':
description: Unexpected server error (`INTERNAL_ERROR`). Carries `request_id`.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/broadcasts/{id}/test:
post:
operationId: testBroadcast
summary: Send a test copy of a broadcast
description: Delivers the real message to up to 5 addresses on your own verified domains. Works on every plan including Free, costs send quota, and does not change the broadcast status. Requires a live API key — the mail really is delivered.
tags:
- Broadcasts
parameters:
- name: id
in: path
required: true
description: The broadcast id.
schema:
type: string
format: uuid
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/TestBroadcastRequest'
responses:
'200':
description: Test sent.
content:
application/json:
schema:
$ref: '#/components/schemas/TestBroadcastResponse'
'400':
description: The request body or query failed validation (`VALIDATION_ERROR`).
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'401':
description: Missing, malformed, or revoked API key (`UNAUTHORIZED`).
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'403':
description: A recipient is neither an account email on this organization nor on a verified domain, or a test-mode key was used (`DOMAIN_NOT_VERIFIED`, `FORBIDDEN`).
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
description: No such resource on this organization (`NOT_FOUND`).
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'429':
description: Rate limit exceeded (`RATE_LIMITED`).
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'500':
description: Unexpected server error (`INTERNAL_ERROR`). Carries `request_id`.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/broadcasts/{id}/cancel:
post:
operationId: cancelBroadcast
summary: Cancel a broadcast
description: Stops a scheduled or in-flight broadcast. Messages already handed to the MTA still deliver.
tags:
- Broadcasts
parameters:
- name: id
in: path
required: true
description: The broadcast id.
schema:
type: string
format: uuid
responses:
'200':
description: Cancelled.
content:
application/json:
schema:
$ref: '#/components/schemas/Broadcast'
'401':
description: Missing, malformed, or revoked API key (`UNAUTHORIZED`).
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'403':
description: The key exists but may not reach this resource — a `sending_access` key outside the send paths, a test-mode key writing live state, or an account on hold (`FORBIDDEN`, `ACCOUNT_RESTRICTED`).
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
description: No such resource on this organization (`NOT_FOUND`).
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'409':
description: The broadcast is not in a cancellable state (`CONFLICT`).
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'429':
description: Rate limit exceeded (`RATE_LIMITED`).
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'500':
description: Unexpected server error (`INTERNAL_ERROR`). Carries `request_id`.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
components:
schemas:
SendBroadcastResponse:
type: object
required:
- id
- status
- scheduled_at
properties:
id:
type: string
format: uuid
status:
type: string
enum:
- sending
- scheduled
scheduled_at:
type:
- string
- 'null'
format: date-time
Broadcast:
type: object
required:
- id
- name
- status
- fromAddress
- subject
- createdAt
properties:
id:
type: string
format: uuid
organizationId:
type: string
format: uuid
name:
type: string
status:
type: string
enum:
- draft
- scheduled
- sending
- sent
- paused
- held
- cancelled
description: '`held` is a send stopped for review; unlike `paused` it is not resumable by the customer.'
audienceId:
type:
- string
- 'null'
format: uuid
fromAddress:
type: string
replyTo:
type:
- string
- 'null'
subject:
type: string
html:
type:
- string
- 'null'
reactSource:
type:
- string
- 'null'
editorJson:
type:
- object
- 'null'
additionalProperties: true
templateId:
type:
- string
- 'null'
format: uuid
templateVariables:
type:
- object
- 'null'
additionalProperties:
type: string
heldReason:
type:
- string
- 'null'
scheduledAt:
type:
- string
- 'null'
format: date-time
startedAt:
type:
- string
- 'null'
format: date-time
completedAt:
type:
- string
- 'null'
format: date-time
recipientCount:
type:
- integer
- 'null'
sentCount:
type:
- integer
- 'null'
trackOpens:
type: boolean
trackClicks:
type: boolean
createdAt:
type: string
format: date-time
updatedAt:
type:
- string
- 'null'
format: date-time
BroadcastListItem:
type: object
required:
- id
- name
- status
- fromAddress
- subject
- createdAt
properties:
id:
type: string
format: uuid
name:
type: string
status:
type: string
enum:
- draft
- scheduled
- sending
- sent
- paused
- held
- cancelled
audienceId:
type:
- string
- 'null'
format: uuid
audienceName:
type:
- string
- 'null'
fromAddress:
type: string
subject:
type: string
recipientCount:
type:
- integer
- 'null'
sentCount:
type:
- integer
- 'null'
scheduledAt:
type:
- string
- 'null'
format: date-time
startedAt:
type:
- string
- 'null'
format: date-time
completedAt:
type:
- string
- 'null'
format: date-time
createdAt:
type: string
format: date-time
EmptyResponse:
type: object
description: An empty object. The resource is gone.
additionalProperties: false
CreateBroadcastRequest:
type: object
required:
- name
- audience_id
- from
- subject
additionalProperties: false
description: Either `html` or `template_id` is required.
properties:
name:
type: string
minLength: 1
maxLength: 200
audience_id:
type: string
format: uuid
topic_id:
type:
- string
- 'null'
format: uuid
description: Narrows the audience to the contacts subscribed to this topic. Omit (or send `null`) to reach the whole audience.
from:
type: string
description: Must be on a verified sending domain.
reply_to:
type: string
subject:
type: string
minLength: 1
html:
type: string
editor_json:
type:
- object
- 'null'
additionalProperties: true
template_id:
type: string
format: uuid
template_variables:
type: object
additionalProperties:
type: string
track_opens:
type: boolean
track_clicks:
type: boolean
TestBroadcastResponse:
type: object
required:
- id
- sent_to
- email_ids
properties:
id:
type: string
format: uuid
sent_to:
type: array
items:
type: string
description: Addresses actually mailed, lowercased and de-duplicated.
email_ids:
type: array
items:
type: string
format: uuid
UpdateBroadcastRequest:
type: object
additionalProperties: false
description: Only a draft, scheduled or paused broadcast can be updated. Setting `scheduled_at` to null unschedules it back to draft.
properties:
name:
type: string
minLength: 1
maxLength: 200
audience_id:
type: string
format: uuid
topic_id:
type:
- string
- 'null'
format: uuid
description: Narrows the audience to the contacts subscribed to this topic. Omit (or send `null`) to reach the whole audience.
from:
type: string
reply_to:
type:
- string
- 'null'
subject:
type: string
minLength: 1
html:
type: string
editor_json:
type:
- object
- 'null'
additionalProperties: true
template_id:
type:
- string
- 'null'
format: uuid
template_variables:
type:
- object
- 'null'
additionalProperties:
type: string
scheduled_at:
type:
- string
- 'null'
format: date-time
track_opens:
type: boolean
track_clicks:
type: boolean
Error:
type: object
description: Every non-2xx response from the API has this shape. `code` is stable and safe to branch on; `error` is a human sentence that may change.
required:
- error
- code
properties:
error:
type: string
description: Human-readable explanation of the failure.
code:
type: string
enum:
- UNAUTHORIZED
- FORBIDDEN
- NOT_FOUND
- VALIDATION_ERROR
- RATE_LIMITED
- MONTHLY_LIMIT_EXCEEDED
- DAILY_LIMIT_EXCEEDED
- PLAN_LIMIT_EXCEEDED
- ALL_SUPPRESSED
- RECIPIENT_DOMAIN_UNDELIVERABLE
- DOMAIN_NOT_VERIFIED
- SENDING_SUSPENDED
- ACCOUNT_RESTRICTED
- WORKSPACE_INACTIVE
- SENDER_NOT_PERMITTED
- SERVICE_PAUSED
- LIST_SEND_HELD
- BROADCAST_HELD
- ATTACHMENT_STORAGE_ERROR
- INTERNAL_ERROR
- CONFLICT
- BAD_REQUEST
- PAYLOAD_TOO_LARGE
description: Stable machine-readable error code.
request_id:
type: string
description: Correlation id, returned on 500s and echoed in the `X-Request-Id` header on every response. Quote it in support requests.
ListBroadcastsResponse:
type: object
required:
- data
properties:
data:
type: array
items:
$ref: '#/components/schemas/BroadcastListItem'
SendBroadcastRequest:
type: object
additionalProperties: false
properties:
scheduled_at:
type: string
format: date-time
description: ISO 8601. Omit to start sending immediately.
BroadcastDetail:
allOf:
- $ref: '#/components/schemas/Broadcast'
- type: object
required:
- stats
properties:
stats:
type: object
additionalProperties:
type: integer
description: 'Recipient counts keyed by email status, e.g. `{ "delivered": 1204, "bounced": 3 }`.'
TestBroadcastRequest:
type: object
required:
- to
additionalProperties: false
properties:
to:
type: array
minItems: 1
maxItems: 5
items:
type: string
format: email
description: Each address must be on a domain verified on your account — a test send delivers real mail without the paid-plan gate, so it is restricted to inboxes you have proved you control.
securitySchemes:
bearerAuth:
type: http
scheme: bearer
description: 'An eusend API key, sent as `Authorization: Bearer eu_live_…`. Create one in the dashboard under API keys.'
externalDocs:
description: eusend documentation
url: https://eusend.dev/docs