eusend-dev Broadcasts API

One message sent to a whole audience.

Operations 8

POST /broadcasts Create a broadcast #
GET /broadcasts List broadcasts #
GET /broadcasts/{id} Get a broadcast #
PATCH /broadcasts/{id} Update or schedule a broadcast #
DELETE /broadcasts/{id} Delete a broadcast #
POST /broadcasts/{id}/send Send, schedule, or resume a broadcast #
POST /broadcasts/{id}/test Send a test copy of a broadcast #
POST /broadcasts/{id}/cancel Cancel a broadcast #

Work with this as data

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 Specification

eusend-dev-broadcasts-api-openapi.yml Raw ↑
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