Sending domains (Amba-managed or self-hosted DNS), verification, and the From address rules for project email.
Project email goes out from Amba's shared mailbox until the project adds a sending domain and it verifies. A domain the project bought through Amba is Amba-managed (dns_managed: true): Amba writes its DNS records, starts verification, and keeps checking, so there is no DNS step. Any other domain is self-hosted (dns_managed: false): you create the returned records at your DNS host, then call verify. The email guide walks through both paths. Templates, suppressions, sends, and deliveries are described in the email guide.
Sender choice happens on the server. The client SDKs need no change: passwordless sign-in email (one-time codes and magic links) uses the project's default sender once it is set.
Endpoints
| Method | Path | Description |
|---|---|---|
| POST | /admin/projects/:projectId/email/domains | Add a sending domain. |
| GET | /admin/projects/:projectId/email/domains | List sending domains. |
| GET | /admin/projects/:projectId/email/domains/:domain | Refresh one sending domain. |
| POST | /admin/projects/:projectId/email/domains/:domain/verify | Publish (Amba-managed) and verify. |
| DELETE | /admin/projects/:projectId/email/domains/:domain | Remove a sending domain. |
| POST | /admin/projects/:projectId/email/send | Send email; from.email must be on a verified domain. |
| PATCH | /admin/projects/:projectId | Set the default sender (see Projects). |
The sending-domain object
Every domain endpoint returns this shape (inside data).
| Field | Type | Description |
|---|---|---|
domain | string | The sending domain. |
status | "pending" | "verified" | "failed" | The project can send from addresses on the domain once it is verified. |
provider_status | string | null | Verification progress as last checked: not_started, pending, partially_verified (some records verified, the rest still being checked; status stays pending), verified, partially_failed, failed, or temporary_failure. |
dns_managed | boolean | true: one of the project's own domains bought through Amba (or a subdomain of one); Amba publishes the records and no DNS action is needed. false: you create the records. |
dns_status | "published" | "pending" | "conflict" | null | Amba-managed only. published: every record in records is in DNS. pending: Amba writes the rest on the next automatic check. conflict: a record Amba did not create blocks a name. null when self-hosted. |
dns_error | string | null | Amba-managed only: why the records are not all published yet. |
records | Record[] | The DNS records the domain needs (below). |
recommended_dmarc | object | null | Self-hosted domains with no DMARC policy: _dmarc.<domain> TXT v=DMARC1; p=none; to create. Always null for Amba-managed domains, where Amba adds it. |
default_sender_fallback | boolean | true while the project default sender is on this domain and the domain is unverified; email then goes from the shared mailbox. |
verified_at | string | null | When the domain verified. |
next_check_at | string | null | When Amba next checks verification automatically; null when no check is scheduled. |
checks_until | string | null | End of the 72-hour window of automatic checks that starts when Amba publishes the records or verify is called. |
next_step | string | What happens next and whether any DNS action is needed. While verification is partway (partially_verified), it names each record still unverified. |
last_error | string | null | The last verification refresh error. |
created_at, updated_at | string | Timestamps. |
Record
| Field | Type | Description |
|---|---|---|
record | "DKIM" | "SPF" | "DMARC" | Purpose. DMARC appears only for Amba-managed domains. |
type | "TXT" | "MX" | "CNAME" | DNS record type. The return-path (SPF) records can include a CNAME such as rsend.example.com. |
name | string | Fully qualified record name, e.g. send.example.com. |
value | string | Record content. For MX, the mail host (priority holds the priority). For CNAME, the target host. |
priority | number | MX only. |
status | string | Verification status of this record as last checked; verified once it verifies. |
publish_state | "published" | "pending" | "conflict" | "not_needed" | null | Amba-managed only. not_needed: DMARC, the domain already has a policy, a TXT record or a delegated CNAME (kept as it is). null when self-hosted. |
created_by_amba | boolean | true when Amba created the record; removing the domain deletes it. |
conflict | string | null | The existing record that blocks this one, when publish_state is conflict. |
POST /admin/projects/:projectId/email/domains
Add a sending domain.
- Amba-managed (one of this project's domains bought through Amba, or a subdomain of one): Amba writes the DKIM TXT record, the
send.MX and SPF TXT records, any return-path CNAME (such asrsend.example.com), and_dmarcTXTv=DMARC1; p=none;when the domain has no DMARC policy, then starts verification once every record is in DNS and schedules automatic checks. Identical existing records are left alone, the domain's root MX and SPF records (email forwarding) are never touched, and an existing DMARC policy is kept. - Self-hosted (any other domain): Amba registers the domain and returns the records to create. Nothing is written to DNS.
Request
| Field | Type | Required | Description |
|---|---|---|---|
domain | string | yes | e.g. example.com or mail.example.com. |
Response 201 (Amba-managed)
Response 201 (self-hosted)
Errors
400 INVALID_JSON/400 INVALID_DOMAIN— the body or domain is malformed.409 DOMAIN_CLAIMED— the domain belongs to another project: it was added there first, or another project bought it through Amba.409 DNS_RECORD_CONFLICT— Amba-managed: a record Amba did not create holds a name Amba needs (another SPF policy onsend., another DKIM key at the selector, a CNAME at a TXT or MX name, or any record at the name of a return-path CNAME other than that same CNAME). The message names each record; Amba leaves it unchanged. The domain is added anyway and returned inerror.details.domain. If a site or function domain on this project uses that name, remove that domain; otherwise contact Amba support to have the record removed. Then call verify.502 EMAIL_PROVIDER_REJECTED/503 EMAIL_PROVIDER_UNAVAILABLE— the domain could not be registered; retry.
Try it:
/admin/projects/%7B%7BprojectId%7D%7D/email/domainscurl -X POST 'https://api.amba.dev/v1/admin/projects/%7B%7BprojectId%7D%7D/email/domains' \
-H 'Content-Type: application/json' \
-d '{
"domain": "mail.example.com"
}'Curl:
GET /admin/projects/:projectId/email/domains
List the project's sending domains, refreshing each one's verification status.
Response 200
Try it:
/admin/projects/%7B%7BprojectId%7D%7D/email/domainscurl -X GET 'https://api.amba.dev/v1/admin/projects/%7B%7BprojectId%7D%7D/email/domains'Curl:
GET /admin/projects/:projectId/email/domains/:domain
Refresh one sending domain. Reads only: it never writes DNS.
Response 200
The sending-domain object.
Errors
404 DOMAIN_NOT_FOUND.
Try it:
/admin/projects/%7B%7BprojectId%7D%7D/email/domains/%7B%7Bdomain%7D%7Dcurl -X GET 'https://api.amba.dev/v1/admin/projects/%7B%7BprojectId%7D%7D/email/domains/%7B%7Bdomain%7D%7D'Curl:
POST /admin/projects/:projectId/email/domains/:domain/verify
Start verification and restart the 72-hour window of automatic checks.
- Amba-managed: first re-publishes any record that is not in DNS yet (and adopts a domain that was added before its purchase completed), then starts verification once every record is published.
- Self-hosted: call this after creating the records. Amba keeps checking automatically until the domain verifies or the window ends.
When the window ends unverified, the domain stays pending, next_check_at becomes null, and next_step asks you to call verify again. On the transition to verified, Amba emits the email.domain.verified control event ({ "domain": "example.com", "dns_managed": true }) to subscribed control webhooks.
Response 200
The sending-domain object.
Errors
404 DOMAIN_NOT_FOUND.409 DNS_RECORD_CONFLICT— as for add.502 EMAIL_PROVIDER_REJECTED/503 EMAIL_PROVIDER_UNAVAILABLE— the verification request failed; retry.
Try it:
/admin/projects/%7B%7BprojectId%7D%7D/email/domains/%7B%7Bdomain%7D%7D/verifycurl -X POST 'https://api.amba.dev/v1/admin/projects/%7B%7BprojectId%7D%7D/email/domains/%7B%7Bdomain%7D%7D/verify'Curl:
DELETE /admin/projects/:projectId/email/domains/:domain
Remove a sending domain. For an Amba-managed domain, Amba deletes the DNS records it created; every other record (your own records, an existing DMARC policy, email forwarding) stays as it is. If the project default sender used this domain, email falls back to the shared mailbox.
Response 200
Errors
404 DOMAIN_NOT_FOUND.502 DNS_CLEANUP_FAILED— the records Amba created could not be deleted. Nothing was removed; retry.
Try it:
/admin/projects/%7B%7BprojectId%7D%7D/email/domains/%7B%7Bdomain%7D%7Dcurl -X DELETE 'https://api.amba.dev/v1/admin/projects/%7B%7BprojectId%7D%7D/email/domains/%7B%7Bdomain%7D%7D'Curl:
POST /admin/projects/:projectId/email/send
Send a templated or ad-hoc email. The full body is described in the email guide. Sender fields:
| Field | Type | Description |
|---|---|---|
from | { email, name? } | Optional. from.email must be on a verified sending domain of this project. Defaults to the project default sender, then the shared mailbox. |
reply_to | string | string[] | Optional. Defaults to the project's default_reply_to. |
Errors
400 INVALID_SENDER—from.emailis not on a verified sending domain of this project. Nothing is sent.
Try it:
/admin/projects/%7B%7BprojectId%7D%7D/email/sendcurl -X POST 'https://api.amba.dev/v1/admin/projects/%7B%7BprojectId%7D%7D/email/send' \
-H 'Content-Type: application/json' \
-d '{
"to": {
"email": "user@example.com"
},
"subject": "Welcome",
"text": "Thanks for signing up."
}'Curl: