Skip to content

Using the Admin API

The Admin API is a JSON-over-HTTP RPC API served by the admin-api Lambda. Every operation is a POST request with a JSON body; there are no GET, PUT, or DELETE routes.

The Admin API is served at api.<domainName>. The Mailbox CDK construct provisions the ACM certificate and Route 53 record automatically.

If the optional prefix property is set, a label is inserted between the service name and the base domain:

CDK propsAdmin API endpoint
domainName: "example.com"https://api.example.com
domainName: "example.com", prefix: "mailbox"https://api.mailbox.example.com

The Admin API requires a Bearer JWT issued by the Cognito User Pool that was passed to the Mailbox construct. The token must carry the adminApi audience and the ADMIN permission scope.

Use the OAuth 2.0 client_credentials flow. The CDK stack provisions a dedicated headless client whose credentials are available as CloudFormation outputs (AdminHeadlessClientId and AdminHeadlessClientSecret).

Terminal window
# 1 — Obtain a token from Cognito
# The exact scope string depends on your IDP plugin configuration.
# Check the CloudFormation outputs or ask your administrator for the configured scope.
TOKEN=$(curl -s -X POST \
"https://<cognito-domain>.auth.<region>.amazoncognito.com/oauth2/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=<AdminHeadlessClientId>" \
-d "client_secret=<AdminHeadlessClientSecret>" \
-d "scope=<admin-scope>" \
| jq -r '.access_token')
# 2 — Use the token in every Admin API call
curl -s -X POST "https://api.mail.example.com/domains/ListDomains" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{}'

Admin console UIs use the authorization_code flow. A short-lived access token is obtained via the Cognito hosted UI and sent in the same Authorization: Bearer header.

Every method call follows the same pattern:

POST /<service>/<MethodName>
Authorization: Bearer <token>
Content-Type: application/json
{ ...request fields... }

The service path and method name map directly to the protobuf service definitions in mailbox-idl/admin-api/proto/. For example, DomainsService.ListDomains is called at:

POST /domains/ListDomains

Successful responses return HTTP 200 with a JSON body containing the response fields defined in the IDL. There is no envelope wrapper — the response is the message directly.

Errors return a non-2xx status code with a JSON body:

{
"code": "not_found",
"message": "Domain 'example.com' does not exist"
}

Common status codes:

CodeMeaning
200Success
400Validation error — check the message field
401Missing or invalid token
403Token lacks the required permission scope
404Requested resource not found
409Conflict (e.g. DNS record already exists)
500Internal error

The /status/Ping endpoint requires no specific scope and is useful for smoke-testing:

Terminal window
curl -s -X POST "https://api.mail.example.com/status/Ping" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{}'
# → {}
Terminal window
# 1 — Register a domain
curl -s -X POST "https://api.mail.example.com/domains/CreateDomain" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"domain": "acme.com"}' | jq .
# 2 — List DNS records the domain requires
curl -s -X POST "https://api.mail.example.com/domains/GetDomainVerification" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"domain_id": "<id-from-step-1>"}' | jq .
# 3 — Once DNS is in place, verify
curl -s -X POST "https://api.mail.example.com/domains/VerifyDomain" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"domain_id": "<id-from-step-1>"}' | jq .
Terminal window
# 1 — Create the user
USER=$(curl -s -X POST "https://api.mail.example.com/users/CreateUser" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"email": "alice@acme.com",
"display_name": "Alice"
}' | jq .)
echo $USER
# 2 — Add a mail alias so she can receive email
curl -s -X POST "https://api.mail.example.com/aliases/CreateAlias" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"account_id": "<account_id from USER>",
"local_part": "alice",
"domain_id": "<domain_id for acme.com>",
"is_active": true
}' | jq .