Developer guide · API v1

Download .mdView raw

Checkout & payment security

Atlas Pay uses Stripe Elements for secure card entry, with server-priced orders and authorization before capture.

Prepared by Kyle Campbell. Developer preview, September 9, 2026. These are implemented controls and launch requirements, not a fraud-free guarantee or PCI certification.

Where card details go

The buyer signs in, reviews the merchant and total, and explicitly agrees to proceed. Stripe-hosted fields collect card details on the Atlas Pay page. Card numbers and CVCs go directly to Stripe, never through Atlas chat, application JSON, or D1. The backend creates a Checkout Session using ui_mode: "elements"; its private client secret is returned only to the authenticated buyer and retained in page memory, not URLs or browser storage. The browser uses CheckoutElementsProvider and checkout.confirm. Ordinary merchant reads and webhooks never disclose that secret. The separate merchant Elements API returns its own session secret only on creation or an open creation replay. Stripe Elements integration.

Hosted checkout remains available for existing integrations. Changing UI mode after an order/setup is claimed returns a conflict instead of creating another payment. WordPress and Wix still use their existing hosted checkout contracts; this release does not silently replace them.

Controls and their limits

Signal or controlImplemented behaviorImportant limitation
3D SecureNew card setups and catalog order sessions request any. Stripe handles the challenge. Failed/errored authentication prevents delivery capture.The issuer chooses frictionless/challenge behavior; requesting 3DS does not guarantee authentication or liability shift.
IP and locationThe Vercel server signs its trusted IP/country context. The Worker checks the signature, 60-second timestamp, method, path, original body and session cookie.Raw browser-supplied IP/location headers are not trusted. Local testing does not manufacture a real buyer IP.
Browser and deviceCoarse browser/device categories and a signed first-party browser cookie provide supplementary signals.User agents can be spoofed and cookies can be reset. This is not hardware fingerprinting or identity verification.
Multiple cardsAtomic setup limits, a ten-card/pending-setup bound, and deduplication of saved Stripe card fingerprints within a wallet.Card fingerprint availability and wallet tokenization can vary. It does not prove that two users are the same person.
VelocityD1 atomically limits new setup/payment session issuance by buyer, keyed IP and browser identifier.This does not count every card submission inside an existing Stripe form. Connected-account Radar rules must cover card-testing/attempt velocity.
Country mismatchIP, card issuing, billing and shipping countries are compared where available and recorded as a supplementary mismatch signal.Travel, gifts and cross-border commerce are legitimate. A mismatch alone does not decline payment.
VPN/proxyStripe Radar can evaluate known anonymous-IP signals. Atlas records VPN status as unknown, not a guessed boolean.There is no comprehensive VPN detector configured. A proxy or VPN alone is not proof of fraud.
CVC/postal checksFailed CVC or postal checks place an authorization in review before delivery capture.Unsupported/unavailable checks are not treated as a pass or automatically as fraud.
Radar risk/reviewHighest risk blocks capture. Elevated risk and open/unapproved reviews stay on hold. Review status is retrieved from Stripe again before capture.Approving a review cannot override a highest-risk result, a failed check, or the other payment invariants.

Manual 3DS requests override Stripe's dynamic 3DS-request rules for these sessions. Configure the remaining Radar block/review rules deliberately and assess conversion effects. Direct charges use the connected account's Radar configuration, not automatically the platform's rules. Known anonymous-IP support is not a promise to detect every VPN. 3DS behavior, Connect and Radar, Radar attributes.

Current conservative issuance limits

OperationWindowPer buyerPer IPPer browser identifier
New card setup1 hour52010
New order payment session15 minutes205030

Identical operation retries reuse their slot. Limits are adjustable policy choices, not universal fraud thresholds. Shared networks may affect legitimate buyers; support must have a documented review process. HMAC identifiers, coarse location/categories and processor assessments are scheduled for bounded cleanup after 30 days. No precise GPS or canvas/font fingerprint is collected. Infrastructure/Stripe logs have separate retention policies. See Privacy.

