Visual Architecture Diagrams
These diagrams show how UrbanPayX 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 UrbanPayX 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 │
└───────┘ └────────┘
| Status | Terminal? | What happened |
|---|---|---|
pending | No | Payment link created, waiting for user action |
processing | No | User started bank authorization |
succeeded | Yes | Bank confirmed the payment |
failed | Yes | Bank rejected the payment |
expired | Yes | Checkout window elapsed without completion |
cancelled | Yes | User abandoned the checkout flow |
KYC verification flow
UrbanPayX supports two verification modes. Choose based on whether you want UrbanPayX to handle identity checks or bring your own verification.
Mode A: UrbanPayX KYC
Your Backend UrbanPayX 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 UrbanPayX 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
UrbanPayX KYC mode:
[user created] ──► none ──► pending ──┬──► approved ✓
▲ │
│ └──► rejected
│ │
└───── reset (retry) ───┘
External attestation mode:
[user created] ──► pending ──┬──► verified ✓
│
└──► rejected
Payment eligibility
Before generating a payment link, UrbanPayX checks the user's verification status:
| Active mode | Payment-eligible status | Blocked statuses |
|---|---|---|
urbanpayx_kyc | kyc_status = approved | none, pending, rejected |
external_attestation | external_verification_status = verified | pending, rejected |
Authentication flow
UrbanPayX supports two authentication methods: API key (server-to-server) and email/password (dashboard).
API key authentication
Your Backend UrbanPayX
│ │
│ POST /auth/api-token │
│ {api_key, api_secret} │
│ ────────────────────────► │
│ │
│ {access_token, TTL: 2h} │
│ ◄──────────────────────── │
│ │
│ GET /transactions/{id} │
│ Authorization: Bearer │
│ {access_token} │
│ ────────────────────────► │
│ │
│ Transaction data │
│ ◄──────────────────────── │
│ │
│ ... 2 hours later ... │
│ │
│ POST /auth/api-token │
│ ────────────────────────► │
│ │
│ {new access_token} │
│ ◄──────────────────────── │
Email/password login with MFA
Dashboard User UrbanPayX
│ │
│ 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 auth | Email/password login | |
|---|---|---|
| Access token TTL | 2 hours | 30 minutes |
| Refresh token | Not issued | 30-day TTL, rotated on use |
| Role | Always operations | User's assigned role |
| MFA | Not applicable | Email OTP or TOTP |
| Best for | Server-to-server | Dashboard 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 UrbanPayX
│ │
│ ── 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
| Environment | Typical wait time |
|---|---|
| Sandbox | Minutes |
| Production | 3–5 business days |
In production, subscribe to the opco.status_changed webhook rather than polling.
Webhook delivery flow
When a business event occurs, UrbanPayX delivers a signed webhook to your endpoint with automatic retries.
UrbanPayX 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 ─────► │ │ │
│ └──────────────┘ │ │ │
│ │ UrbanPayX Platform │ │
│ ┌──────────────────────┐ │ │ │
│ │ Your Webhook │ ◄── Webhooks ──│ API Gateway │ │
│ │ Endpoint │ │ │ Background Workers│ │
│ └──────────────────────┘ │ │ │
│ └────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────┐
│ END USER │
│ │
│ ┌──────────┐ Hosted checkout ┌────────────────────────┐ │
│ │ Browser │ ────────────────► │ UrbanPayX Platform │ │
│ │ │ KYC verification │ │ │
│ └────┬─────┘ └────────────────────────┘ │
│ │ │
│ │ Bank auth │
│ ▼ │
│ ┌──────────┐ │
│ │ Bank App │ │
│ └──────────┘ │
└─────────────────────────────────────────────────────────────────────┘
Related guides
- Integration Tutorial — End-to-end tutorial with working code
- Webhook Event Catalog — Exact payload structures for every event type
- Transaction Lifecycle — Status transitions and error handling
- Authentication Guide — Token management and MFA setup
- KYC Verification Guide — Both verification modes explained
- Core Concepts — Domain model and entity relationships