Architecture Diagrams

Visual Architecture Diagrams

These diagrams show how UrbanPay systems work together. Use them to understand the full lifecycle of payments, verification, authentication, and webhooks before you write a single line of code.


Payment flow

This is the complete journey from payment link creation to webhook confirmation.

  Your Backend                  UrbanPay                  Payer's Browser            Payer's Bank
       │                            │                            │                        │
       │  POST /checkout/paylink    │                            │                        │
       │ ────────────────────────►  │                            │                        │
       │                            │                            │                        │
       │  {transaction_id,          │                            │                        │
       │   checkout_url,            │                            │                        │
       │   status: pending}         │                            │                        │
       │  ◄──────────────────────── │                            │                        │
       │                            │                            │                        │
       │         Send checkout_url to payer                      │                        │
       │ ──────────────────────────────────────────────────────► │                        │
       │                            │                            │                        │
       │                            │    Open hosted checkout    │                        │
       │                            │  ◄──────────────────────── │                        │
       │                            │                            │                        │
       │                            │    Show bank selection     │                        │
       │                            │  ────────────────────────► │                        │
       │                            │                            │                        │
       │                            │                            │   Authorize payment    │
       │                            │                            │ ─────────────────────► │
       │                            │                            │                        │
       │                            │                            │   Payment confirmed    │
       │                            │  ◄──────────────────────────────────────────────────│
       │                            │                            │                        │
       │  Webhook:                  │                            │                        │
       │  payment.status_changed    │                            │                        │
       │  ◄──────────────────────── │                            │                        │
       │                            │                            │                        │
       ▼  Verify signature,         │                            │                        │
          fulfill order             │                            │                        │

Transaction status state machine

                          ┌──────────────────────┐
                          │                      │
    Payment link ──────►  │      pending         │
    created                │                      │
                          └──┬───────┬────────┬──┘
                             │       │        │
                Bank auth    │       │        │   TTL elapsed
                started      │       │        │   or user abandoned
                             ▼       │        ▼
                     ┌────────────┐  │  ┌──────────┐
                     │ processing │  │  │ expired / │
                     └──┬─────┬──┘  │  │ cancelled │
                        │     │     │  └───────────┘
              Bank      │     │     │
            confirmed   │     │  Bank rejected
                        ▼     ▼
                 ┌───────┐  ┌────────┐
                 │succeed│  │ failed │
                 └───────┘  └────────┘
StatusTerminal?What happened
pendingNoPayment link created, waiting for user action
processingNoUser started bank authorization
succeededYesBank confirmed the payment
failedYesBank rejected the payment
expiredYesCheckout window elapsed without completion
cancelledYesUser abandoned the checkout flow

KYC verification flow

UrbanPay supports two verification modes. Choose based on whether you want UrbanPay to handle identity checks or bring your own verification.

Mode A: UrbanPay KYC

  Your Backend                  UrbanPay                      User
       │                            │                           │
       │  POST /kyc/users           │                           │
       │ ────────────────────────►  │                           │
       │                            │                           │
       │  {user_id,                 │                           │
       │   kyc_status: none}        │                           │
       │  ◄──────────────────────── │                           │
       │                            │                           │
       │  POST /kyc/verify          │                           │
       │ ────────────────────────►  │                           │
       │                            │                           │
       │  {kyc_status: pending,     │                           │
       │   verification_url}        │                           │
       │  ◄──────────────────────── │                           │
       │                            │                           │
       │       Send verification_url to user                    │
       │ ─────────────────────────────────────────────────────► │
       │                            │                           │
       │                            │   Complete identity check │
       │                            │  ◄──────────────────────  │
       │                            │                           │
       │                            │   Review and verify       │
       │                            │   (internal)              │
       │                            │                           │
       │  Webhook:                  │                           │
       │  kyc.status_changed        │                           │
       │  ◄──────────────────────── │                           │
       │                            │                           │
       ▼  User now eligible         │                           │
          for payments              │                           │

Mode B: External attestation

  Your Backend                  UrbanPay               Your KYC Provider
       │                            │                        │
       │  POST /kyc/users           │                        │
       │ ────────────────────────►  │                        │
       │                            │                        │
       │  {user_id,                 │                        │
       │   status: pending}         │                        │
       │  ◄──────────────────────── │                        │
       │                            │                        │
       │  Run your own verification                          │
       │ ─────────────────────────────────────────────────►  │
       │                            │                        │
       │  Verification result       │                        │
       │  ◄───────────────────────────────────────────────── │
       │                            │                        │
       │  POST /kyc/external/       │                        │
       │  status/USER_ID          │                        │
       │ ────────────────────────►  │                        │
       │                            │                        │
       │  {status: verified}        │                        │
       │  ◄──────────────────────── │                        │
       │                            │                        │
       │  Webhook:                  │                        │
       │  kyc.status_changed        │                        │
       │  ◄──────────────────────── │                        │