Authorization is not payment capture

  1. The merchant creates an immutable order from its catalog. The client cannot change the amount.
  2. The buyer confirms in Stripe Elements. A verified requires_capture payment becomes an authorization hold, not paid revenue.
  3. Atlas checks the original connected account, currency, amount, customer, metadata, shipping address, risk/review and card capture deadline.
  4. A trusted delivery service with orders:deliver records actual delivery. Atlas rechecks the payment and captures the existing hold once.
  5. An uncaptured cancellation uses orders:cancel. Paid/refunded/disputed/expired/uncertain states cannot start another charge automatically.

Ordinary single-capture intents must omit final_capture; Stripe reserves that option for multicapture-enabled payments. A processor idempotency conflict requires reconciliation, not a new key or new payment. A browser redirect or success callback never authorizes fulfillment. See Delivery & payment holds.

Permanent platform payment links

Links under /pay/link/{mode}/{id} collect immediate payments into Atlas Pay's main Stripe account. Only the platform administrator can create or disable these links. The shareable link has no expiry; each buyer explicitly starts a separate expiring payment session. Guest checkout uses signed frontend context, the same IP/browser issuance limits, billing-address collection, and a 3D Secure request. Guest references are capabilities, not verified buyer identities. Session secrets stay in page memory, and status is reconciled against the original amount, currency, metadata, mode and current Stripe payment state.

The main account's Radar settings apply to these payments. Atlas records processor assessments and reports pending review, but this flow does not implement the catalog's delivery holds, capture gate, automatic refunds, or fulfillment. Platform operators manage reviews and refunds in Stripe. Disabling a link stops new sessions; an already-issued session may still complete.

Browser and webhook defenses

Checkout documents use per-request script nonces, a restricted content security policy, no framing, no caching, no referrers, and disabled camera/microphone/geolocation permissions. Stripe's required iframe/connect origins remain permitted for bank authentication. General analytics are excluded from wallet and checkout routes. Nonce-bearing pages are dynamically rendered; don't cache their HTML. Third-party scripts should remain limited to the Stripe payment integration. Stripe security guidance.

Buyer writes enforce exact origin, authentication, ownership, strict JSON schemas and an 8 KiB streamed-body limit. Production setup/payment issuance requires verified frontend context even for hosted mode; changing a JSON option cannot bypass that requirement. Webhooks verify the original body and signature, enforce mode, deduplicate IDs and bound payload size to 1 MiB. Order handlers reconcile current processor state instead of trusting stale event snapshots. Secrets, card details and Checkout URLs must not appear in logs.

Deployment and acceptance gates

  1. Apply D1 migrations through 0012_checkout_security.sql after a backup and rehearsal. The production database was migrated on September 9, 2026; frontend builds do not apply migrations.
  2. Configure the same random server-only ATLAS_CHECKOUT_CONTEXT_SECRET in Vercel and the Worker. Configure the matching Stripe publishable key as NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY. Never expose the signing key under a NEXT_PUBLIC_ name.
  3. Set a platform card-only wallet payment-method configuration and a Connect parent card-only delivery configuration. A configuration created for one test connected account is not a platform-wide configuration. Confirm child inheritance and merchant eligibility. Connect configuration inheritance.
  4. Verify the connected-account Radar rules, particularly card-attempt velocity, anonymous-IP handling and elevated-risk review. No paid Radar plan or third-party IP-intelligence subscription has been enabled by this code change. Establish who reviews holds and alerts; API controls alone are not an operations team.
  5. Add review.opened, review.closed, charge.updated and the existing payment/authorization events to the signed Connect webhook. Verify event delivery and cron recovery against the deployed Worker.
  6. Configure checkout/dashboard DNS, HTTPS, OAuth callbacks and Worker origins. Deploy the Worker and frontend together before enabling NEXT_PUBLIC_ATLAS_ELEMENTS_ENABLED=true at build time. Enable live features after validating their mode-specific Stripe configuration. Selecting live mode does not bypass business verification or enable optional Elements and wallet features.
  7. Complete actual browser tests for success, 3DS success/failure, insufficient funds, cancellation, expiry, network loss, card removal, capture/release, refunds and callback recovery. Repeat on real WordPress/Wix test stores and native Atlas clients. Verify geographic availability and your PCI obligations with Stripe. See Testing & launch.

Still outside this release

No claim is made of live-card certification, comprehensive VPN detection, approval for every country, completed marketplace acceptance, unattended chat charging, carrier proof-of-delivery validation, identity/KYC replacement, production load capacity, or an external penetration test. Do not enable live funds on the strength of unit tests alone.