eoinbox is not open yet. This site describes the service we are building; items marked "Later" arrive after launch.
All docs

Using the API

Create an API key, call the management API, connect Bitwarden through the SimpleLogin-compatible API, and read mail with JMAP.

eoinbox has two public APIs:

  • the management API at https://api.eoinbox.com/v1 for domains, addresses, identities, keys and your account;
  • JMAP at https://mail.eoinbox.com for the mail itself.

The full list of endpoints is in the API reference.

Create an API key

  1. Open Settings → API keys → Create key.
  2. Name it, and choose only the scopes it needs, for example addresses:write for a script that creates aliases.
  3. Optionally set an expiry date and limit the key to specific domains.
  4. Copy the key. It starts with eo_ and is shown only once.

Available scopes: account:read, account:write, domains:read, domains:write, addresses:read, addresses:write, identities:read, identities:write, tokens:write, webhooks:write.

Make a request

Send the key in the Authorization header:

curl https://api.eoinbox.com/v1/domains \
  -H "Authorization: Bearer eo_your_key"

Create an alias:

curl -X POST https://api.eoinbox.com/v1/addresses \
  -H "Authorization: Bearer eo_your_key" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 3f1c0d7e-shop-signup" \
  -d '{"domainId": "dom_...", "localPart": "shop", "note": "online shop"}'

Create a masked alias with a random name:

curl -X POST https://api.eoinbox.com/v1/addresses/random \
  -H "Authorization: Bearer eo_your_key" \
  -H "Content-Type: application/json" \
  -d '{"note": "signed up at example-shop"}'

Without domainId, the masked alias is created on alias.eoinbox.com.

Conventions

  • JSON in and out, UTF-8.
  • Errors look like this, with a machine-readable code:
    { "error": { "code": "plan_limit", "message": "Alias limit reached", "details": { "limit": 50 } } }
    Common codes: unauthorized, insufficient_scope, not_found, validation_failed, conflict, plan_limit, rate_limited.
  • Pagination: lists accept ?limit=50&cursor=... and return { "items": [...], "nextCursor": "..." }. nextCursor is null on the last page.
  • Idempotency: send an Idempotency-Key header with POST requests and you can safely retry for 24 hours without creating duplicates.
  • Rate limits apply per key. On 429, wait and retry.

Bitwarden

Bitwarden's password generator can create a new alias on your domain each time you sign up somewhere. It talks to eoinbox through our SimpleLogin-compatible API.

  1. In eoinbox, create an API key with the addresses:write scope. To control which domain new aliases use, restrict the key to that domain.
  2. In Bitwarden, open the Generator and select Username.
  3. Choose Forwarded email alias as the type and SimpleLogin as the service.
  4. Paste your eoinbox key into API key.
  5. Set the server URL (labelled for self-hosted servers) to https://api.eoinbox.com/compat/simplelogin.
  6. Click Generate. A new alias appears in your eoinbox address list, with a note about where it was made.

Labels in Bitwarden may differ slightly between the browser extension, desktop and mobile apps.

SimpleLogin and addy.io compatibility

Other tools that support SimpleLogin or addy.io can use eoinbox the same way:

ServiceBase URLAuthentication
SimpleLoginhttps://api.eoinbox.com/compat/simpleloginAuthentication: eo_your_key
addy.iohttps://api.eoinbox.com/compat/addyAuthorization: Bearer eo_your_key

Both cover the alias part of those APIs: creating random and custom aliases, listing, enabling, disabling and deleting them. They use the same eoinbox API keys. For anything else, use the management API.

Mail data with JMAP

Reading, searching and writing mail uses JMAP (RFC 8620 and RFC 8621), the same API our webmail uses. Point any JMAP library at https://mail.eoinbox.com and authenticate with your API key. Sending mail requires the corresponding scope.

Webhooks (after launch)

Webhooks notify your server when something happens: message.received, address.created, address.updated, domain.status_changed and message.bounced. Each request carries an Eoinbox-Signature header:

Eoinbox-Signature: t=1767225600,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd

v1 is the hex HMAC-SHA256 of t + "." + body, using the webhook secret. Check the signature and reject requests with an old timestamp.