# PRD: UPI Dynamic (Dynamic QR Processing)

**Version**: 1.0  
**Date**: 2026-06-12  
**Status**: Active  

---

## 1. Executive Summary

**UPI Dynamic** handles all dynamic QR code payments where merchants generate unique QR codes on-the-fly for each transaction. It provides real-time QR validation, payment processing, and supports merchant timeout scenarios. Dynamic QRs have 30-minute validity and 8000 INR amount limit per NPCI regulations.

---

## 2. Product Overview

### 2.1 Purpose
- **Dynamic QR Generation**: Create unique QR per transaction
- **Real-time Validation**: Validate QR payload in real-time
- **Payment Processing**: Handle ReqPay for dynamic QRs
- **Timeout Simulation**: Support merchant timeout scenarios
- **30-minute Validity**: Enforce strict expiry windows
- **Amount Limits**: Enforce 8000 INR per-transaction limit
- **High Throughput**: Support millions of daily dynamic QRs
- **Merchant Integration**: Integrate with merchant systems

### 2.2 Key Users
- **Merchants**: Generate QRs on POS/app
- **Customers**: Scan QR to initiate payment
- **Acquirers**: Process resulting payments
- **Support Teams**: Monitor QR generation

---

## 3. Core Features

### 3.1 Dynamic QR Generation
- **Unique Per Transaction**: Each payment gets distinct QR
- **Real-time Creation**: Generate within milliseconds
- **Payload Structure**: Include merchant, amount, MCC, timestamp
- **Base64 Encoding**: Encode QR data for NPCI
- **Transaction Linking**: Link to transaction record
- **Merchant Details**: Include merchant VPA, category
- **Amount Included**: Encode payment amount in QR

### 3.2 ReqValQr Processing (Dynamic)
- **22-Step Flow**: Complete validation pipeline
- **XML Parsing**: Parse NPCI ReqValQr request
- **Dynamic Detection**: Identify as initiation_mode=16
- **Verification Token**: Generate UUID per validation
- **PE Expiry Check**: Detect if QR has expired (optional)
- **Merchant Lookup**: Find merchant by payee VPA
- **Amount Validation**: Check against 8000 INR limit
- **Timeout Simulation**: Handle gourmet@mercury timeouts
- **Event Creation**: Create initial event chain
- **Async Processing**: Spawn background task

### 3.3 ReqPay Processing (Dynamic)
- **19-Step Flow**: Payment processing pipeline
- **Token Validation**: Verify token from ReqValQr
- **Timeout Handling**: 30-second timeout for gourmet@mercury
- **Amount Checks**: Validate against 8000 INR limit (X7 error)
- **Merchant Validation**: YH error for invalid merchants
- **Status Tracking**: SUCCESS/FAILED/REVERSAL
- **Settlement Calculation**: Calculate fees

### 3.4 Timeout Scenarios
- **Timeout VPA**: gourmet@mercury (merchant identifier)
- **Timeout Duration**: 30 seconds (simulated processing delay)
- **Timeout Error**: Generic timeout response
- **Reversal Support**: Automatic reversal after timeout
- **Recovery**: Customer can retry payment

### 3.5 Error Handling - Dynamic Specific
- **X7 Error**: Amount exceeds 8000 INR
- **YH Error**: Merchant signature/encryption failure
- **PE Error**: Dynamic QR expired (>30 minutes)
- **ZE Error**: Invalid verification token
- **ZD Error**: Duplicate message ID
- **ZF Error**: Verification/signature failed
- **IP05/08/10**: Acquirer-specific scenarios

### 3.6 HTTP API Endpoints
- **POST /api/v1/dynamic-qr/validate**: ReqValQr handler
- **POST /api/v1/dynamic-qr/pay**: ReqPay handler
- **POST /api/v1/dynamic-qr/check**: ReqChkTxn handler
- **GET /api/v1/dynamic-qr/:id**: View QR details
- **GET /api/v1/dynamic-qr/:id/status**: Get payment status

---

## 4. Database Schema

### 4.1 Key Tables
| Table | Purpose | Org ID |
|-------|---------|--------|
| qr_validations | Dynamic QR validation | MER101 |
| req_pays | Dynamic payments | MER101 |
| transactions | Payment records | MER101 |
| static_qrs | Not used | N/A |
| qr_validation_events | Event chain | MER101 |
| transaction_events | Event chain | MER101 |

