Product architecture

How VerifyPay works

A QR-to-pay flow with digital age verification, Stripe checkout, and real-time tablet confirmation — built for UK retail.

End-to-end payment flow

1. Scan QR

Customer scans QR on display unit.

2. Verify age

OIDC flow with OneID / Yoti.

3. Pay

Stripe Checkout — Card / Apple / Google Pay.

4. Webhook

Stripe confirms payment to backend.

5. Tablet

WebSocket pushes green confirmation.

System components

Customer device

  • — Camera (QR scan)
  • — PWA — no install
  • — OIDC redirect

VerifyPay backend

  • — Node.js API
  • — OIDC verifier
  • — Stripe webhook handler
  • — WebSocket gateway

Retail tablet

  • — Android display
  • — Persistent WebSocket
  • — Green / red screen

Identity provider

  • — OneID
  • — Yoti
  • — OIDC / OAuth2

Stripe

  • — Checkout session
  • — 3DS handling
  • — Apple / Google Pay

PostgreSQL

  • — Encrypted at rest
  • — 7-year audit log
  • — Hashed identifiers

Verification rules engine

Every transaction passes through a deterministic rules pipeline. Any failure short-circuits the flow.

age >= 18 (Challenge 25 enforced via document scan)

ID document not on revocation list

Liveness score >= 0.92

Outlet active and within trading hours

Stripe payment_intent.succeeded received within 60s

Customer hash not flagged in fraud register

Data model

Core entities. PII is hashed; only minimum required data is retained.

transactions

— id

— reference

— outlet_id

— product_id

— amount

— status

— stripe_session_id

— verification_id

— created_at

verifications

— id

— provider (oneid|yoti)

— customer_hash

— age_band

— liveness_score

— verified_at

— expires_at

outlets

— id

— name

— city

— tablet_id

— trading_hours

— active

audit_log

— id

— actor

— action

— entity

— payload_hash

— ip

— created_at

Security & compliance

TLS 1.3 only

PCI-DSS via Stripe

AES-256 at rest

Signed webhooks