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: 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