Skip to main content
Ruber’s HTTP API lets your own software work with mail in the mailboxes your organization owns. It is a normal JSON API over HTTPS: no SDK required, no websocket, nothing to install.

What you can do

Rolling out. GET /v1/mailboxes is live now. The rest are shipping shortly — until they land, a call may answer 404. Nothing about the request or response shapes below will change when they do.

Base URL

Every request must be HTTPS. There is no HTTP port to redirect from.

Authentication

Send your key as a bearer token:
Keys are created under Settings → API keys in the dashboard. They begin rk_, and the full key is shown exactly once, in the dialog that creates it. Ruber stores only a SHA-256 hash — we cannot show it to you again, and we cannot recover it. If a key is lost, revoke it and create another.
A key is a password for your mail. Keep it out of source control, out of front-end code, and out of anything a browser downloads. If a key is exposed, revoke it in the dashboard — revocation takes effect immediately, on the next request.

Every authentication failure looks the same

A missing header, a malformed header, a key that never existed and a key you revoked all answer the same 401 with the same sentence. That is deliberate: distinguishing them would let someone holding a list of guesses learn which ones are real keys that happen to be revoked. A missing permission is different, and is deliberately specific — see below.

Permissions

Every key carries a set of permissions, and a key can only do what you granted it when you created it. There is no “full access” key, no admin, and no wildcard. Permissions cannot be changed after creation — to change what a key may do, create a new one and revoke the old. When you create a key you choose one level per resource: Two things about that table are worth reading twice. Write includes Read. Choosing Write on a resource grants its read scope too. A key that may move a message between folders but cannot see which folder it is in describes no real integration. Sending is its own resource. messages:write covers changing mail that already exists — marking it read, starring it, filing it. It does not let a key send anything. Sending creates mail that leaves under your domain’s reputation and spends your plan’s daily allowance, so it is a separate, deliberate choice.

When a key lacks a permission

You get a 403 that names exactly what was missing, because by then the caller has proved they hold a real key and there is nothing left to protect:

Private mailboxes are not readable

A Private mailbox is encrypted to a key held only in its owner’s browser. Ruber holds no copy, so there is nothing the API could return but ciphertext and nothing it could send. Private mailboxes do appear in GET /v1/mailboxes, with "mode": "private" — hiding them would make an integration report a mailbox as missing when it simply cannot be read by anyone but its owner. Any endpoint that takes an address will refuse a Private one with invalid_request and say why. Smart mailboxes work normally.

Errors

Every error has the same shape. The code is stable and is what your software should branch on; the message is written for a human reading a log and may be reworded at any time.
404 does not mean “does not exist”. A mailbox belonging to another organization and a mailbox that was never created both answer not_found. Telling them apart would turn the API into a way to test whether an address exists on the platform, one guess at a time.

Rate limits

Requests are limited per key, at 600 per minute. That is ten a second sustained — comfortably above any integration doing real work. Going over returns 429 with a Retry-After header giving the seconds to wait. There is no lockout: a client that misjudges its own rate recovers on the next window.
Narrower limits still apply underneath. Sending, in particular, also passes a per-account hourly limit, a short burst ceiling, and your plan’s daily allowance — so this ceiling is never a way around them. A send refused by the daily allowance returns quota_exceeded, not rate_limited.

Caching

Every response carries Cache-Control: no-store. Responses are scoped to one organization’s mail, and a shared cache keyed on the URL alone would serve one customer’s inbox to another. Do not cache these responses in shared infrastructure.