### 4.2 QRValidation for Dynamic
```
org_id: MER101 (always for dynamic)
initiation_mode: 16
qr_medium: DYNAMIC
ver_token: UUID generated per validation
qr_expires_at: current_time + 30 minutes
validation_type: DOMESTIC or INTERNATIONAL
base_amount: 1-8000 INR (domestic) or in base currency (intl)
inr_amount_calc: final INR amount after FX
```

### 4.3 ReqPay for Dynamic
```
org_id: MER101
amount: 1-8000 INR
status: SUCCESS/FAILED/PENDING/REVERSED
settlement_amount: calculated after fees
```

---

## 5. Processing Flow

### 5.1 ReqValQr Flow (22 Steps)
1. Receive HTTP POST from NPCI
2. Parse XML payload
3. Extract message ID, merchant, amount
4. Detect initiation_mode = 16 → Dynamic QR
5. Validate XML schema
6. Optional: Check PE (payment expired)
7. Determine validation_type (DOMESTIC or INTERNATIONAL)
8. Lookup merchant by payee VPA
9. Validate merchant is active
10. For dynamic: Check amount ≤ 8000 INR (X7 if exceeds)
11. For international: Fetch FX rate + convert to INR
12. Generate verification token (UUID)
13. Calculate qr_expires_at = now + 30 min
14. Create QRValidation record
15. Create initial event in qr_validation_events
16. Compute XML hashes (SHA256)
17. Store hashes for audit trail
18. Build RespValQr with token and timestamp
19. Add special handling for timeout VPA (gourmet@mercury)
20. Send ACK response immediately (status 00)
21. Spawn async Task for additional processing
22. Return RespValQr to NPCI

### 5.2 ReqPay Flow (19 Steps)
1. Receive HTTP POST from NPCI
2. Parse XML payload
3. Extract message ID (msg_id) and txn_id
4. Check idempotency: msg_id must be unique (ZD error if duplicate)
5. Lookup verification token from ReqValQr
6. Validate token exists (ZE error if missing)
7. Validate token not expired (PE error if expired)
8. Verify token hasn't been used before (ZD error if already used)
9. Extract payer/payee addresses
10. Verify amount matches original quote
11. Verify currency matches
12. Validate merchant status
13. For gourmet@mercury: Simulate 30-second timeout
14. For X7 scenario: Check if amount > 8000 → X7 error, settlement_amount=0
15. For YH scenario: Merchant signature validation fails
16. If all valid: Update transaction status to SUCCESS
17. Calculate settlement_amount with fees
18. Append event to transaction_events chain
19. Send RespPay with status to NPCI

### 5.3 Timeout Scenario Flow
1. Check if payee_addr == gourmet@mercury
2. If yes: Simulate 30-second processing delay
3. Return timeout response to customer
4. Optionally trigger automatic reversal
5. Allow customer to retry payment

---

## 6. Error Scenarios

### 6.1 Validation Phase Errors
| Scenario | Error Code | Cause | Response |
|----------|-----------|-------|----------|
| S1 | 00 | Normal success | RespValQr with token |
| S2 | PE | QR expired (>30 min) | Payment expired error |
| S3 | X7 | Amount > 8000 INR | Amount exceeds limit |
| S4 | YH | Merchant validation failed | Merchant error |
| S5 | ZE | Invalid token | Token not found |
| S6 | ZD | Duplicate msg_id | Duplicate transaction |
| S7 | ZF | Verification failed | Signature invalid |
| S8 | ZQ | QR not found | QR lookup failure |
| S9 | ZR | Merchant not found | Merchant lookup failure |
| S10 | 96 | System error | HTTP 500 |

### 6.2 Payment Phase Errors
| Scenario | Error Code | Amount | Settlement |
|----------|-----------|--------|-----------|
| S1 | 00 | 1000 INR | 1000 INR |
| S2 | 00 | Timeout (gourmet@mercury) | 0 INR (timeout) |
| S3 | 00 | Reversal | 0 INR (reversed) |
| S4 | X7 | 9000 INR | 0 INR (exceeds limit) |
| S5 | YH | 5000 INR | 0 INR (merchant error) |
| S6 | ZE | Any | Invalid token |
| S7 | ZD | Any | Duplicate |
| S8 | ZF | Any | Signature failed |
| S9 | IP05 | Any | Acquirer error |
| S10 | 96 | Any | System error |

---

## 7. Configuration

