What's New in v2
Everything that changed in 3PAY v2 — webhook signing, automatic retries, merchant-controlled withdrawals, rate limiting, and security hardening.
What's New in v2
3PAY v2 is a comprehensive security and reliability overhaul — 18 stages of fixes covering financial safety, webhook infrastructure, access control, and developer experience. This page summarizes every merchant-facing change.
Webhook HMAC-SHA256 Signing
Every webhook now includes a cryptographic signature so you can verify it came from 3PAY.
- Header:
X-Webhook-Signature: sha256=<hex-digest> - HMAC-SHA256 computed from the raw JSON body using your per-merchant
webhookSecret - New merchants auto-receive a secret on registration
Quick verification (Node.js):
const crypto = require('crypto');
const expected = crypto.createHmac('sha256', webhookSecret).update(rawBody).digest('hex');
const received = req.headers['x-webhook-signature']?.replace('sha256=', '');
const valid = crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(received));Manage your secret:
| Method | Endpoint | Description |
|---|---|---|
GET | /api/v1/webhook/secret | View masked secret (last 8 chars visible) |
POST | /api/v1/webhook/secret/rotate | Generate new secret (returned once) |
→ Full details in the Webhook Handling guide.
Automatic Webhook Retries
Failed webhook deliveries now retry automatically with exponential backoff.
| Attempt | Delay | Cumulative Time |
|---|---|---|
| 1 | 1 minute | 1 min |
| 2 | 5 minutes | 6 min |
| 3 | 30 minutes | 36 min |
| 4 | 2 hours | 2 hr 36 min |
| 5 | 12 hours | 14 hr 36 min |
After 5 failures, automatic retries stop. You can still manually retry:
POST /api/v1/webhook/retry/{webhookEventId}
Monitor failures:
GET /api/v1/webhook/events?deliveryStatus=failed
Merchant-Controlled Withdrawals
⚠️ Breaking Change
| v1 | v2 | |
|---|---|---|
| Who approves withdrawals | Admin | Merchant |
| Admin dashboard | Approve/reject buttons | Read-only (view history) |
| Merchant dashboard | View only | Approve/reject buttons |
Merchants now approve/reject their own withdrawal requests via the dashboard or API. Admin can no longer take action on merchant withdrawals.
3 new API endpoints:
GET /api/v1/public/withdrawal-requests # List pending requests
POST /api/v1/public/withdrawal-requests/{id}/approve # Approve (requires x-api-secret)
POST /api/v1/public/withdrawal-requests/{id}/reject # Reject (requires x-api-secret)
→ Full details in the Pay-Outs & Withdrawals guide.
Dashboard Payouts Simplified
| v1 | v2 | |
|---|---|---|
| Behavior | autoPayout flag controlled execute vs queue | Always executes after OTP |
| Approval | Could require second approval | OTP verification is sufficient |
Dashboard payouts now always execute immediately after OTP verification. No more two-step approval flow.
API Payout Endpoint Removed
⚠️ Breaking Change
POST /api/v1/public/payout/create → 404 (disabled)
Payouts must be initiated from the merchant dashboard with 2FA verification. The read-only query endpoint still works:
GET /api/v1/public/payout/get → still active
If you were using the API payout endpoint, switch to dashboard payouts with OTP.
Rate Limiting
6-tier rate limiting system protects against abuse and ensures fair usage.
| Tier | Limit | Window | Applies To |
|---|---|---|---|
| Auth | 15 requests | 15 min | Login, register, password reset |
| Financial | 30 requests | 15 min | Withdrawals, balance updates, approve/reject |
| Wallet Generation | 20 requests | 15 min | POST /wallet/generate |
| Standard API | 100 requests | 15 min | All other public API endpoints |
| Dashboard | 200 requests | 15 min | Dashboard browsing |
| Public Page | 60 requests | 15 min | Customer-facing payment pages |
Exceeding the limit returns 429 Too Many Requests:
{ "success": false, "message": "API rate limit exceeded. Try again in 15 minutes." }Standard RateLimit-* response headers are included on every response.
→ Full details in the Authentication & Security guide.
API Secret Header Changed
| v1 | v2 | |
|---|---|---|
x-api-secret | Never verified | Optional — validated if sent |
| Missing header | Ignored | Lookup uses apikey alone |
| Invalid header | Ignored | Returns 401 |
| Approve/reject | Not required | Required |
The x-api-secret header is optional for backward compatibility. If you send it, it must be correct. It is required for approve/reject withdrawal endpoints.
Security Hardening
- SSRF protection — Webhook URLs and payment callback URLs reject private/internal IPs
- Pagination capped — All list endpoints return max 100 results per page
- API timeouts — External API calls timeout after 10-15 seconds (no hanging requests)
- CORS restricted — Allowlist-based origin validation (public API paths exempt for server-to-server)
- JWT cookies hardened —
secure: true+sameSite: strictin production - Swagger docs protected — Password-protected with HTTP basic auth
- ERC20 dynamic gas — Gas price fetched from network with 10% buffer (no more hardcoded 30 Gwei)
- Transaction validation — All blockchain transaction results checked on-chain (
receipt.status) - Regex injection protection — 47 instances of user input sanitized for MongoDB
$regex - Log sanitization — Credentials redacted from API logs and access logs
- Inter-service auth — Backend microservices authenticate with shared secrets
Removed Features
| Feature | Status | Details |
|---|---|---|
| Refund endpoints | Disabled | /api/v1/refund/* returns 404. Handle refunds outside 3PAY. |
| Goldy tokenization | Archived | Token mint/burn endpoints return 404. |
| Wallet transfers | Removed | Feature placeholder removed. |
| Test notifications | Removed | Debug endpoints disabled. |
Migration Checklist
If you're upgrading from v1:
- Implement webhook HMAC verification — See Authentication & Security
- Update withdrawal management — Use merchant dashboard or new API endpoints (admin no longer approves)
- Remove calls to
POST /payout/create— Switch to dashboard payouts with 2FA - Add retry logic for
429responses — Implement exponential backoff - Verify your
x-api-secret— If you send it, it's now validated. Ensure it matches your dashboard value - Update error handling — New error response formats for rate limits and validation errors
Updated 1 day ago
