All docs

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:

  • userid, 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, otherwise null.
  • subscription{ plan, status, currentPeriodEnd, manageable }.
  • isAdmintrue only 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.