# PRD: UPI Static (Static QR Processing)

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

---

## 1. Executive Summary

**UPI Static** handles all static QR code payments where merchants use pre-printed or fixed QR codes. It provides persistent QR validation, payment processing with extended validity, and supports special timeout scenarios. Static QRs have 365-day validity (1 year) and 200 INR amount limit per NPCI regulations.

---

## 2. Product Overview

### 2.1 Purpose
- **Static QR Management**: Store and manage pre-printed QRs
- **Long-term Validity**: Support 365-day QR validity
- **Lower Amount Limit**: Enforce 200 INR per-transaction limit
- **Persistent Records**: Retrieve same QR for multiple transactions
- **tr/tn Storage**: Store terminal and network identifiers
- **Batch Generation**: Generate QRs for merchant networks
- **Legacy Support**: Support pre-printed QR compatibility
- **Stability**: Support small merchants with consistent QRs

### 2.2 Key Users
- **Small Merchants**: Use pre-printed static QRs
- **Retail Networks**: Generate QR batches for stores
- **Support Teams**: Manage QR inventory
- **Acquirers**: Process static QR payments

---

## 3. Core Features

### 3.1 Static QR Storage
- **Pre-generated QRs**: Create QRs in advance
- **Long Validity**: 365-day validity period
- **Terminal Identifiers**: Store tr (terminal) and tn (network)
- **Unique Identifiers**: Each QR has unique tr/tn pair
- **Merchant Linking**: Link to merchant organization
- **Batch Management**: Manage QR in batches
- **Inventory Tracking**: Track active/inactive QRs

### 3.2 ReqValQr Processing (Static)
- **19-Step Flow**: Validation pipeline
- **XML Parsing**: Parse NPCI ReqValQr request
- **Static Detection**: Identify as initiation_mode=02 or 15
- **tr/tn Lookup**: Find static QR by terminal identifiers
- **Verification Token**: Generate UUID per validation
- **PE Expiry Check**: Validate against 1-year expiry
- **Merchant Lookup**: Find merchant by payee VPA
- **Amount Validation**: Check against 200 INR limit (X7 error)
- **Timeout Simulation**: Handle gourmet@merstatic timeouts
- **Event Creation**: Create initial event chain

### 3.3 ReqPay Processing (Static)
- **19-Step Flow**: Payment processing pipeline
- **Token Validation**: Verify token from ReqValQr
- **Timeout Handling**: 30-second timeout for gourmet@merstatic
- **Amount Checks**: Validate against 200 INR limit (X7 error)
- **Merchant Validation**: YH error for invalid merchants
- **Status Tracking**: SUCCESS/FAILED/REVERSAL
- **tr/tn Persistence**: Same QR used for multiple payments

### 3.4 Static QR Lifecycle
1. **Creation**: Generate static QR with 1-year validity
2. **Assignment**: Link to merchant
3. **Deployment**: Print QR codes for merchants
4. **Usage**: Accept multiple payments via same QR
5. **Tracking**: Monitor payment history
6. **Expiry**: Deactivate after 365 days
7. **Archive**: Store for audit trail

### 3.5 tr/tn Identifier Management
- **tr (Terminal ID)**: Unique terminal identifier
- **tn (Network ID)**: Network identifier
- **Uniqueness**: tr/tn pair uniquely identifies QR
- **Lookup**: Fast retrieval by tr/tn
- **Validation**: Verify format and validity
- **Terminal Registry**: Maintain registry of known terminals

### 3.6 Error Handling - Static Specific
- **X7 Error**: Amount exceeds 200 INR (not 8000 like dynamic)
- **YH Error**: Merchant signature/encryption failure
- **PE Error**: Static QR expired (>365 days)
- **ZE Error**: Invalid verification token
- **ZD Error**: Duplicate message ID
- **ZF Error**: Verification/signature failed
- **ZQ Error**: tr/tn not found in static_qrs table

