Register an email domain
Scopeemail-domains:writeRegisters a domain to send your account's emails from and returns the DNS records you have to
publish for it. The domain starts PENDING; publish the records and ask for the check with
POST /v1/accounts/{account_id}/email-domains/{email_domain_id}/verify. A domain that is not
VERIFIED 72 hours after it was registered is removed and its name is freed.
- Add-on: requires the custom email domain add-on, which is contracted with BeeL. Without
it the call answers
403 FEATURE_NOT_AVAILABLE. - Default: the first domain of an account, or the new one when the account has no default domain, becomes the default; otherwise the default does not change.
EMAIL_DOMAIN_INVALID(422): the text is not a full domain name. Internationalised names are accepted and stored in their ASCII form.EMAIL_DOMAIN_RESERVED(422): the domain cannot be used as a sending domain, for example because it belongs to BeeL or to a public mailbox provider.EMAIL_DOMAIN_UNAVAILABLE(409): the domain is already in use: registered by your account, by another account, or already held in the sending service BeeL uses. The answer is the same in every case and says nothing about who holds it.- While it registers: a domain that is still registering shows
status: PENDINGwithdns_records: []. Read it again in a few seconds; if it stays that way, remove it withDELETEand register it again. EMAIL_DOMAIN_LIMIT_REACHED(409): the account already holds as many domains as the add-on allows;error.details.limitcarries that number.- Unpaid billing: when the billing of the account is unpaid the call answers
402 PAYMENT_REQUIRED. - Credentials: it changes the real account, so it requires a live API key or a dashboard
session. A test API key answers
403 LIVE_CREDENTIAL_REQUIRED. Send anIdempotency-Keyso a retry does not repeat the operation.
Keys are prefixed beel_sk_, and each one carries the scopes it was created with: a key
short of the scope an operation needs is answered 403. The scope an operation requires
is shown next to its title, and the full catalogue lives in the Scopes reference.
Keys are created from the BeeL dashboard. They are secret credentials: do not share them or commit them to source control.
In: header
Path Parameters
Your own account, or an account you provisioned. The account in the path, not the credential, decides which account the operation acts on. A 403 is returned when you do not reach it, the same response an account that does not exist gets.
uuidHeader Parameters
Idempotency key to prevent duplicates in sensitive operations.
- Any unique client-generated string (e.g. an order id). A UUID also works but is not required
- Allowed characters: letters, digits,
_and-(max 255 chars) - Retrying with the same key replays the first response when it was a success (2xx) or a
server error (5xx): same status and body, plus the header
Idempotency-Replay: true. After a 5xx, check whether the operation took effect before retrying with a new key - A 4xx is not stored: the key is released, so the corrected request can reuse it
- Stored responses expire 24 hours after processing
The key is scoped per user and environment, and bound to the request body, so retrying after a network timeout replays the stored response instead of repeating the operation.
| Status | Code | When |
|---|---|---|
400 | INVALID_IDEMPOTENCY_KEY | The key breaks the format rules above. |
409 | IDEMPOTENCY_KEY_PROCESSING | The first request is still in flight. Wait for the Retry-After seconds (2) and retry with the same key. |
409 | IDEMPOTENCY_KEY_MISMATCH | The key was already used with a different body. Use a new key. |
^[a-zA-Z0-9_-]+$length <= 255Fully qualified domain name to send from. It is trimmed, lowercased and stored without a trailing dot; internationalised names are stored in their ASCII form.
Response Body
application/json
application/json
application/json
application/json
application/json
application/json
application/json
application/json
application/json
application/json
application/json
curl -X POST "https://app.beel.es/api/v1/accounts/497f6eca-6276-4993-bfeb-53cbbbba6f08/email-domains" \ -H "Content-Type: application/json" \ -d '{ "domain": "facturas.ejemplo.com" }'{
"success": true,
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"domain": "facturas.ejemplo.com",
"status": "PENDING",
"is_default": true,
"dns_records": [
{
"type": "MX",
"name": "send",
"value": "mail.example.com",
"priority": 10,
"status": "PENDING"
},
{
"type": "TXT",
"name": "send",
"value": "v=spf1 include:example.com ~all",
"status": "PENDING"
}
],
"created_at": "2025-01-20T14:30:00Z"
},
"meta": {
"timestamp": "2025-01-20T14:30:00Z",
"request_id": "req_123"
}
}{
"success": false,
"error": {
"code": "BAD_REQUEST",
"message": "Invalid request"
},
"meta": {
"timestamp": "2025-01-15T10:30:00Z",
"request_id": "4bf92f3577b34da6a3ce929d0e0e4736"
}
}{
"success": false,
"error": {
"code": "UNAUTHORIZED",
"message": "Authentication is required to access this resource"
},
"meta": {
"timestamp": "2025-01-15T10:30:00Z",
"request_id": "4bf92f3577b34da6a3ce929d0e0e4736"
}
}{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "The provided data is not valid",
"details": {
"field": "specific error message"
}
},
"meta": {
"timestamp": "2025-01-15T10:30:00Z",
"request_id": "4bf92f3577b34da6a3ce929d0e0e4736"
},
"type": "https://docs.beel.es/errors/INVOICE_NO_LINES",
"title": "INVOICE_NO_LINES",
"detail": "The invoice must have at least one line",
"instance": "/v1/invoices/abc-123"
}{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "The provided data is not valid",
"details": {
"field": "specific error message"
}
},
"meta": {
"timestamp": "2025-01-15T10:30:00Z",
"request_id": "4bf92f3577b34da6a3ce929d0e0e4736"
},
"type": "https://docs.beel.es/errors/INVOICE_NO_LINES",
"title": "INVOICE_NO_LINES",
"detail": "The invoice must have at least one line",
"instance": "/v1/invoices/abc-123"
}{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "The provided data is not valid",
"details": {
"field": "specific error message"
}
},
"meta": {
"timestamp": "2025-01-15T10:30:00Z",
"request_id": "4bf92f3577b34da6a3ce929d0e0e4736"
},
"type": "https://docs.beel.es/errors/INVOICE_NO_LINES",
"title": "INVOICE_NO_LINES",
"detail": "The invoice must have at least one line",
"instance": "/v1/invoices/abc-123"
}{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "The provided data is not valid",
"details": {
"field": "specific error message"
}
},
"meta": {
"timestamp": "2025-01-15T10:30:00Z",
"request_id": "4bf92f3577b34da6a3ce929d0e0e4736"
},
"type": "https://docs.beel.es/errors/INVOICE_NO_LINES",
"title": "INVOICE_NO_LINES",
"detail": "The invoice must have at least one line",
"instance": "/v1/invoices/abc-123"
}{
"success": false,
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Too many requests. Please try again in 60 seconds."
},
"meta": {
"timestamp": "2025-01-15T10:30:00Z",
"request_id": "4bf92f3577b34da6a3ce929d0e0e4736"
}
}{
"success": false,
"error": {
"code": "INTERNAL_ERROR",
"message": "Internal server error"
},
"meta": {
"timestamp": "2025-01-15T10:30:00Z",
"request_id": "4bf92f3577b34da6a3ce929d0e0e4736"
}
}{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "The provided data is not valid",
"details": {
"field": "specific error message"
}
},
"meta": {
"timestamp": "2025-01-15T10:30:00Z",
"request_id": "4bf92f3577b34da6a3ce929d0e0e4736"
},
"type": "https://docs.beel.es/errors/INVOICE_NO_LINES",
"title": "INVOICE_NO_LINES",
"detail": "The invoice must have at least one line",
"instance": "/v1/invoices/abc-123"
}{
"success": false,
"error": {
"code": "UNSUPPORTED_MEDIA_TYPE",
"message": "Unsupported media type: text/plain. Supported: application/json"
},
"meta": {
"timestamp": "2025-01-15T10:30:00Z",
"request_id": "4bf92f3577b34da6a3ce929d0e0e4736"
}
}List the email domains GET
Returns the domains the account sends its emails from, each with the DNS records to publish and the verification status of the domain and of every record. It only reads; it does not register or verify anything. - **Without the add-on:** the list is still returned, so you can see what the account holds, and `max_email_domains` is `0`. - **`max_email_domains`:** the maximum number of domains the custom email domain add-on allows the account; `null` when the add-on sets no explicit limit. The add-on is contracted with BeeL. - **`verified_at` and `last_checked_at`:** absent until the domain is verified or checked for the first time. - **Environment:** domains belong to the account and are the same in test and live. **Closed catalogue.** The domains of an account are a short, bounded set: the response carries no `pagination`, the operation takes no paging parameters, and every response holds the whole set.
Get an email domain GET
Returns one domain of your account with the DNS records to publish and the verification status of the domain and of every record. It only reads; it does not verify anything. A domain still registering shows `status: PENDING` with `dns_records: []`. It works without the custom email domain add-on, so you can inspect what the account holds. A domain of another account, or one already removed, answers `404`.