Postbox docs

Authentication

Two credential types, what each one reaches, and how project scoping works.

Every request carries a bearer credential:

Authorization: Bearer pb_live_...

There are two prefixes. The prefix is not decoration: it is what the server uses to decide what the credential can reach.

PrefixReachesHeld by
pb_live_…Everything in a projectYour server. Never a browser.
pb_tok_…One single mailboxA browser or end-user client.

Project keys (pb_live_)

A project key belongs to one project inside your org. Create one in the console, or over the API for automated rotation (see API keys).

For /messages, /events, /tokens, and /actions the key is already project-scoped. There is nothing else to pass.

For org-level routes (/domains, /mailboxes, /webhooks, /folders, policies, keys, stats) the key authenticates the whole org, so you point a call at one project with a header:

X-Project-Id: prj_...

Leave it off for genuinely org-level calls, such as listing projects. An unknown or foreign project ID returns 404, not 403, because Postbox does not confirm the existence of resources you cannot reach.

A pb_live_ key is project-scoped, but your plan allowance is metered org-wide. A busy project on a shared org plan can trip the cap for every other project in the org. Account for this before splitting environments across many projects on a low tier.

Mailbox tokens (pb_tok_)

A mailbox token is minted server-side from a project key and is safe to hand to an untrusted client. It is locked to one mailbox for its whole life.

const { token } = await pb.tokens.create({
  mailboxId: mailbox.id,
  permissions: ["read"], // required: name at least one scope
  expiresIn: 3600, // seconds; defaults to 30 days
});
// → { id, token: "pb_tok_...", expiresAt }

permissions is required. A token minted without at least one scope is rejected with 400, because a credential handed to a browser must never default to full mailbox control. See Permissions.

Using a pb_tok_ against a sibling mailbox in the same project returns 403. It never returns another mailbox's data.

Keep expiresIn short. The default of 30 days is a convenience, not a recommendation, and a token in a browser is a token you no longer control.

The raw HTTP

The SDK is a thin wrapper. To mint a token from a language without one, the contract is:

POST /v1/tokens
Authorization: Bearer pb_live_...
Content-Type: application/json

{ "mailboxId": "…", "permissions": ["read"], "expiresIn": 3600 }
{ "success": true, "data": { "id": "…", "token": "pb_tok_...", "expiresAt": "…" } }

Minting a token requires the manage permission.

Revoking a token

A token stays valid until it expires, unless you revoke it first. A revoked token fails every request with 401 immediately, even while its expiresAt is still in the future.

POST /v1/tokens/{id}/revoke
Authorization: Bearer pb_live_...
{ "success": true, "data": { "id": "…", "revokedAt": "…" } }

Revocation is idempotent: revoking a token that is already revoked returns its original revocation time. To cut a whole mailbox off at once (a suspended student, say) revoke every active token it holds in one call:

DELETE /v1/mailboxes/{mailboxId}/tokens
Authorization: Bearer pb_live_...
{ "success": true, "data": { "revoked": 3 } }

Both require the manage permission. A mailbox-scoped pb_tok_ may only revoke tokens for its own mailbox.

Permissions

Permissions are checked per credential. Today the set is coarse:

PermissionGrants
sendSending mail.
receive (alias read)Reading and listing messages.
manage (alias manage_folders)Managing folders, minting tokens, and other management writes.

Credentials fail closed. A credential whose permission list is empty holds no scopes, so every permission check denies it with 403. There is no "unscoped means full access" default. Name the scopes you actually need: a read-only inbox token should carry ["read"] and nothing more.

Keeping keys safe

  • Never ship a pb_live_ key to a browser, a mobile app, or anything else you do not control. Mint a pb_tok_ instead.
  • Give each environment its own key so you can revoke one without an outage everywhere else.
  • Give each credential only the scopes it needs. A leaked send-only key cannot read mail or manage the account, and a credential with no scopes reaches nothing.
  • Rotate by creating the new key, deploying it, then revoking the old one. Keys are shown once at creation and stored only as a hash, so a lost key cannot be recovered, only replaced.