### 3.7 HTTP API Endpoints
- **POST /api/v1/static-qr/validate**: ReqValQr handler
- **POST /api/v1/static-qr/pay**: ReqPay handler
- **POST /api/v1/static-qr/check**: ReqChkTxn handler
- **POST /api/v1/static-qr/generate**: Generate new static QR
- **GET /api/v1/static-qr/:id**: View QR details
- **GET /api/v1/static-qr/:id/payments**: View payment history

---

## 4. Database Schema

### 4.1 Key Tables
| Table | Purpose | Org ID |
|-------|---------|--------|
| static_qrs | Static QR records | MER102 |
| qr_validations | QR validations | MER102 |
| req_pays | Static payments | MER102 |
| transactions | Payment records | MER102 |
| qr_validation_events | Event chain | MER102 |
| transaction_events | Event chain | MER102 |

### 4.2 StaticQR Schema
```
id: primary key
tr: terminal identifier
tn: network identifier
org_id: MER102 (always for static)
merchant_id: linked merchant
payee_addr: merchant VPA
qr_payload: encoded QR data
created_at: creation timestamp
expires_at: current_time + 365 days
status: active/inactive/expired
payment_count: number of payments processed
last_payment_at: timestamp of last payment
```

### 4.3 QRValidation for Static
```
org_id: MER102 (always for static)
initiation_mode: 02 or 15
qr_medium: STATIC
tr: terminal ID from request
tn: network ID from request
ver_token: UUID generated per validation
qr_expires_at: stored from static_qr expires_at
validation_type: DOMESTIC or INTERNATIONAL
base_amount: 1-200 INR (domestic) or in base currency (intl)
```

### 4.4 ReqPay for Static
```
org_id: MER102
amount: 1-200 INR
tr: terminal ID
tn: network ID
status: SUCCESS/FAILED/PENDING/REVERSED
settlement_amount: calculated after fees
```

---

## 5. Processing Flow

### 5.1 Static QR Generation Flow
1. Merchant requests QR batch generation
2. Define merchant, tr/tn ranges, expiry date
3. For each tr/tn pair:
   - Generate QR payload with merchant VPA
   - Encode base64
   - Create static_qr record
   - Set expires_at = now + 365 days
4. Return QR codes for printing
5. Track batch in system

### 5.2 ReqValQr Flow (19 Steps)
1. Receive HTTP POST from NPCI
2. Parse XML payload
3. Extract message ID, tr (terminal), tn (network)
4. Detect initiation_mode = 02 or 15 → Static QR
5. Validate XML schema
6. Lookup static QR by tr/tn (ZQ error if not found)
7. Validate static QR not expired (PE error if expired)
8. Optional: Check PE (payment expired)
9. Determine validation_type (DOMESTIC or INTERNATIONAL)
10. Extract merchant details from static_qr
11. For static: Check amount ≤ 200 INR (X7 if exceeds)
12. For international: Fetch FX rate + convert to INR
13. Generate verification token (UUID)
14. Set qr_expires_at from static_qr record
15. Create QRValidation record
16. Create initial event in qr_validation_events
17. Compute XML hashes (SHA256)
18. Build RespValQr with token and timestamp
19. Send ACK response immediately

### 5.3 ReqPay Flow (19 Steps)
1. Receive HTTP POST from NPCI
2. Parse XML payload
3. Extract message ID and tr/tn
4. Check idempotency: msg_id must be unique
5. Lookup verification token
6. Validate token not expired
7. Verify token hasn't been used before
8. Extract payer address from request
9. Verify amount matches original quote
10. For gourmet@merstatic: Simulate 30-second timeout
11. For X7 scenario: Check if amount > 200 → X7 error
12. For YH scenario: Merchant signature validation fails
13. If all valid: Update transaction status to SUCCESS
14. Increment payment_count on static_qr
15. Update last_payment_at on static_qr
16. Calculate settlement_amount with fees
17. Append event to transaction_events chain
18. Send RespPay with status to NPCI
19. Reuse same static QR for future payments

---

## 6. Error Scenarios

