Legal
Security
Last updated: 2026-04-22
Our model, in one sentence
We never touch raw card numbers; we delegate card data handling to Stripe (a PCI-DSS Level 1 service provider), we hash every secret we store ourselves, and we narrow the blast radius of every credential we issue so a compromise is recoverable.
What we don't store
- PAN, CVV, or expiration beyond masked form. Reveal is done client-side via Stripe's ephemeral-key mechanism; the full card number never transits our API.
- Plaintext API keys. We store only
sha-256(key)and a non-reversible 12-character prefix for recognition. - Plaintext magic-link tokens. Same treatment: only
sha-256(token)is persisted, with a hard 15-minute expiry and single-use consumption. - Passwords. We don't have passwords. Sign-in is magic-link only.
Transport and storage
- All traffic is HTTPS; HSTS is preloaded on our production domain.
- Database is managed PostgreSQL in a US region. The application connects via TLS; credentials are rotated on a schedule and are never in source control.
- Session cookies are
httpOnly,SameSite=Lax, andSecurein production. 30-day maximum lifetime.
API key controls
- Keys are scoped per user. An API key cannot access another user's cards, holds, or approvals.
- Revoking a key takes effect on the next request (sub-second propagation in practice).
- The full key is shown exactly once at creation. We cannot recover a lost key; you rotate and revoke.
- Rate limit: 1000 requests per hour per key (configurable upward on request).
- Every endpoint accepts an
Idempotency-Keyheader to de-duplicate retries.
Card-level controls
- Every card has a hard
spending_limitenforced by Stripe at authorization time. The limit cannot be exceeded even if our service is compromised. - Cards are single-use by default and self-expire after 7 days if unused (inherited from Stripe Issuing's single-use flow).
- Closing a card is instant; Stripe propagates the revocation to the card network within 1-5 seconds.
Webhook verification
- Every Stripe webhook is verified via
Stripe-Signatureand the signing secret. - Every event is recorded by Stripe event ID with a unique constraint; duplicate deliveries short-circuit.
- We never trust webhook payloads for authorization decisions we haven't independently validated.
Compliance posture
- We inherit PCI-DSS compliance from Stripe by never handling cardholder data ourselves.
- We are not a money transmitter because we never take custody of user funds in v0; money moves between your card and Stripe's Issuing balance.
- KYB data is collected per user at the level required by the issuing bank and card network.
- SOC2 Type II attestation is v1+ work, not in place for v0.
Reporting a vulnerability
If you believe you have found a security issue in AgentPay, please email [email protected]. Include steps to reproduce, the affected endpoint or surface, and the impact. We acknowledge within two business days and aim to remediate critical issues within 7 days.
Good-faith security research on test-mode accounts is welcome. Please do not:
- Test against accounts you do not own.
- Run automated scanners that generate high volumes of traffic.
- Publicly disclose findings before we have had a reasonable chance to respond.
Known limitations
Honest list of things we know about and are working on:
- No SOC2 attestation yet.
- No multi-factor authentication option for dashboard sign-in beyond magic-link.
- Rate-limit state is in-memory; a multi-process deployment would need Redis-backed counters (v1 work).
- No formal SLA in v0; test-mode only.