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:

MethodEndpointDescription
GET/api/v1/webhook/secretView masked secret (last 8 chars visible)
POST/api/v1/webhook/secret/rotateGenerate new secret (returned once)

→ Full details in the Webhook Handling guide.


Automatic Webhook Retries

Failed webhook deliveries now retry automatically with exponential backoff.

AttemptDelayCumulative Time
11 minute1 min
25 minutes6 min
330 minutes36 min
42 hours2 hr 36 min
512 hours14 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

v1v2
Who approves withdrawalsAdminMerchant
Admin dashboardApprove/reject buttonsRead-only (view history)
Merchant dashboardView onlyApprove/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

v1v2
BehaviorautoPayout flag controlled execute vs queueAlways executes after OTP
ApprovalCould require second approvalOTP 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.

TierLimitWindowApplies To
Auth15 requests15 minLogin, register, password reset
Financial30 requests15 minWithdrawals, balance updates, approve/reject
Wallet Generation20 requests15 minPOST /wallet/generate
Standard API100 requests15 minAll other public API endpoints
Dashboard200 requests15 minDashboard browsing
Public Page60 requests15 minCustomer-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

v1v2
x-api-secretNever verifiedOptional — validated if sent
Missing headerIgnoredLookup uses apikey alone
Invalid headerIgnoredReturns 401
Approve/rejectNot requiredRequired

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 hardenedsecure: true + sameSite: strict in 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

FeatureStatusDetails
Refund endpointsDisabled/api/v1/refund/* returns 404. Handle refunds outside 3PAY.
Goldy tokenizationArchivedToken mint/burn endpoints return 404.
Wallet transfersRemovedFeature placeholder removed.
Test notificationsRemovedDebug endpoints disabled.

Migration Checklist

If you're upgrading from v1:

  1. Implement webhook HMAC verification — See Authentication & Security
  2. Update withdrawal management — Use merchant dashboard or new API endpoints (admin no longer approves)
  3. Remove calls to POST /payout/create — Switch to dashboard payouts with 2FA
  4. Add retry logic for 429 responses — Implement exponential backoff
  5. Verify your x-api-secret — If you send it, it's now validated. Ensure it matches your dashboard value
  6. Update error handling — New error response formats for rate limits and validation errors