About Per-Request Credentials
The Authentication guide is built on one rule: the Sent API key
arrives as Authorization: Bearer <key>, becomes an SDK client for that request, and is gone
when the request ends. It is never a boot-time singleton and never a stored environment
variable. This page explains why the pattern exists, who actually sends the bearer key in
each deployment shape, and why it makes tenant isolation structural rather than something you
remember to enforce.
Why per-request
Three concrete payoffs, not dogma:
- Multi-tenant by default. One deployment can serve many customers, each with their own key, because the credential travels with the request instead of living in the process.
- No secret at rest in your app. The key is never written to your environment, config, or disk. Your app is a pass-through; it holds the key only for the microseconds a request is in flight.
- Rotation is free. A customer rotates their key in the dashboard and sends the new one on the next request. Nothing to redeploy, no restart.
The underlying idea is not unique to Sent. The key is a bearer credential, and a bearer credential in a backend is analogous to a session token in a web app: it travels with each request and is resolved fresh each time, so no request depends on state left behind by an earlier one. A per-request client is what that model looks like inside your own service.
Who sends the bearer key
The Authorization: Bearer <key> used throughout the Authentication guide is the shape of
the pattern; who supplies the key depends entirely on whether you have one Sent account or
many.
Multi-tenant / reseller. Each of your customers has their own Sent account and key. Here, "the caller" is genuinely external (your customer's own backend, or their session in your dashboard), and they legitimately hand you their Sent key on each call because it's theirs.
Single-tenant (the common case). You have exactly one Sent account, so there is no external party who owns a Sent key, and a key shipped to a browser or mobile app is a key published. "Per-request" here means your own backend resolves the one key for each request or job, rather than baking it into a global at boot.
In the single-tenant case, what matters is when the key is read, not what system it's read from. Reading it from your normal config or env on each request (not cached into a module-level variable at import or boot time) is a perfectly reasonable starting point, and it still delivers the real payoffs: rotation without a redeploy, and no key frozen into a long-lived process.
A dedicated secrets manager earns its operational cost when you need cross-service rotation: one place to change a credential that many services read. Until then, per-request resolution from ordinary config gives you the same properties with less machinery.
Why tenant isolation is structural
Because the client is constructed from the request's key and discarded when the request ends, there is no shared client and no way for one tenant's calls to go out under another tenant's key. Isolation doesn't depend on every developer remembering to scope every call; the shape of the code makes the failure impossible.
A boot-time singleton silently forfeits this: every request goes out under whatever single key the process started with, which makes multi-tenant serving impossible and turns key rotation into a redeploy. The per-request factory is what keeps tenant A's messages from being sent on tenant B's account.
Single-tenant apps get the mirror image of the same property: because nothing caches the key across requests, rotating the one key is a configuration change, not a deployment event.
Where to go from here
The pattern itself is a few small functions per framework. To act on this understanding:
Authenticating Requests with Per-Request Clients
Build a Sent SDK client from the request's bearer key. Per-request client factories in seven frameworks, 401 guards, key verification, and easy rotation.
Sending Messages with the Sent SDK: The Outbound Path
A thin, testable service layer over messages.send: the request shape, multi-recipient response mapping, channels, sandbox sends, and where status comes from.