Authentication

API keys for servers and agents, session tokens for browsers.

Every call to the Senddy API is authenticated. There are two kinds of credential, and which one you use depends on where your code runs.

Where your code runsUseWhy
Your server, a script, an agentAPI keySimple, long-lived, kept secret on your side
A user's browser or phoneSession tokenShort-lived, per user, safe to ship to the client

API keys#

Create keys in the Developer Dashboard. Pass one to the client as apiKey, and the client sends it as X-API-Key on every request.

TypeScript
const senddy = createSenddyClient({
  // …chain config
  apiKey: process.env.SENDDY_API_KEY,
});

Never put an API key in browser code. Anyone can read it from your bundle, and every user would share one rate limit.

Session tokens#

In a browser, your server mints a short-lived token for each signed-in user, and the client uses that instead of a key.

On your server, after you've verified the user is signed in:

TypeScript
const res = await fetch(`${SENDDY_API_URL}/session`, {
  method: 'POST',
  headers: { 'content-type': 'application/json', 'x-api-key': process.env.SENDDY_API_KEY! },
  body: JSON.stringify({ sub: user.id, perms: ['read', 'write'], ttl_secs: 900 }),
});
const { token, exp } = await res.json(); // token starts with "sst_"

Require an explicit Authorization header on that route, not just a cookie, so another site can't mint tokens for a signed-in user. Throttle it per user.

In the browser, give the client a provider function. It's called when a token is needed, and again if one expires, after which the request is retried once.

TypeScript
const senddy = createSenddyClient({
  // …chain config
  sessionToken: async () => {
    const res = await fetch('/api/session-token', { method: 'POST', headers: { authorization: `Bearer ${userAuthToken}` } });
    return (await res.json()).token;
  },
});

Cache the token in the provider and refresh it shortly before it expires. When sessionToken is set, the client doesn't send apiKey.

Using Privy#

If your app signs users in with Privy, you can skip the server route. Register your Privy app with us at developers@senddy.com, and the browser can exchange the user's Privy access token for a session directly at POST /session/exchange.

Rate limits#

Limit
Per signed-in user, with a session token120 requests a minute
Per developer60 requests a minute and 10,000 a day by default. Ask us for more

Requests over a limit get a 429. A request with an expired session token gets 401 SESSION_EXPIRED, which the client handles for you.