KYC status state machines

UrbanPay KYC mode:

  [user created] ──► none ──► pending ──┬──► approved  ✓
                       ▲                │
                       │                └──► rejected
                       │                       │
                       └───── reset (retry) ───┘

External attestation mode:

  [user created] ──► pending ──┬──► verified  ✓
                               │
                               └──► rejected

Payment eligibility

Generating a payment link does not check the user's verification status — a link can be created regardless of kyc_status or external_verification_status. If your compliance policy requires a verified user before payment, check the status yourself (via GET /kyc/status/USER_ID, or the kyc.status_changed webhook) and gate the call in your own application.


Authentication flow

UrbanPay supports two authentication methods: API key (server-to-server) and email/password (dashboard).

API key authentication

  Your Backend                  UrbanPay
       │                            │
       │  POST /auth/api-token      │
       │  {api_key, api_secret}     │
       │ ────────────────────────►  │
       │                            │
       │  {access_token, TTL: 2h}   │
       │  ◄──────────────────────── │
       │                            │
       │  GET /transactions/{id}    │
       │  Authorization: Bearer     │
       │  {access_token}            │
       │ ────────────────────────►  │
       │                            │
       │  Transaction data          │
       │  ◄──────────────────────── │
       │                            │
       │    ... 7 days later  ...   │
       │                            │
       │  POST /auth/api-token      │
       │ ────────────────────────►  │
       │                            │
       │  {new access_token}        │
       │  ◄──────────────────────── │

Email/password login with MFA

  Dashboard User                UrbanPay
       │                            │
       │  POST /auth/login          │
       │  {email, password}         │
       │ ────────────────────────►  │
       │                            │
       │         ┌──────────────────┤
       │         │ Verify password  │
       │         └──────────────────┤
       │                            │
       ├─── If MFA NOT required ────┤
       │                            │
       │  {access_token,            │
       │   refresh_token}           │
       │  ◄──────────────────────── │
       │                            │
       ├─── If MFA required ────────┤
       │                            │
       │  {otp_pending,             │
       │   challenge_token}         │
       │  ◄──────────────────────── │
       │                            │
       │  POST /auth/login/         │
       │  verify-otp                │
       │  {otp_code,                │
       │   challenge_token}         │
       │ ────────────────────────►  │
       │                            │
       │  {access_token,            │
       │   refresh_token}           │
       │  ◄──────────────────────── │
       │                            │
       ├─── Token refresh ──────────┤
       │                            │
       │  POST /auth/refresh        │
       │  {refresh_token}           │
       │ ────────────────────────►  │
       │                            │
       │  {new access_token,        │
       │   new refresh_token}       │
       │  ◄──────────────────────── │

Token comparison

API key authEmail/password login
Access token TTL7 days30 minutes
Refresh tokenNot issued30-day TTL, rotated on use
RoleSet per API credential (owner/operations/developer/custom)User's assigned role
MFANot applicableEmail OTP or TOTP
Best forServer-to-serverDashboard and admin

OpCo lifecycle

Operating Companies (OpCos) represent the regulated entities that process payments. Every OpCo must be registered and activated before it can process transactions.

  Your Backend                  UrbanPay
       │                            │
       │  ── Phase 1: Create ────── │
       │                            │
       │  POST /opcos/create        │
       │ ────────────────────────►  │
       │                            │
       │  {opco_id,                 │
       │   status: draft}           │
       │  ◄──────────────────────── │
       │                            │
       │  PATCH /opcos/{id}         │
       │  (optional edits)          │
       │ ────────────────────────►  │
       │                            │
       │  ── Phase 2: Submit ────── │
       │                            │
       │  PATCH /opcos/{id}/submit  │
       │ ────────────────────────►  │
       │                            │
       │  {status:                  │
       │   awaiting_approval}       │
       │  ◄──────────────────────── │
       │                            │
       │  ── Phase 3: Approval ──── │
       │                            │
       │         ┌──────────────────┤
       │         │ Upstream         │
       │         │ registration     │
       │         │ + polling        │
       │         └──────────────────┤
       │                            │
       │  Webhook:                  │
       │  opco.status_changed       │
       │  {status: activated}       │
       │  ◄──────────────────────── │
       │                            │
       ▼  OpCo ready for payments   │