### 6.1 Static Validation Errors
| Scenario | Error Code | Cause | Response |
|----------|-----------|-------|----------|
| S1 | 00 | Normal success | RespValQr with token |
| S2 | PE | QR expired (>365 days) | Payment expired error |
| S3 | X7 | Amount > 200 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 | tr/tn not in static_qrs | QR not found |
| S9 | ZR | Merchant not found | Merchant lookup failure |
| S10 | 96 | System error | HTTP 500 |

### 6.2 Static Payment Errors
| Scenario | Error Code | Amount | Settlement |
|----------|-----------|--------|-----------|
| S1 | 00 | 100 INR | 100 INR |
| S2 | 00 | Timeout (gourmet@merstatic) | 0 INR |
| S3 | 00 | Reversal | 0 INR |
| S4 | X7 | 250 INR | 0 INR (exceeds 200) |
| S5 | YH | 150 INR | 0 INR (merchant error) |
| S6 | ZE | Any | Invalid token |
| S7 | ZD | Any | Duplicate |
| S8 | ZF | Any | Signature failed |
| S9 | ZQ | Any | Static QR not found |
| S10 | 96 | Any | System error |

---

## 7. Configuration

### 7.1 Static-Specific Settings
```elixir
# Static QR Configuration
STATIC_QR_EXPIRY_DAYS=365
STATIC_QR_LIMIT_INR=200
TIMEOUT_DURATION_SECONDS=30
TIMEOUT_VPA=gourmet@merstatic

# Routing
STATIC_ORG_ID=MER102
STATIC_NET_INST_ID=MER1020002
STATIC_INITIATION_MODE=02

# Settlement
STATIC_X7_SETTLEMENT=0
STATIC_YH_SETTLEMENT=0

# Terminal Registry
TR_VALID_FORMAT=^[A-Z0-9]{8}$
TN_VALID_FORMAT=^[A-Z0-9]{6}$
```

### 7.2 Difference from Dynamic
| Feature | Dynamic | Static |
|---------|---------|--------|
| Validity | 30 minutes | 365 days |
| Amount Limit | 8000 INR | 200 INR |
| Generation | Per transaction | Pre-generated |
| QR Reuse | One-time | Multiple times |
| Timeout VPA | gourmet@mercury | gourmet@merstatic |
| Org ID | MER101 | MER102 |
| initiation_mode | 16 | 02/15 |

---

## 8. API Examples

### 8.1 Generate Static QR Request
```json
POST /api/v1/static-qr/generate
{
  "merchant_id": 123,
  "tr_prefix": "TERM",
  "tr_count": 100,
  "tn_prefix": "NET",
  "validity_days": 365
}
```

### 8.2 ReqValQr Request
```xml
POST /api/v1/static-qr/validate
<ReqValQr>
  <MsgID>MSG1234567890</MsgID>
  <Ts>2026-06-12T10:30:00Z</Ts>
  <OrgID>MER102</OrgID>
  <Curr>INR</Curr>
  <Amount>100.00</Amount>
  <Mcc>5411</Mcc>
  <TR>TERM0001</TR>
  <TN>NET001</TN>
</ReqValQr>
```

### 8.3 RespValQr Response
```xml
<RespValQr>
  <MsgID>MSG1234567890</MsgID>
  <Status>00</Status>
  <VerToken>550e8400-e29b-41d4-a716-446655440000</VerToken>
  <ExpiresAt>2027-06-12T00:00:00Z</ExpiresAt>
  <Ts>2026-06-12T10:30:00Z</Ts>
</RespValQr>
```

---

## 9. Dependencies

- Same as upi_dynamic
- Plus: Terminal registry queries
- Plus: Long-term QR tracking

---

## 10. Performance Requirements

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

---

## 11. Inventory Management

- Track active static QRs per merchant
- Monitor payment_count for analytics
- Alert when QR approaching expiry
- Archive expired QRs
- Generate replacement QRs

---

## 12. Success Metrics

| Metric | Target | Status |
|--------|--------|--------|
| Payment Success Rate | 99.5% | ✅ |
| QR Lookup Speed | < 10ms | ✅ |
| Duplicate Prevention | 100% | ✅ |
| Expiry Accuracy | 100% | ✅ |

