Skip to content

Public and private keys

Every organization has one public key and up to 20 active private keys. Find them on the Security page, in the Public key and Private keys sections. Owners, admins and developers can see them; only owners and admins can create, revoke and rotate keys.

Public key Private key
Format pk_… sk_…
Secret? No – it is visible in your page source Yes – like a password
Use in Browsers, mobile apps, static sites Servers, serverless functions, CI
Send as body user_id or header X-Frontmail-Public-Key header Authorization: Bearer sk_… or body accessToken
Origin check ✓ must match allowed origins; no Origin needs Allow mobile apps an Origin header is refused (private_key_in_browser) unless allowed
Turnstile ✓ when the template requires it skipped
Rate limits per organization, per IP, per key per organization, per key
Endpoints send, send-form, uploads, messages/:id (with status token) all, including send-batch, history, templates

The public key only identifies your organization. Anyone can copy it from your site, which is why requests signed with it are checked for their origin, bot signals and rate – and why templates cannot use dynamic recipients unless you explicitly allow it. A public-key client can read the status of its own messages only, using the status_token returned by send (sent in the X-Frontmail-Status-Token header).

Private keys bypass the browser-oriented checks, so they must never reach a browser. Typical uses: sending from your backend, the Node SDK, batch sends, reading history, and npx frontmail types.

  • Create one with New private key. It is shown once – copy it and confirm with I’ve stored it safely. Frontmail stores only a hash and the last four characters.
  • Give each key a name (e.g. “Production backend”, “CI”) so you can see where it is used – the Last used column shows when each key was last used.
  • The Allow private key API switch (Security → Abuse protection) can switch off private-key access for the organization entirely if you only send from browsers; private-key requests then fail with 403 forbidden.
  • Private-key requests that carry an Origin header – i.e. that come from a web page – fail with 403 private_key_in_browser. This also applies to the EmailJS-style accessToken body field and to the read endpoints. Servers don’t send Origin, so server-side code is unaffected. Only if you really need a private key in a browser (an internal admin tool, never a public page) turn on Allow private keys in browsers (Security → Abuse protection, off by default).

Private keys: create a new key, deploy it to your servers, check that Last used of the old key stops changing, then Revoke the old key. Revocation is immediate; requests with a revoked key fail with invalid_private_key.

Public key: click Rotate key in the Public key section. You get a new key immediately; the old one keeps working for a grace period of 24 hours so you can redeploy your site, then it fails with invalid_public_key. Rotate the public key when you see abuse despite allowed origins and Turnstile, or when you move an app to a new organization.

Key creation, revocation and rotation are recorded in the audit log.