Authentication
- Written for
- + Written for
- Deprecated
- + Deprecated
- Applies to
- + Applies to
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 |
| Until revoked |
| Scripts, servers, the SDK, the MCP server |
Session token | 64 hexadecimal characters | 14 days from creation, not extended by use |
| 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.
lastUsedAtis 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 |
|---|---|---|---|
| string | No | A label for the key. Trimmed and truncated to 80 characters. Defaults to |
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:
Create a new key.
Deploy the new key everywhere the old one is used.
Revoke the old key.
Session tokens
Session tokens are what the dashboard uses. You get one from:
Endpoint | Body | Success |
|---|---|---|
|
|
|
|
|
|
When the deployment has Cloudflare Turnstile configured,
turnstileTokenis required. A missing or invalid value returns400.Both endpoints are rate-limited to 10 requests per minute per client IP. Over the limit returns
429withRetry-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 |
|
|
API key limit reached (25) |
|
|
API key used for account export or deletion |
|
|
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.jsonReturns 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 |
|---|---|---|---|
| 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 thex-shippified-inbound-keyheader or as?key=. The endpoint returns503when 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 withgrepor a secret scanner.Use a separate key for each integration so you can revoke one without breaking the others.
Check
lastUsedAtin 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.