Authentication

AdminUpdated Sep 24, 2026

Authentication

Every authenticated endpoint takes a bearer token in the Authorization header:

Authorization: Bearer <token>

Shippified accepts two kinds of token on the same header:

Token

Format

Lifetime

Issued by

Intended for

API key

sk_ + 32 URL-safe base64 characters (35 characters total)

Until revoked

POST /api/account/api-keys or Settings → Developer

Scripts, servers, the SDK, the MCP server

Session token

64 hexadecimal characters

14 days from creation, not extended by use

POST /api/auth/login, POST /api/auth/register

The dashboard and mobile app

The server tells them apart by prefix. A token that starts with sk_ is looked up as an API key. Anything else is treated as a session token. The server does not read cookies or query-string tokens.

Note: Use an API key for programmatic access. Password login can require a Cloudflare Turnstile token (see Session tokens), which makes it impractical to script.

API keys

Properties

  • Full access to the workspace. A key can do everything its owner can do in the workspace. Keys have no scopes and no read-only mode. Treat every key as a production credential. The only exceptions are the irreversible account actions, export and deletion, which need a signed-in session.

  • Shown once. The raw key appears only in the response that creates it. The server stores a SHA-256 hash, and the key cannot be recovered later.

  • Identified by prefix. Each key record keeps the first 11 characters (sk_ plus 8), so you can tell keys apart without seeing the secret.

  • Usage tracking. lastUsedAt is updated on every request that authenticates with the key.

  • Limit. Each account can hold up to 25 keys. Creating a 26th returns 429.

  • No expiry. A key works until you revoke it.

Create a key

POST /api/account/api-keys

Body field

Type

Required

Notes

name

string

No

A label for the key. Trimmed and truncated to 80 characters. Defaults to "Untitled key".

curl -s -X POST https://shippified.net/api/account/api-keys \
  -H "Authorization: Bearer $SHIPPIFIED_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"Inventory sync"}'

Response 201 Created:

{
  "key": "sk_3kq9V0xExampleExampleExample1234",
  "record": {
    "id": "key_m1x2y3z4_a1b2c3",
    "name": "Inventory sync",
    "prefix": "sk_3kq9V0xE",
    "createdAt": "2026-09-24T15:02:11.482Z"
  }
}

Store key right away. It is never returned again.

Note: Any valid credential can create keys, including another API key. To mint your first key, use the dashboard (Settings → Developer → API keys) or a session token.

List keys

GET /api/account/api-keys

curl -s https://shippified.net/api/account/api-keys \
  -H "Authorization: Bearer $SHIPPIFIED_API_KEY"
{
  "items": [
    {
      "id": "key_m1x2y3z4_a1b2c3",
      "name": "Inventory sync",
      "prefix": "sk_3kq9V0xE",
      "createdAt": "2026-09-24T15:02:11.482Z",
      "lastUsedAt": "2026-09-24T15:10:40.019Z"
    }
  ]
}

This list is not paginated, since an account holds at most 25 keys. The key hash is never returned.

Revoke a key

DELETE /api/account/api-keys/:id

curl -s -X DELETE https://shippified.net/api/account/api-keys/key_m1x2y3z4_a1b2c3 \
  -H "Authorization: Bearer $SHIPPIFIED_API_KEY"

Returns 200 {"ok": true}, or 404 {"error": "API key not found"}. Revocation takes effect immediately: the next request with that key gets 401.

Rotating a key

Keys cannot be rotated in place. To rotate:

  1. Create a new key.

  2. Deploy the new key everywhere the old one is used.

  3. Revoke the old key.

Session tokens

Session tokens are what the dashboard uses. You get one from:

Endpoint

Body

Success

POST /api/auth/register

email, password (min. 8 chars), optional displayName, turnstileToken

201 {token, user, state}

POST /api/auth/login

email, password, turnstileToken

200 {token, user, state}

  • When the deployment has Cloudflare Turnstile configured, turnstileToken is required. A missing or invalid value returns 400.

  • Both endpoints are rate-limited to 10 requests per minute per client IP. Over the limit returns 429 with Retry-After: 60.

  • Wrong credentials return 401 {"error": "Invalid email or password"}.

