Security & custody

A concrete description of how funds, keys, and data are handled. No marketing.

Custody model

Spawnpay uses custodial wallets on Base L2 (chainId 8453) and an internal ledger. Deposit addresses must come from the ledger service. This page does not establish signer isolation, multisig custody, or an automated sweep policy.

Your access credential is the spk_ bearer key. Keys are verified with constant-time HMAC/hash comparison and never logged in plaintext. Rotating a key via POST /api/key/rotate invalidates prior tokens immediately.

Treasury address (Base L2): 0xef1a2C2c83D159e99b1e8Fd2E941c88038050161 · public balance; not proof of customer revenue or reserve coverage.

Ledger correctness

All internal sub-cent settlements go through a Redis-locked ledger. Every credit/debit on a user account acquires lock:ledger:<userId> before mutating credit_balance, funded_balance, or related counters. The lock pattern uses Redis SETNX with an expiry — no two writes for the same user race, even across replicas.

// from packages/backend/src/ledger.js
const lock = await acquireLock(`lock:ledger:${userId}`);
try {
  // mutate balance + write tx row + write dedup marker
} finally {
  releaseLock(lock);
}

Idempotency keys are mandatory on send / proxy / scrape / screenshot. Same key within the same minute bucket returns the prior result instead of double-charging. Per-tool refunds on upstream failure roll the charge back to the caller's balance in the same locked critical section.

Auth surface

Panic mode

The backend ships with a PANIC_MODE env flag. When set, all paid endpoints return 503 immediately, no balance mutations, no upstream calls. Designed for the case where a vulnerability is suspected and the only safe action is to halt money movement. Reads (balance, deposits) stay available so users can see state.

Data retention

WhatWhereRetention
spk_ key (hash)SQLite (VPS)Indefinite while account active
Transaction rows (sends, charges, deposits)SQLite (VPS) + Base L2Indefinite
Proxy request bodyNOT storedDiscarded after upstream forward
Proxy response bodyNOT storedDiscarded after caller return
Caller IP for rate limitingRedis24h rolling window
Audit log of admin actionsSQLite (VPS)Indefinite

Known limits — what we do NOT claim

No formal SOC 2 / ISO 27001 audit. No 24/7 paging SLA. Single-region (US-east VPS + Vercel global edge). For regulated workloads where these matter, layer your own boundary or contact us for an enterprise discussion.
Custodial = trust trade-off. If the VPS master seed were compromised, balances tied to that seed would be exposed. Operationally we run minimum-access (single operator, audited shell history, no unattended SSH). But the trust assumption is the trust assumption — we recommend keeping working balances small ($1-$100) and topping up rather than parking large amounts.

Disclosure

Security disclosures: security@spawnpay.ai. Please include reproduction steps and affected endpoint; verified findings receive prompt remediation and public credit upon request.

READ THE FAQ → LIVE TELEMETRY → DOCS →