January 6, 2026 - v1.3.0
Overview
This release introduces a mandatory idempotency key requirement for refund and payout operations to enhance transaction safety and prevent accidental duplicate processing. This is a breaking change for merchants using refund or payout endpoints.
X-Idempotent-Key header before January 20, 2026. After this date, requests without this header will be rejected with 400 Bad Request.Breaking Changes
1. Mandatory Idempotency Key for Refunds
What's Changed
The X-Idempotent-Key header is now required for all refund operations:
Endpoint Affected:
POST /api/v1/payment-gateway/order/refund
New Required Header:
| Header | Type | Required | Description |
|---|---|---|---|
X-Idempotent-Key | string | Yes | Unique key to prevent duplicate refunds (UUID recommended) |
Example Request:
curl -X POST https://merchant.dv.vai247.pro/api/v1/payment-gateway/order/refund \
-H "X-App-Id: your-app-id" \
-H "X-Api-Key: your-api-key" \
-H "X-Timestamp: 1704542400" \
-H "X-Idempotent-Key: 550e8400-e29b-41d4-a716-446655440000" \
-H "Content-Type: application/json" \
-d '{
"order_id": "ord_abc123xyz",
"amount": 50.00,
"reason": "Customer request"
}'
Impact of Change
- Prevents duplicate refunds caused by network retries, user error, or system failures
- Protects merchants from financial loss due to accidental duplicate refund processing
- Industry standard practice for financial operations
- 24-hour idempotency window: Same key returns cached result if retried within 24 hours
What Will Break
❌ Requests without X-Idempotent-Key will fail with:
{
"error": {
"code": "missing_idempotent_key",
"message": "X-Idempotent-Key header is required for refund operations",
"request_id": "req_xyz789"
}
}
Migration Steps
Install UUID Library
# Node.js
npm install uuid
# Golang
go get github.com/google/uuid
Update Refund Function
Add idempotent key generation to your refund code
Test Integration
Verify refunds work with the new header in sandbox
Deploy to Production
Roll out changes before January 20, 2026
Code Examples
import "github.com/google/uuid"
func refundOrder(orderID string, amount float64, reason string) error {
// Generate unique idempotent key
idempotentKey := uuid.New().String()
req.Header.Set("X-App-Id", os.Getenv("DVPAY_APP_ID"))
req.Header.Set("X-Api-Key", os.Getenv("DVPAY_API_KEY"))
req.Header.Set("X-Timestamp", fmt.Sprintf("%d", time.Now().Unix()))
req.Header.Set("X-Idempotent-Key", idempotentKey)
// Make API call...
}
const { v4: uuidv4 } = require('uuid');
async function refundOrder(orderId, amount, reason) {
// Generate unique idempotent key
const idempotentKey = uuidv4();
const response = await axios.post(url, payload, {
headers: {
'X-App-Id': process.env.DVPAY_APP_ID,
'X-Api-Key': process.env.DVPAY_API_KEY,
'X-Timestamp': Math.floor(Date.now() / 1000).toString(),
'X-Idempotent-Key': idempotentKey,
'Content-Type': 'application/json'
}
});
return response.data;
}
Implementation Reference
→ Refund Order API Documentation
2. Mandatory Idempotency Key for Payouts
What's Changed
The X-Idempotent-Key header is now required for all payout operations:
Endpoint Affected:
POST /api/v1/payment-gateway/order/payout
New Required Header:
| Header | Type | Required | Description |
|---|---|---|---|
X-Idempotent-Key | string | Yes | Unique key to prevent duplicate payouts (UUID recommended) |
Example Request:
curl -X POST https://merchant.dv.vai247.pro/api/v1/payment-gateway/order/payout \
-H "X-App-Id: your-app-id" \
-H "X-Api-Key: your-api-key" \
-H "X-Timestamp: 1704542400" \
-H "X-Idempotent-Key: 660f9500-f39c-51e5-b827-557766551111" \
-H "Content-Type: application/json" \
-d '{
"account_id": "acc_123",
"amount": 200.00,
"currency": "USD",
"description": "Monthly commission"
}'
Impact of Change
- Prevents duplicate payouts caused by network issues, retries, or user error
- Protects merchant balance from unintended double payments
- Critical for financial accuracy in marketplace and platform businesses
- Safe retry mechanism: Same key returns original response without duplicate processing
What Will Break
❌ Requests without X-Idempotent-Key will fail with:
{
"error": {
"code": "missing_idempotent_key",
"message": "X-Idempotent-Key header is required for payout operations",
"request_id": "req_abc456"
}
}
Migration Steps
Install UUID Library
Same as refund migration above
Update Payout Function
Add idempotent key generation to your payout code
Test Integration
Verify payouts work with the new header in sandbox
Deploy to Production
Roll out changes before January 20, 2026
Code Examples
import "github.com/google/uuid"
func processPayout(accountID string, amount float64, currency string) error {
// Generate unique idempotent key
idempotentKey := uuid.New().String()
req.Header.Set("X-App-Id", os.Getenv("DVPAY_APP_ID"))
req.Header.Set("X-Api-Key", os.Getenv("DVPAY_API_KEY"))
req.Header.Set("X-Timestamp", fmt.Sprintf("%d", time.Now().Unix()))
req.Header.Set("X-Idempotent-Key", idempotentKey)
// Make API call...
}
const { v4: uuidv4 } = require('uuid');
async function processPayout(accountId, amount, currency) {
// Generate unique idempotent key
const idempotentKey = uuidv4();
const response = await axios.post(url, payload, {
headers: {
'X-App-Id': process.env.DVPAY_APP_ID,
'X-Api-Key': process.env.DVPAY_API_KEY,
'X-Timestamp': Math.floor(Date.now() / 1000).toString(),
'X-Idempotent-Key': idempotentKey,
'Content-Type': 'application/json'
}
});
return response.data;
}
Implementation Reference
New Features
1. Idempotency Protection Window
What's New
DVPay now caches idempotent request results for 24 hours, enabling safe retries:
How It Works:
- First request with
X-Idempotent-Key: abc-123→ Processes refund/payout - Retry with same
X-Idempotent-Key: abc-123→ Returns cached result (no duplicate processing) - After 24 hours → Key expires, can be reused
Benefits:
- Safe network retry logic: Retry failed requests without fear of duplicates
- Handles timeouts gracefully: If client times out but server processes, retry returns the result
- Automatic deduplication: Server-side protection against duplicate submissions
- Prevents user double-click issues: Multiple submissions with same key are handled safely
Example Scenario:
// Request times out due to network issue
try {
await refundOrder('ord_123', 50.00, 'refund', 'key-abc-123');
} catch (error) {
// Network timeout, but refund may have processed
}
// Safe to retry with same idempotent key
try {
// If refund processed: returns original result
// If refund didn't process: processes now
await refundOrder('ord_123', 50.00, 'refund', 'key-abc-123');
} catch (error) {
// Handle actual error
}
Implementation Reference
→ Error Handling - Idempotency
2. New Error Code: missing_idempotent_key
What's New
New error code returned when X-Idempotent-Key header is missing:
Error Response:
{
"error": {
"code": "missing_idempotent_key",
"message": "X-Idempotent-Key header is required for this operation",
"details": {
"endpoint": "/api/v1/payment-gateway/order/refund",
"required_header": "X-Idempotent-Key",
"documentation": "https://docs.dvpay.com/api-reference/refund-order"
},
"request_id": "req_xyz789",
"timestamp": 1704542400
}
}
HTTP Status Code: 400 Bad Request
Affected Endpoints:
POST /api/v1/payment-gateway/order/refundPOST /api/v1/payment-gateway/order/payout
Impact of Feature
- Clear error messaging for missing headers
- Includes documentation link for quick fix
- Helps developers quickly identify and fix integration issues
Implementation Reference
→ Error Handling Documentation
Documentation Updates
All relevant documentation has been updated to reflect the idempotency key requirement:
Migration Timeline
January 6, 2026 (Today)
Grace period begins. Both with and without X-Idempotent-Key accepted, but warnings logged.
January 13, 2026
Deprecation warnings in response headers. All responses include X-DVPay-Deprecation-Warning header.
January 20, 2026
Enforcement begins. Requests without X-Idempotent-Key rejected with 400 Bad Request.
January 27, 2026
Full enforcement. All merchants must have updated integrations.
Migration Checklist
Before January 20, 2026, complete these steps:
Review Integration
Identify all code calling refund or payout APIs
Install UUID Library
Add UUID generation capability to your project
Update Refund Functions
Add X-Idempotent-Key header with unique UUID
Update Payout Functions
Add X-Idempotent-Key header with unique UUID
Test in Sandbox
Verify both endpoints work with new header
Update Error Handling
Add handling for missing_idempotent_key error
Deploy to Production
Roll out changes before January 20, 2026
Monitor Logs
Check for deprecation warnings and fix any missed instances
Testing Guide
Sandbox Testing
Test your updated integration in the sandbox environment:
# Test Refund with Idempotent Key
curl -X POST https://sandbox.merchant.dv.vai247.pro/api/v1/payment-gateway/order/refund \
-H "X-App-Id: sandbox-app-id" \
-H "X-Api-Key: sandbox-api-key" \
-H "X-Timestamp: $(date +%s)" \
-H "X-Idempotent-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"order_id": "test_order_123", "amount": 10.00}'
Test Idempotency Behavior
Verify that duplicate requests return the same result:
# First request - processes refund
IDEMPOTENT_KEY="550e8400-e29b-41d4-a716-446655440000"
curl -X POST $URL -H "X-Idempotent-Key: $IDEMPOTENT_KEY" -d '{...}'
# Second request - returns cached result, no duplicate
curl -X POST $URL -H "X-Idempotent-Key: $IDEMPOTENT_KEY" -d '{...}'
Test Error Handling
Verify proper error when header is missing:
# Request without idempotent key (should fail after Jan 20)
curl -X POST $URL -d '{...}'
# Expected: 400 Bad Request with missing_idempotent_key error
Frequently Asked Questions
Q: Why is this change necessary?
A: Idempotency keys prevent duplicate refunds and payouts caused by network retries, timeouts, or user error. This protects both merchants and customers from financial losses due to duplicate transactions.
Q: Can I reuse the same idempotent key?
A: After 24 hours, keys expire and can be reused. However, we recommend generating a unique UUID for each operation.
Q: What happens if I retry with the same key?
A: The API returns the original response without processing a duplicate transaction. This is safe and expected behavior.
Q: Do I need idempotent keys for other endpoints?
A: No, only refund and payout operations require idempotency keys. Other endpoints (create order, generate QR, etc.) do not require this header.
Q: What UUID version should I use?
A: UUID v4 (random) is recommended. Most UUID libraries default to v4.
Q: What if my language doesn't have a UUID library?
A: Any unique string works. Common alternatives:
- Timestamp + random string:
${Date.now()}-${Math.random()} - Hash of request data:
sha256(orderid + amount + timestamp) - Database-generated unique ID
Technical Details
Idempotency Key Requirements
- Format: Any string up to 255 characters
- Recommended: UUID v4 format
- Validation: Must be non-empty
- Storage: Cached server-side for 24 hours
- Scope: Per merchant account
Performance Impact
- Latency: No measurable increase (<1ms overhead)
- Storage: Minimal (keys cached in Redis)
- Rate Limits: Unchanged
Backward Compatibility
During grace period (Jan 6-20, 2026):
- Requests without header: ✅ Accepted (with warning)
- Requests with header: ✅ Accepted
After enforcement (Jan 20+, 2026):
- Requests without header: ❌ Rejected (400 Bad Request)
- Requests with header: ✅ Accepted
Support
If you need assistance migrating your integration:
- Documentation: API Reference
- Email Support: support@dvpay.com
- Developer Forum: https://forum.dvpay.com
- Emergency Hotline: +855-xxx-xxx-xxx (business hours)
Summary
This release introduces mandatory idempotency key protection for refund and payout operations—a critical security enhancement that prevents duplicate transactions. All merchants must update their integrations before January 20, 2026 to avoid service disruption.
Action Required: Add X-Idempotent-Key header to all refund and payout API calls.