### 7.1 Dynamic-Specific Settings
```elixir
# Dynamic QR Configuration
DYNAMIC_QR_EXPIRY_MINUTES=30
DYNAMIC_QR_LIMIT_INR=8000
TIMEOUT_DURATION_SECONDS=30
TIMEOUT_VPA=gourmet@mercury

# Routing
DYNAMIC_ORG_ID=MER101
DYNAMIC_NET_INST_ID=MER1010001
DYNAMIC_INITIATION_MODE=16

# Settlement
DYNAMIC_X7_SETTLEMENT=0
DYNAMIC_YH_SETTLEMENT=0
```

### 7.2 Feature Flags
```elixir
feature_flag(:dynamic_qr_timeout_enabled, true)
feature_flag(:dynamic_qr_async_processing, true)
feature_flag(:dynamic_qr_merchant_timeout, true)
```

---

## 8. API Examples

### 8.1 ReqValQr Request
```xml
POST /api/v1/dynamic-qr/validate
<ReqValQr>
  <MsgID>MSG1234567890</MsgID>
  <Ts>2026-06-12T10:30:00Z</Ts>
  <OrgID>MER101</OrgID>
  <Curr>INR</Curr>
  <Amount>1000.00</Amount>
  <Mcc>5411</Mcc>
  <RefUrl>aW5pdGlhdGlvbl9tb2RlPTE2</RefUrl>
  <Signature>...</Signature>
</ReqValQr>
```

### 8.2 RespValQr Response (Success)
```xml
<RespValQr>
  <MsgID>MSG1234567890</MsgID>
  <Status>00</Status>
  <VerToken>550e8400-e29b-41d4-a716-446655440000</VerToken>
  <ExpiresAt>2026-06-12T11:00:00Z</ExpiresAt>
  <Ts>2026-06-12T10:30:00Z</Ts>
</RespValQr>
```

### 8.3 ReqPay Request
```xml
POST /api/v1/dynamic-qr/pay
<ReqPay>
  <MsgID>PAY9876543210</MsgID>
  <TxnID>TXN1234567890</TxnID>
  <VerToken>550e8400-e29b-41d4-a716-446655440000</VerToken>
  <Amount>1000.00</Amount>
  <Curr>INR</Curr>
  <PayerAddr>customer@upi</PayerAddr>
  <PayeeAddr>merchant@upi</PayeeAddr>
  <Timestamp>2026-06-12T10:35:00Z</Timestamp>
</ReqPay>
```

### 8.4 RespPay Response (Success)
```xml
<RespPay>
  <MsgID>PAY9876543210</MsgID>
  <Status>00</Status>
  <TxnID>TXN1234567890</TxnID>
  <SettlementAmount>995.00</SettlementAmount>
  <Timestamp>2026-06-12T10:35:05Z</Timestamp>
</RespPay>
```

---

## 9. Dependencies

- **phoenix**: Web framework
- **ecto_sql**: Database layer
- **myxql**: MySQL driver
- **req**: HTTP client for NPCI callbacks
- **sweet_xml**: XML parsing
- **uuid**: Token generation
- **timex**: DateTime handling
- **decimal**: Precise amount calculations

---

## 10. Performance Requirements

| Metric | Target | SLA |
|--------|--------|-----|
| ReqValQr Response | < 100ms | 99.9% |
| ReqPay Response | < 150ms | 99.9% |
| QR Expiry Check | Real-time | N/A |
| Throughput | 10,000 TPS | N/A |
| Availability | 99.95% | SLA |

---

## 11. Testing Strategy

- ✅ Unit tests for validation functions
- ✅ Integration tests for end-to-end QR flow
- ✅ Timeout simulation tests
- ✅ Amount limit boundary tests (8000 INR)
- ✅ Error scenario tests (X7, YH, PE, etc.)
- ✅ Concurrency tests for high load
- ✅ Expiry window tests (30-minute boundary)

---

## 12. Monitoring & Alerts

| Alert | Threshold | Action |
|-------|-----------|--------|
| Error Rate High | > 1% | Immediate review |
| Timeout Rate High | > 5% | Check timeout VPA |
| Expiry Rate High | > 10% | Analyze user behavior |
| Latency P95 | > 500ms | Scale/optimize |
| Database CPU | > 80% | Add replicas |

---

## 13. Future Enhancements

1. Machine learning for fraud detection
2. Dynamic limit adjustment based on merchant risk
3. Advanced timeout recovery mechanisms
4. Enhanced async processing with retries
5. Merchant app integration SDK