Sessions expire 14 days after they are issued and are not refreshed by activity. To end a session early:

curl -s -X DELETE https://shippified.net/api/auth/session \
  -H "Authorization: Bearer $SESSION_TOKEN"

This deletes the session token sent in the header and always returns 200 {"ok": true}. It does not affect API keys. To revoke a key, use DELETE /api/account/api-keys/:id.

There is no guest or demo login on the production instance. Every session belongs to a registered account.

Checking who you are

GET /api/auth/me accepts either token type. It returns the account plus a workspace snapshot:

curl -s https://shippified.net/api/auth/me \
  -H "Authorization: Bearer $SHIPPIFIED_API_KEY"

The user object includes id, username, email, displayName, createdAt, publicProfile, publicStats, webhookHandle, timezone, plan, the subscription fields, and emailVerified. You need webhookHandle to build Discord intake URLs (see Getting orders in).

Failure responses

Situation

Status

Body

No Authorization header, malformed header, unknown or revoked key, expired or deleted session

401

{"error": "Not authenticated"}

API key limit reached (25)

429

{"error": "API key limit reached (25). Revoke unused keys first."}

API key used for account export or deletion

401

{"error": "Sign in to … (API keys can't do this)."}

Invalid and expired credentials get the same 401. The response does not say which case applies.

Account export and deletion

Two account endpoints accept only a session token. They refuse API keys with 401, so a leaked key can't download everything or destroy the account. In the dashboard they are under Settings → Profile → Your data.

Export your data

GET /api/account/export

curl -s https://shippified.net/api/account/export \
  -H "Authorization: Bearer $SESSION_TOKEN" \
  -o shippified-export.json

Returns 200 with a JSON document (sent with Content-Disposition: attachment) containing exportedAt, account, settings, orders, emailSources, bots, customTemplates, subscriptions, shares, apiKeys, and intakeMessages (the stored source emails and webhook posts).

Secrets are stripped: no password hash or reset tokens, no mailbox password or OAuth tokens (email sources keep only the IMAP host, port, TLS flag and username, or the connected Gmail or Outlook address), no API key hashes (keys appear as they do in the key list), and no webhook signing secrets.

Delete your account

DELETE /api/account

Body field

Type

Required

Notes

confirmEmail

string

Yes

The account's email address. Compared case-insensitively after trimming.

curl -s -X DELETE https://shippified.net/api/account \
  -H "Authorization: Bearer $SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"confirmEmail":"[email protected]"}'

Returns 200 {"ok": true}. Deletion is immediate and permanent: the account and everything it owns (orders, sources, bots, templates, keys, webhook subscriptions, shares, logs) are removed, and every session and API key stops working. A missing or mismatched confirmEmail returns 400. For what happens to backups, see Account and privacy.

Credentials that are not bearer tokens

Some URLs carry their own credential because the sender cannot set headers:

  • Discord intake URLs (/api/webhooks/discord/:handle/:slug): the unguessable handle and slug in the URL act as the credential. Do not use an API key for these. See Getting orders in.

  • Forwarding inbox addresses (<slug>@shippified.net): the random slug in the address routes mail to your source.

  • Inbound mail worker (POST /api/inbound/mail): an operator-only shared key, sent in the x-shippified-inbound-key header or as ?key=. The endpoint returns 503 when the deployment has no key configured. See Getting orders in.

  • Outbound webhook signatures: Shippified signs what it sends you with a per-subscription whsec_… secret. See Webhooks.

Security checklist

  • Keep keys in environment variables or a secrets manager, never in source control. The sk_ prefix makes leaked keys easy to find with grep or a secret scanner.

  • Use a separate key for each integration so you can revoke one without breaking the others.

  • Check lastUsedAt in the key list to find keys you no longer use.

  • Do not ship API keys in browser or mobile client code. A key grants full workspace access.

For account-level settings such as password and privacy, see Account and privacy.

Was this page helpful?