Authentication
SendItWhenever uses two kinds of credentials, for two kinds of caller:
- API keys — for machines (your backend, scripts, the SDK).
- Session login — for humans (the dashboard, in your browser).
Most integration work uses an API key. Session login only matters for account management actions like creating keys or managing billing.
API keys
An API key authenticates programmatic requests. Pass it as a bearer token:
Authorization: Bearer sw_live_xxx
Or, with the SDK, give it to the constructor:
const sendit = new SendIt("sw_live_xxx");
Key format
Keys are prefixed by environment so you can tell them apart at a glance:
| Prefix | Environment |
|---|---|
sw_live_ |
Production — real schedules. |
sw_test_ |
Testing. |
The SDK validates the format in the constructor and throws immediately if a key is empty or malformed, so a typo fails fast rather than on the first request.
How keys are stored
- A key's full value is shown only once, at creation. Copy it then — it cannot be retrieved again.
- We store only a SHA-256 hash of the key, never the original. If you lose a key, revoke it and create a new one.
- If you suspect a key has leaked, revoke it immediately from the dashboard.
Managing keys
Keys are created, listed, rotated, and revoked from your dashboard settings. These actions require session login, not an API key — an API key cannot mint, rotate, or revoke other keys (this prevents privilege escalation if a key leaks).
Rotating a key issues a fresh value and revokes the old one in a single step — useful when a key may have leaked but you want minimal downtime. As with creation, the new raw value is shown only once.
Session login
The dashboard signs you in without a password, using either:
- Magic link — enter your email, click the link we send.
- OAuth — sign in with Google or GitHub.
A successful login sets a session cookie (sw_session) that is HttpOnly (not readable by JavaScript) and SameSite=Lax (sent on top-level navigations but not cross-site requests, which mitigates CSRF). In production it is scoped to .sendit-whenever.com so the dashboard and API share it. The dashboard sends it automatically. The following actions are session-only and cannot be done with an API key:
- Creating and revoking API keys
- Changing your display name or deleting your account
- Starting checkout or opening the billing portal
Reading and writing schedules works with either an API key or a session.
Verifying which credential you have
GET /v1/me accepts either credential and returns your profile and current plan. The response includes:
user—id,email,name,avatarUrl,status,emailVerified,createdAt.authSource—"session"or"apiKey", so you can tell which credential authenticated the call.apiKey—{ id, env }when authenticated by a key, otherwisenull.subscription—{ plan, status, currentPeriodEnd, manageable }.isAdmin—trueonly for whitelisted admin sessions.
The SDK has no dedicated method for it because, in normal use, you authenticate per call — but it's a handy way to confirm a key is live:
curl https://api.sendit-whenever.com/v1/me \
-H "Authorization: Bearer sw_live_xxx"
A 401 UNAUTHORIZED means the key is missing, malformed, revoked, or belongs to a deactivated account. See Error Codes.