OpCo status state machine

  POST /opcos/create
         │
         ▼
      ┌───────┐     Submit     ┌───────────────────┐    Approved    ┌───────────┐
      │ draft │ ─────────────► │ awaiting_approval │ ─────────────► │ activated │
      └───────┘                └───────────────────┘                └─────┬─────┘
                                        │                                 │
                                        │ Rejected                        │ Admin action
                                        ▼                                 ▼
                                  ┌──────────┐                     ┌─────────────┐
                                  │ rejected │                     │ deactivated │
                                  └──────────┘                     └─────────────┘

Approval timeline

EnvironmentTypical wait time
SandboxMinutes
Production3–5 business days

In production, subscribe to the opco.status_changed webhook rather than polling.


Webhook delivery flow

When a business event occurs, UrbanPay delivers a signed webhook to your endpoint with automatic retries.

  UrbanPay                      Your Endpoint
       │                            │
       │  Event occurs              │
       │  (e.g. payment succeeded)  │
       │                            │
       │  POST {your_webhook_url}   │
       │  Signed: HMAC-SHA256       │
       │ ────────────────────────►  │
       │                            │
       ├─── If 2xx response ────────┤
       │                            │
       │  200 OK                    │
       │  ◄──────────────────────── │
       │  ✓ Delivered               │
       │                            │
       ├─── If non-2xx / timeout ───┤
       │                            │
       │  500 / timeout             │
       │  ◄──────────────────────── │
       │                            │
       │  Retry with exponential    │
       │  backoff (up to 8 times)   │
       │ ────────────────────────►  │

Webhook event lifecycle

                           ┌─────────────────────┐
  Event created ─────────► │      PENDING        │ ◄─── Retry (non-2xx)
                           └──┬──────────────┬───┘        │
                              │              │             │
                        2xx   │              │  Max        │
                     response │              │ attempts    │
                              ▼              ▼             │
                       ┌───────────┐  ┌─────────────┐     │
                       │ DELIVERED │  │ DEAD_LETTER │     │
                       └───────────┘  └─────────────┘     │

Your handler checklist

  1. Receive POST request
         │
         ▼
  2. Verify HMAC-SHA256 signature
         │
    ┌────┴────┐
    │ Invalid │ ──► Return 401
    └────┬────┘
         │ Valid
         ▼
  3. Check timestamp freshness (< 5 min)
         │
    ┌────┴────┐
    │  Stale  │ ──► Return 401
    └────┬────┘
         │ Fresh
         ▼
  4. Check event ID for duplicates
         │
    ┌────┴──────┐
    │ Duplicate │ ──► Return 200 (skip processing)
    └────┬──────┘
         │ New
         ▼
  5. Process the event
         │
         ▼
  6. Store event ID (for dedup)
         │
         ▼
  7. Return 200

System overview

  ┌─────────────────────────────────────────────────────────────────────┐
  │                       YOUR INFRASTRUCTURE                          │
  │                                                                    │
  │   ┌──────────────┐                    ┌────────────────────────┐   │
  │   │ Your Backend │ ── REST API ─────► │                        │   │
  │   └──────────────┘                    │                        │   │
  │                                       │   UrbanPay Platform    │   │
  │   ┌──────────────────────┐            │                        │   │
  │   │ Your Webhook         │ ◄── Webhooks ──│  API Gateway       │   │
  │   │ Endpoint             │            │   │  Background Workers│   │
  │   └──────────────────────┘            │                        │   │
  │                                       └────────────────────────┘   │
  └─────────────────────────────────────────────────────────────────────┘

  ┌─────────────────────────────────────────────────────────────────────┐
  │                          END USER                                   │
  │                                                                    │
  │   ┌──────────┐  Hosted checkout   ┌────────────────────────┐       │
  │   │ Browser  │ ────────────────►  │   UrbanPay Platform    │       │
  │   │          │  KYC verification  │                        │       │
  │   └────┬─────┘                    └────────────────────────┘       │
  │        │                                                           │
  │        │  Bank auth                                                │
  │        ▼                                                           │
  │   ┌──────────┐                                                     │
  │   │ Bank App │                                                     │
  │   └──────────┘                                                     │
  └─────────────────────────────────────────────────────────────────────┘

Related guides