eusend-dev Domains API

Register sending domains and verify their DKIM, SPF and DMARC records.

Operations 6

POST /domains Register a sending domain #
GET /domains List sending domains #
GET /domains/{id} Get a sending domain #
DELETE /domains/{id} Delete a sending domain #
GET /domains/{id}/domain-connect Check Domain Connect support for a domain #
POST /domains/{id}/verify Re-check the DNS records now #

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-domains-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-domains-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: eusend Domains 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: Domains
  description: Register sending domains and verify their DKIM, SPF and DMARC records.
paths:
  /domains:
    post:
      operationId: createDomain
      summary: Register a sending domain
      description: Generates a DKIM key pair and returns every DNS record to publish. DNS polling starts immediately; the domain cannot send until it reaches `verified`.
      tags:
      - Domains
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateDomainRequest'
      responses:
        '201':
          description: Registered. Publish `records`, then poll the domain.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CreateDomainResponse'
        '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'
        '409':
          description: That domain is already verified on another account (`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'
    get:
      operationId: listDomains
      summary: List sending domains
      description: Every domain on the organization with its verification status.
      tags:
      - Domains
      responses:
        '200':
          description: The domains.
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/DomainListItem'
        '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'
  /domains/{id}:
    get:
      operationId: getDomain
      summary: Get a sending domain
      description: Includes the DKIM public key, the DNS records to publish, and whether a verification chain is polling right now.
      tags:
      - Domains
      parameters:
      - name: id
        in: path
        required: true
        description: The domain id.
        schema:
          type: string
          format: uuid
      responses:
        '200':
          description: The domain.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Domain'
        '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'
    delete:
      operationId: deleteDomain
      summary: Delete a sending domain
      description: Removes the domain and rotates its DKIM key out of use. Keys scoped to it stop authenticating. Live emails still scheduled from it are canceled and their quota refunded.
      tags:
      - Domains
      parameters:
      - name: id
        in: path
        required: true
        description: The domain id.
        schema:
          type: string
          format: uuid
      responses:
        '200':
          description: Deleted.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DeleteDomainResponse'
        '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'
  /domains/{id}/domain-connect:
    get:
      operationId: getDomainConnect
      summary: Check Domain Connect support for a domain
      description: Asks whether the customer’s DNS provider can write the eusend records for them, and hands back the signed apply URL when it can. Evaluated per request — providers add and remove templates on their own schedule.
      tags:
      - Domains
      parameters:
      - name: id
        in: path
        required: true
        description: The domain id.
        schema:
          type: string
          format: uuid
      responses:
        '200':
          description: Supported, or the reason it is not.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DomainConnectResponse'
        '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'
  /domains/{id}/verify:
    post:
      operationId: verifyDomain
      summary: Re-check the DNS records now
      description: Starts a verification chain immediately instead of waiting for the next scheduled poll.
      tags:
      - Domains
      parameters:
      - name: id
        in: path
        required: true
        description: The domain id.
        schema:
          type: string
          format: uuid
      responses:
        '200':
          description: A check was started.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MessageResponse'
        '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'
components:
  schemas:
    CreateDomainRequest:
      type: object
      required:
      - name
      additionalProperties: false
      properties:
        name:
          type: string
          description: The domain itself (`acme.com`), not an address on it. Mailbox providers such as gmail.com are refused.
    MessageResponse:
      type: object
      required:
      - message
      properties:
        message:
          type: string
    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.
    CreateDomainResponse:
      type: object
      required:
      - id
      - name
      - records
      properties:
        id:
          type: string
          format: uuid
        name:
          type: string
        records:
          type: array
          items:
            $ref: '#/components/schemas/DnsRecord'
          description: The full ordered record set. Prefer this over `dkim`/`dmarc`.
        dkim:
          $ref: '#/components/schemas/DnsRecord'
          description: Deprecated shortcut kept for SDK compatibility.
        dmarc:
          $ref: '#/components/schemas/DnsRecord'
          description: Deprecated shortcut kept for SDK compatibility.
    DeleteDomainResponse:
      type: object
      required:
      - message
      - canceled_scheduled_emails
      properties:
        message:
          type: string
        canceled_scheduled_emails:
          type: integer
          description: Scheduled emails from this domain that were canceled with it.
    DomainConnectResponse:
      type: object
      description: 'Whether the domain’s DNS provider can publish our records for the customer. Not having Domain Connect is the ordinary case, so every negative answer is a 200 with `supported: false` — the caller’s job either way is to render the copy-paste records.'
      required:
      - supported
      properties:
        supported:
          type: boolean
        provider:
          type: string
          description: The DNS provider’s name, when one was identified.
        applyUrl:
          type: string
          format: uri
          description: Signed URL to redirect the customer to. Present only when `supported` is true.
        reason:
          type: string
          enum:
          - not_configured
          - no_domain_connect
          - no_settings
          - no_sync_flow
          - template_not_onboarded
          - lookup_failed
          description: Why Domain Connect is unavailable. Present only when `supported` is false.
    DnsRecord:
      type: object
      description: One record to publish on the sending domain.
      required:
      - id
      - type
      - name
      - value
      - purpose
      - description
      properties:
        id:
          type: string
          description: 'Stable key: `dkim`, `dmarc`, `returnPathSpf`, `returnPathMx`.'
        type:
          type: string
          enum:
          - TXT
          - MX
        name:
          type: string
        value:
          type: string
        priority:
          type: integer
          description: MX records only.
        purpose:
          type: string
          enum:
          - authentication
          - policy
          - alignment
          description: '`authentication` blocks sending when missing; `policy` is recommended; `alignment` is optional and enables Return-Path SPF alignment when both alignment records are published.'
        description:
          type: string
    DomainListItem:
      type: object
      required:
      - id
      - name
      - status
      - createdAt
      properties:
        id:
          type: string
          format: uuid
        name:
          type: string
        status:
          type: string
          enum:
          - pending
          - verified
          - failed
        createdAt:
          type: string
          format: date-time
    Domain:
      type: object
      required:
      - id
      - name
      - status
      - createdAt
      - verification
      - records
      properties:
        id:
          type: string
          format: uuid
        name:
          type: string
        dkimPublicKey:
          type: string
        dkimSelector:
          type: string
        status:
          type: string
          enum:
          - pending
          - verified
          - failed
        createdAt:
          type: string
          format: date-time
        verifiedAt:
          type:
          - string
          - 'null'
          format: date-time
        returnPathAligned:
          type: boolean
        verification:
          type: object
          description: Whether a DNS polling chain is running for this domain right now.
          required:
          - running
          - startedAt
          properties:
            running:
              type: boolean
            startedAt:
              type:
              - string
              - 'null'
              format: date-time
        diagnostic:
          type:
          - object
          - 'null'
          description: What the last unmatched DNS check found, when it found a mistake rather than an absence — the record published under the domain twice because the control panel appends it, a key cut off at the 255-character limit for one DNS string, a DKIM key we did not issue on the same selector. Null is the ordinary “not published yet”, and it clears once the record is right. New codes may be added, so treat an unknown one as generic.
          required:
          - code
          properties:
            code:
              type: string
              enum:
              - doubled_domain
              - truncated_key
              - foreign_key
              - quoted_value
              - multiple_records
              - cname_at_selector
            foundAt:
              type: string
              description: The name the record actually resolved at (`doubled_domain`).
            publishedChars:
              type: integer
            expectedChars:
              type: integer
            target:
              type: string
              description: Where the CNAME points (`cname_at_selector`).
            provider:
              type: object
              description: The DNS host serving the zone, recognised from its nameservers. Absent when none of them is one we know.
              required:
              - id
              - label
              - guide
              properties:
                id:
                  type: string
                label:
                  type: string
                guide:
                  type:
                  - string
                  - 'null'
                  description: Path to the setup guide for this panel on eusend.dev, or null where there is none.
        records:
          type: array
          items:
            $ref: '#/components/schemas/DnsRecord'
  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