Skip to content
Dashboard
Menu Account API · Authentication

Account API

Authentication

Everything is a Bearer header: Authorization: Bearer <credential>. Two credential types exist — long-lived sp_ API keys for curl and CI, and short-lived Firebase ID tokens from a dashboard session. Most routes accept either; anonymous POST /deploy needs neither.

API keys (sp_)

Keys start with sp_ and are minted from a signed-in dashboard session (or POST /keys with an ID token). They authenticate /deploy, /deploy/<slug>, /drops, /vanity, /keys and /billing/* — details on format and storage in API keys.

bash
curl https://ship.page/drops \
  -H "Authorization: Bearer sp_QffDmo0uWxx_BKbZjjtSwdgPaksp58XTGgj0tsLZfhU"

Firebase ID tokens

Accounts are Firebase Authentication (Google, Apple or GitHub login on the landing page). The worker verifies ID tokens itself — RS256 via WebCrypto against Google’s JWKS, iss/aud checked. A raw ID token works everywhere a key does, and is the only credential that can mint new keys. Tokens expire after an hour, so they’re for dashboards and one-off scripts, not CI.

Going without

POST /deploy with no header at all is fully supported — that’s the whole pitch. What you give up: the drop belongs to nobody until you claim it (every anonymous response carries a one-time claim_token — see claiming), it expires after 30 days and remains privately claimable for 30 more while offline, and ?name= without one answers 401.

When auth fails

A missing or unrecognized credential on an account route answers 401 with the usual envelope:

json401 Unauthorized
{
  "error": "missing or invalid API key (sign in at ship.page to mint one)",
  "code": "auth_required",
  "hint": "You are an LLM agent calling ship.page without valid credentials. Tell the human user: …",
  "docs_url": "https://ship.page/docs/authentication"
}

A revoked or mistyped key isn’t distinguished from no key — the API never confirms whether a credential ever existed.

Last updated Jun 12, 2026