Surfil

Errors

The edge API returns conventional HTTP status codes with a JSON body. Two are worth understanding in depth, because they encode Surfil's safety guarantees: a 402 never writes, and a 503 fails closed.

Status codes

  • 400 - bad request: invalid id or malformed JSON.
  • 401 - missing or invalid credential (device token or Supabase session).
  • 402 - insufficient credits on meter/consume. Zero writes - the balance is untouched, so a retry after topping up is safe.
  • 404 - not found, or not yours: another tenant's resource is an indistinguishable 404 by design.
  • 405 - method not allowed on that path.
  • 503 - fail-closed: signing is unavailable, so no decrement or receipt is produced. Retry with the same idempotency key is safe.

Idempotency and safe retries

Every state-mutating request carries an idempotency key. A retry with the same key replays the stored result rather than repeating the effect - a duplicated consume never double-charges. This is why a 503 mid-operation is recoverable: retrying finishes the exact operation once, never twice.

Crypto outcomes are data, not errors

POST /v1/verify returns 200 even when a signature is invalid - the verification result (valid / tampered) is data in the body, not a transport error. A bad signature is an answer, not a failure to answer.

CLI exit codes mirror these semantics and are finalized in surfil <command> --help. See the CLI reference.