Skip to main content

Architecture

AccruPay is a payment router. It sits between your application and payment providers — your backend starts and verifies sessions through AccruPay, while your frontend submits card data directly to the provider through the React SDK. Your server never handles raw card numbers.

Request flow

Your Backend AccruPay Provider
│ │ │
│──(1) start session──────▶│ │
│◀─────── session.id ──────│ │
│ │ │
│──(2) session.id ──▶ Your Frontend │
│ │ │
│ Your Frontend │
│ │────(3) card data + session ──▶│
│ │◀────── provider result ───────│
│ │ │
│──(4) verify(session.id)─▶│ │
│◀────── transaction ──────│ │
│ │ │

Step-by-step

StepActorAction
1Your backendCalls clientSessions.payments.start() with transaction details. AccruPay creates a session and returns session.id.
2Your backendPasses session.id to your frontend (e.g., as part of a checkout API response).
3React SDKCustomer fills card fields and submits. The SDK sends card data directly to the provider. Your server is never in this path.
4Your backendCalls clientSessions.payments.verify() with session.id. AccruPay returns the authoritative transaction result.

Server / client boundary

ResponsibilityRuns on
Start sessionBackend — requires apiSecret
Store apiSecretBackend only — never expose to frontend
Render payment fieldsFrontend — React SDK
Submit card dataFrontend → Provider — React SDK sends directly
Verify resultBackendverify() is the source of truth

Your frontend only needs two public values: merchantPublicId (static, safe to embed) and session.id (per-transaction, scoped, expires).

PCI scope

Card data follows this path:

Browser (React SDK fields) ──▶ Provider SDK ──▶ Provider

Your server is never in the card data path. AccruPay itself does not receive or store raw card numbers. This architecture keeps your integration out of PCI DSS scope for card data handling — your server only exchanges session identifiers and transaction metadata.

note

AccruPay's hosted field components render inside provider-controlled iframes or secure input contexts, depending on the provider. Raw card values are never accessible to your JavaScript.

Verify is the source of truth

verify() is the only signal you should trust for transaction outcome. Do not use the frontend callback as a confirmation trigger.

Why the frontend callback is unreliable:

  • The customer's browser may close, navigate away, or lose connectivity after the provider processes the payment but before your callback fires.
  • Network errors between the provider and your callback handler can silently drop success events.
  • Malicious clients can forge or replay callback payloads.

What happens if you trust the frontend callback instead:

  • Missed payments: Provider charges succeed; your system records nothing. Customer is charged but no order is created.
  • Double charges: You retry a start() on each callback failure, creating multiple sessions against the same intended purchase.
  • Fulfillment without payment: A forged callback triggers order fulfillment before payment is confirmed.

Correct pattern:

frontend callback fires (informational only)


backend calls verify()


act on transaction.status from verify()

Call verify() from your backend after the frontend signals completion. Build your fulfillment, confirmation email, and inventory updates on the verify() result — not on anything that arrived through the browser.

Next steps