32 KiB
title, tags
| title | tags | |||||
|---|---|---|---|---|---|---|
| Payment API |
|
Payment API
Last updated: 2026-05-31 — Postgres integration promotion, oracle quote persistence, AMN scanner rail-switch fix, and partial gasless permit endpoints.
The payment surface is split across provider-neutral payment routers, Request Network checkout/webhook routes, derived-destination custody routes, and admin safety routes:
| Path prefix | File | Purpose |
|---|---|---|
/api/payment/* |
paymentControllerRoutes.ts |
New controller pattern (CRUD + configuration) |
/api/payment/* |
paymentRoutes.ts |
Additional legacy endpoints (tx fetch, exports) |
/api/payment/request-network/* |
requestNetwork/requestNetworkRoutes.ts |
Request Network intent creation, in-house checkout payloads, webhook processing |
/api/payment/derived-destinations/* |
wallets/derivedDestinationRoutes.ts |
Derived destination inspection, balance checks, and sweeping |
/api/payment/decentralized/* |
decentralizedPaymentRoutes.ts |
Legacy wallet-direct confirmations |
/api/payment/amn-scanner/* |
routes/amnScannerWebhookRoutes.ts |
AMN Pay Scanner webhook receiver |
/api/admin/rn/networks/* |
requestNetwork/networkRegistryRoutes.ts |
Request Network chain/token registry |
/api/admin/payments/awaiting-confirmation/* |
awaitingConfirmationRoutes.ts |
Admin queue for payments waiting on confirmation/safety checks |
Core model: Payment. Coordination logic to avoid race conditions when multiple sources update the same payment is in paymentCoordinator.ts.
[!warning] Persistence status Payment APIs still create/read/update Mongo
Paymentdocuments on backend2.6.79. The Postgres branch adds schemas, repos, migrations, and optional quote persistence, but it is not a full payment-domain cutover./api/payment/request-network/intentscan writepayment_quotesonly whenORACLE_QUOTING_ENABLED=true; the payment record itself remains Mongo-backed unless future service wiring changes that boundary.
Configuration / health
POST /api/payment/configuration
Description: Returns the active payment provider configuration, including Request Network settings, supported chain/token data, receiver/derived-destination context, and redirect/webhook URLs where applicable.
Auth required: No
Request body: { amount?, currency?, purchaseRequestId? } (used to scope returned config)
Response 200:
{
"accept": [{ "blockchain": "bsc", "token": "0x55d3...", "receiver": "0xa30..." }],
"redirect": { "success": "...", "cancel": "..." },
"webhook": "https://.../api/payment/request-network/webhook"
}
GET /api/payment/health
Description: Lightweight health probe.
Auth required: No
Response 200: { success, message, endpoints }. Older builds may still list legacy endpoint names in this health payload; rely on app.ts mounts for the authoritative live surface.
GET /api/payment/shkeeper/config
Description: Historical compatibility endpoint for the old SHKeeper-hosted widget. It is not part of the current Request Network checkout path. Auth required: No
Payment records (CRUD)
POST /api/payment
Description: Create a payment record manually. Normal buyer checkout should use POST /api/payment/request-network/pay-in.
Auth required: Bearer JWT
Request body:
{
purchaseRequestId: string;
sellerOfferId: string;
buyerId: string;
sellerId: string;
amount: { amount: number; currency: string };
blockchain?: { network: string; token: string };
metadata?: Record<string, unknown>;
}
Response 201: { /* Payment document */ }
PUT /api/payment/:id
Description: Update a payment record (status, transactionHash, metadata). Auth required: Bearer JWT Request body:
{
status?: "pending" | "processing" | "completed" | "failed" | "cancelled";
transactionHash?: string;
blockchain?: { ... };
metadata?: Record<string, unknown>;
}
GET /api/payment
Description: List the caller's payments (defaults to completed,success status).
Auth required: Bearer JWT
Query params: status, limit (default 50), offset (default 0)
GET /api/payment/:id
Description: Fetch a payment by id. For payments with provider: 'request.network' that are still pending, this endpoint also performs an on-demand RN reconcile: it queries the Request Network node live, and if RN reports the request as paid it immediately marks the payment completed, advances the purchase request to processing, persists selectedOfferId, and accepts the winning offer while rejecting all others. This reconcile path exists because RN webhooks cannot reach a local dev server and the reconcile cron is not started there; the same logic fires in production as a safety net.
Auth required: Bearer JWT
Errors: 404 not found.
⚠️ NOT IMPLEMENTED:
GET /payment/:id/status,POST /payment/:id/confirm, andDELETE /payment/:iddo not exist in the codebase. Do not call these paths.
GET /api/payment/user/:userId
Description: Payments for a specific user (admin or self).
Auth required: Bearer JWT
Query params: status, limit, offset
GET /api/payment/stats / GET /api/payment/stats/:userId
Description: Aggregated counts and sums per status.
Auth required: Bearer JWT
⚠️ Known undercounting: Only payments with status 'confirmed' are counted as successfulPayments. Payments with status 'completed' (the terminal state for SHKeeper and DePay) are not included in this count and are therefore under-reported.
GET /api/payment/export / GET /api/payment/export/:userId
Description: Export payments as json or csv.
Auth required: Bearer JWT
Query params: format=json|csv
⚠️ Privilege gap: The controller-pattern route for this endpoint has no admin guard. Any authenticated user (not just admins) can export payment data.
⚠️ NOT IMPLEMENTED:
/payment/history,/payment/methods,/payment/validate,/payment/transactions, and/payment/escrow/balancedo not exist. Do not call these paths.
POST /api/payment/payments/cleanup-pending
Description: Admin cleanup of stale pending payments.
Auth required: Bearer JWT (admin)
Response 200: { success, deletedCount, message }
POST /api/payment/payments/:id/fetch-tx
Description: Re-queries the blockchain to fetch the missing transactionHash for a completed payment.
Auth required: Bearer JWT (admin) — authenticateToken + authorizeRoles('admin') added in commit 1d881c5 (ISSUE-005 fix).
Response 200: { success, transactionHash, network, source, message }
POST /api/payment/payments/auto-fetch-missing
Description: Batch tx-hash backfill across the database.
Auth required: Bearer JWT (admin) — authenticateToken + authorizeRoles('admin') added in commit 1d881c5 (ISSUE-005 fix).
Request body: { limit?: number } (default 10)
GET /api/payment/payments/:id/debug
Description: Debug bundle including the raw payment, blockchain metadata, and wallet-monitor status. Intended for admin / development.
Auth required: Bearer JWT (admin) — authenticateToken + authorizeRoles('admin') added in commit 1d881c5 (ISSUE-005 fix).
POST /api/payment/callback
Description: Generic payment callback (called by the older client SDK).
Auth required: No (verified by paymentRef matching)
Request body: { paymentId, transactionHash, status, data }
POST /api/payment/verify
Description: Legacy frontend verification endpoint used by the wallet-direct Web3 flow. Confirms a payment and updates the related PurchaseRequest. Auth required: Bearer JWT
Request Network - Pay-in
POST /api/payment/request-network/pay-in
Description: Creates a plain Request Network pay-in intent and stores a Payment with provider: "request.network". The service can attach a per-payment derived destination before creating the provider request. This route stays available at /api/payment/request-network/pay-in, but new provider-selection checkout integrations should prefer /api/payment/request-network/intents.
Auth required: Bearer JWT (buyer)
Request body:
{
purchaseRequestId: string;
sellerOfferId: string;
sellerId: string;
amount: number;
token?: string; // default "USDT" or REQUEST_NETWORK_PAYMENT_CURRENCY
network?: string; // default REQUEST_NETWORK_NETWORK or "bsc"
metadata?: Record<string, unknown>;
}
Response 200: { success: true, data: { paymentId, paymentUrl, providerPaymentId, raw, ... } }
POST /api/payment/request-network/intents
Description: Richer buyer intent endpoint used by the provider-selection checkout. It can dispatch either to request.network or amn.scanner, validates the seller's allowed chain/token choices, and re-points an existing pending intent when the buyer changes rail. When ORACLE_QUOTING_ENABLED=true, the backend ignores client-supplied amount, loads the seller offer price, computes a depeg-protected quote, and uses the computed settlement amount for the provider intent.
Auth required: Bearer JWT (buyer)
Request body additions: provider?: "request.network" | "amn.scanner", token, network, metadata.templateId?.
Response 200: { success: true, data, quote? }. quote includes settleAmount, token, tokenPriceUSD, depegAdjustmentBps, roundingBps, and expiresAt when oracle quoting is enabled.
Errors: 400 for unsupported/disallowed chain-token choice, 422 DEPEG_LIMIT_EXCEEDED when the settlement token exceeds the depeg hard cap, 503 ORACLE_UNAVAILABLE when rates are stale or unavailable.
GET /api/payment/request-network/permit-availability
Description: Checks whether the backend relayer can sponsor an EIP-2612 permit() transaction for a chain/token. This is partial gasless support: it removes the approval transaction gas only; the buyer still sends the final payment transaction.
Auth required: Bearer JWT
Query params: chainId, token
Response 200: { success: true, data: { available, reason?, relayer?, balanceWei?, requiredWei? } }
POST /api/payment/request-network/:paymentId/permit
Description: Broadcasts a buyer-signed EIP-2612 permit through the backend relayer. The route validates the permit against the payment's actual in-house checkout block so the relayer only sponsors real pending payments and the expected fee-proxy spender.
Auth required: Bearer JWT (buyer who owns the payment)
Request body: { owner, spender, value, deadline, v, r, s }
Response 200: { success: true, data: { txHash, allowance } }
Limitations: Only permit-capable tokens/chains qualify. Mainnet USDT is not permit-capable; full gasless payment still requires a forwarder or account-abstraction/paymaster design.
GET /api/payment/request-network/:paymentId/checkout
Description: Rehydrates the in-house checkout payload for an existing Request Network payment so the frontend can build the on-chain approval/payment transaction without relying on the hosted RN page. Auth required: Bearer JWT (buyer who owns the payment)
POST /api/payment/request-network/webhook
Description: Request Network posts settlement updates here. The route verifies x-request-network-signature over the raw body, deduplicates delivery IDs, evaluates the Transaction Safety Provider, and coordinates the payment/ledger update.
Auth required: No (signature-protected)
Response: 200 when processed or duplicate; 202 when accepted but safety checks are pending; 401 for invalid signature.
[!note] RN payout/release/refund routes
POST /api/payment/request-network/:paymentId/payout/initiate,POST /api/payment/request-network/:paymentId/payout/confirm,POST /api/payment/request-network/:paymentId/release/confirm, andPOST /api/payment/request-network/:paymentId/refund/confirmare registered inrequestNetworkRoutes.tsbut are stub-level implementations. They accept the request and return a 200 but do not yet drive the ledger-gated release/refund orchestration. UsePOST /api/payment/:id/releaseandPOST /api/payment/:id/refundfor actual escrow releases.
AMN Pay Scanner - Pay-in
AMN Pay Scanner is a custom in-house blockchain scanner that replaces the hosted Request Network page for payment monitoring. It speaks the same PaymentProviderAdapter interface as the RN adapter.
POST /api/payment/amn-scanner/webhook
Description: AMN Pay Scanner posts settlement confirmations here. The route verifies a webhookSecret-based HMAC signature, then runs the Transaction Safety Provider and PaymentCoordinator pipeline identical to the RN webhook path.
Auth required: No (signature-protected via AMN_SCANNER_WEBHOOK_SECRET)
Request body: { intentId, status, transactionHash?, chainId?, ... } — scanner-specific envelope
Response: 200 processed; 401 bad signature; 400 missing intentId or unknown format; 404 payment not found.
Side effects: Same as the RN webhook — updates Payment, advances PurchaseRequest, accepts/rejects offers, emits socket events when safety checks pass.
[!note] Provider value Payments created via the AMN Pay Scanner have
provider: 'amn.scanner'in the database. This is distinct fromrequest.networkandshkeeper.
GET /api/admin/scanner/status
Description: Proxies to AMN_SCANNER_URL/scanner/status and returns the scanner's internal state.
Auth required: Bearer JWT (admin) — authenticateToken + authorizeRoles('admin') are now applied (the previously documented security gap — unauthenticated access — has been fixed in commit 1d881c5).
Response 200: Scanner status JSON forwarded from the upstream service.
POST /api/admin/scanner/webhooks/retry
Description: Triggers a manual retry of failed/pending scanner webhooks.
Auth required: Bearer JWT (admin)
Request body: { intentId?: string } — omit to retry all pending.
Legacy SHKeeper - Pay-in
[!warning] Historical route family The current
app.tsmounts Request Network routes, notservices/payment/shkeeper/*. Keep this section only for legacy record migration and old operational context.
POST /api/payment/shkeeper/intents
Description: Creates a SHKeeper pay-in intent. The server provisions an invoice on SHKeeper, stores a Payment with provider: "shkeeper", direction: "in", returns the hosted-widget URL.
Auth required: Bearer JWT (buyer)
Request body:
{
purchaseRequestId: string;
sellerOfferId: string;
amount: number;
sellerId: string;
token?: string; // default "USDT"
network?: string; // default "bsc"
metadata?: Record<string, unknown>;
}
Response 200:
{
"success": true,
"data": {
"paymentId": "...",
"paymentUrl": "https://pay.amn.gg/invoice/...",
"externalId": "AMN_...",
"expiresAt": "2026-05-23T11:00:00.000Z"
}
}
Errors: 400 missing fields, 401 not authenticated, 500 SHKeeper error.
Side effects: Emits payment-created globally and to the request room.
POST /api/payment/shkeeper/webhook
Description: SHKeeper posts here when an invoice changes state. Handles both raw-string and JSON bodies and verifies the HMAC signature (x-shkeeper-signature against the raw body using SHKEEPER_WEBHOOK_SECRET).
Auth required: No (signature-protected)
Body: The SHKeeper callback envelope (external_id, crypto, addr, fiat, balance_fiat, balance_crypto, paid, status, transactions[]).
Response 200: { success: true }
Side effects:
- Updates the matching Payment to
completed(OVERPAIDandPAIDboth count). Note:'completed'is the terminal state for SHKeeper payments but is not counted assuccessfulPaymentsinGET /api/payment/stats. - Releases or rejects SellerOffer siblings (the chosen offer becomes
accepted, othersrejected). - Updates PurchaseRequest status to
payment/processing. - Emits
seller-offer-updateto each affected seller room andpurchase-request-updateto the request room.
⚠️ NOT IMPLEMENTED:
GET /api/payment/shkeeper/status/:paymentIddoes not exist. SHKeeper payment status is delivered via socket events only — there is no HTTP polling endpoint.
POST /api/payment/shkeeper/confirm-transaction
Description: Manual fallback when the webhook misses — the frontend calls this after the buyer signs the EVM transaction directly. Coordinated through PaymentCoordinator to avoid double updates.
Auth required: Bearer JWT
Request body: { paymentId, transactionHash, network? }
Response 200: { success, message, data: { paymentId, transactionHash, status } }
Side effects: Closes the SHKeeper invoice session, then runs the same offer/request updates as the webhook.
POST /api/payment/shkeeper/test
Description: Smoke-tests the real SHKeeper API. Development only. Auth required: No
POST /api/payment/shkeeper/callback-test (and GET equivalent)
Description: Echo-style endpoints used during webhook configuration. Auth required: No
POST /api/payment/shkeeper/create-test-payment
Description: Inserts a sample Payment row to exercise the webhook handler. Auth required: No
POST /api/payment/shkeeper/trigger-webhook
Description: Sends a fake webhook payload to the local webhook endpoint for end-to-end testing. Auth required: Bearer JWT
GET /api/payment/shkeeper/wallet-monitor/status
Description: Returns the wallet-monitor state (isMonitoring, watched wallet addresses).
Auth required: No
GET /api/payment/shkeeper/auto-webhook/status
Description: Returns the auto-webhook fallback monitor state. Auth required: No
GET /api/payment/shkeeper/webhook-stats
Description: Counters for webhook deliveries (success / failure / duplicates). Auth required: Bearer JWT (admin)
Legacy SHKeeper - Release / Refund (escrow)
These build an admin-signed transaction off-chain and require a follow-up confirm with the broadcast tx hash. Source: shkeeperService.buildAdminSignedTxPayload and confirmAdminTx.
⚠️ Path correction: The /shkeeper/ segment is NOT present in the actual release/refund routes. The correct paths are under /api/payment/:id/… (not /api/payment/shkeeper/:id/…).
POST /api/payment/:id/release
Description: Prepares the admin-signed payload to release escrow to the seller. Returns the raw payload — the admin client signs and broadcasts.
Auth required: Bearer JWT (admin)
Response 200: { success: true, data: { /* tx payload */ } }
POST /api/payment/:id/release/confirm
Description: Records the broadcast transaction hash for the release; marks the payment as released, updates PurchaseRequest to seller_paid and emits purchase-request-update (type: payment_released).
Auth required: Bearer JWT (admin)
Request body: { txHash: string }
Errors: 400 missing txHash.
POST /api/payment/:id/refund
Description: Mirror of release, but returns the escrow to the buyer. Auth required: Bearer JWT (admin)
POST /api/payment/:id/refund/confirm
Description: Records the refund tx hash; emits purchase-request-update (type: payment_refunded).
Auth required: Bearer JWT (admin)
Request body: { txHash: string }
Legacy SHKeeper - Payouts
Historical payouts were SHKeeper-side outbound transfers. Current routine releases should use ledger-gated release/refund orchestration instead.
POST /api/payment/shkeeper/payout
Description: Create a payout task. The server creates a Payment row with direction: "out" and provider task id, then returns the SHKeeper task descriptor.
Auth required: Bearer JWT (admin)
Request body:
{
purchaseRequestId: string;
sellerOfferId: string;
buyerId: string;
sellerId: string;
amount: number;
recipientAddress: string;
token?: string; // default "USDT"
network?: string; // default "bsc"
metadata?: Record<string, unknown>;
}
Response 200: { success, data: { payoutId, taskId, status }, message }
Side effects: emitGlobalEvent('payout-created', { ... }).
Errors: 400 for each missing required field, 500 upstream error.
GET /api/payment/shkeeper/payout/status/:taskId
Description: Polls SHKeeper for the current task status.
Auth required: Bearer JWT
Response 200: { success, data: { /* status payload */ } }
POST /api/payment/shkeeper/payout/webhook
Description: SHKeeper webhook for payout state changes. Handled by processPayoutWebhookEvent. Emits payout-completed (or payout-updated) global socket events on success.
Auth required: No (signature checked)
Response 200/400: { success, message, data }
Legacy Web3 Wallet-Direct (DePay)
⚠️ NOT IMPLEMENTED:
POST /payment/depay/intents(createDePayIntent) does not exist in the codebase.
POST /api/payment/decentralized/save
Description: Persists a Web3-initiated payment record.
Auth required: Bearer JWT (enforces userId ownership match)
Request body:
{
purchaseRequestId: string;
buyerId: string;
sellerId?: string;
amount: number;
currency?: string;
transactionHash?: string;
network?: string;
token?: string;
walletAddress?: string;
metadata?: Record<string, unknown>;
}
GET /api/payment/decentralized/status/:paymentId
Description: Returns the latest status for a decentralized payment. Auth required: No
PUT /api/payment/decentralized/update
Description: Update a decentralized payment's status / confirmations.
Auth required: Bearer JWT (owner or admin)
Request body: { paymentId, status, confirmations? }
GET /api/payment/decentralized/receiver
Description: Returns the configured escrow receiver wallet address. Auth required: No
GET /api/payment/decentralized/history/:userId
Description: Decentralized payment history for a user. Auth required: Bearer JWT (self or admin)
POST /api/payment/decentralized/verify/:paymentId
Description: Re-verifies a single decentralized payment against the chain. paymentId is a path parameter as shown.
Auth required: Bearer JWT (owner or admin)
POST /api/payment/decentralized/verify-all-pending
Description: Iterates all pending decentralized payments and re-verifies them.
Auth required: Bearer JWT (admin only)
POST /api/payment/decentralized/admin-payout
Description: Pay a seller directly from an admin hot wallet. This bypasses the newer ledger-gated release/refund orchestration and should not be used for routine releases. Auth required: Bearer JWT (admin) Request body:
{
purchaseRequestId: string;
receiverWalletAddress: string;
amount: number;
currency?: string; // default "USDT"
network?: string; // default "BSC"
}
Response 200: { success, data: { /* payout receipt */ } }
Derived Destinations
These endpoints manage per-(buyer, sellerOffer) ephemeral payment addresses.
| Method | Route | Auth | Purpose |
|---|---|---|---|
GET |
/api/payment/derived-destinations |
Admin | List destinations with filters/pagination |
POST |
/api/payment/derived-destinations/sweep |
Admin | Sweep all active destinations |
POST |
/api/payment/derived-destinations/:id/sweep |
Admin | Sweep one destination |
POST |
/api/payment/derived-destinations/:id/balance |
Admin | Refresh on-chain balance for one destination |
GET |
/api/payment/derived-destinations/config/health |
Admin | Verify xpub and sweep signer config |
POST |
/api/payment/derived-destinations/cron/start |
Admin | Start the sweep cron |
POST |
/api/payment/derived-destinations/cron/stop |
Admin | Stop the sweep cron |
GET |
/api/payment/derived-destinations/cron/status |
Admin | Check if sweep cron is running |
GET /api/payment/derived-destinations
Query params: buyerId, sellerOfferId, status (active|swept), address, chainId, page, limit.
Response 200:
{
"success": true,
"data": {
"destinations": [
{
"_id": "...",
"buyerId": "...",
"sellerOfferId": "...",
"address": "0x...",
"derivationPath": "m/44'/60'/0'/0/5",
"derivationIndex": 5,
"chainId": 56,
"status": "active",
"balance": "1000000000",
"sweepCount": 0,
"totalSwept": "0",
"createdAt": "..."
}
],
"pagination": { "page": 1, "limit": 20, "total": 42 }
}
}
POST /api/payment/derived-destinations/sweep
Body: { chainId?: number, tokenSymbol?: string, minSweepAmount?: string } — all optional.
Response 200: { success: true, data: { results: SweepResult[] } }
Each SweepResult:
{
destinationId: string;
address: string;
status: 'success' | 'error' | 'skipped';
txHash?: string;
amount?: string;
error?: string;
}
POST /api/payment/derived-destinations/:id/sweep
Same result shape as above, but for a single destination.
GET /api/payment/derived-destinations/config/health
Response 200:
{
"success": true,
"data": {
"xpubValid": true,
"xpubFingerprint": "0xabcd...",
"signerType": "build-only",
"signerHealthy": true,
"chainId": 56,
"masterWallet": "0x..."
}
}
Frontend PaymentProvider type
src/types/payment.ts defines PaymentProvider as:
type PaymentProvider = 'request.network' | 'test' | 'other';
⚠️ Type gap (M37): Despite both SHKeeper and the legacy wallet-direct (DePay/decentralized) flows being active in production, neither
'shkeeper'nor'decentralized'appears in this union. Any frontend code that branches onproviderwill treat both as'other'or fall through a switch default. The backend stores the literal strings"shkeeper"and"decentralized"in the database; the mismatch exists only in the frontend type definition.
Status model
Payment uses the statuses below across all providers:
pending- intent created, awaiting on-chain settlementprocessing- settlement seen, awaiting confirmationsconfirmed- fully credited (intermediate; sometimes skipped). Note: this is the only status counted assuccessfulPaymentsinGET /api/payment/stats.completed- confirmed, escrow funded. Terminal state for SHKeeper and DePay. Not counted insuccessfulPaymentsstats — see stats undercounting note above.failed- intentionally failed (expired, declined, refused)cancelled- cancelled by user/adminreleased- escrow released to seller through the release/refund orchestration and custody signerrefunded- escrow returned to buyer
Escrow state (escrowState): unfunded → funded → released | refunded.
Confirmation thresholds (admin)
GET /api/admin/settings/confirmation-thresholds
Auth: Admin only
Response 200:
{
"success": true,
"data": [
{ "chainId": 56, "threshold": 12, "source": "default" },
{ "chainId": 1, "threshold": 3, "source": "config" }
]
}
PATCH /api/admin/settings/confirmation-thresholds/:chainId
Auth: Admin only
Body: { "threshold": 3 }
Description: Updates the runtime confirmation threshold for a chain. The in-memory cache is invalidated immediately so the next TransactionSafetyProvider evaluation uses the new value.
Response 200:
{
"success": true,
"message": "Confirmation threshold for chain 56 updated to 3",
"data": { "chainId": 56, "threshold": 3 }
}
GET /api/admin/settings/confirmation-thresholds/history
Auth: Admin only
Description: Returns paginated audit log of past confirmation threshold changes. Each entry records the admin who made the change, old/new threshold values, chain ID, and timestamp. Backed by the ConfigSettingHistory Mongoose model added in commit 27fb15a (task #9).
Response 200: { success: true, data: [{ chainId, oldThreshold, newThreshold, changedBy, changedAt }] }
Note: This endpoint was previously documented as NOT IMPLEMENTED. It was added in commit
27fb15aand is now live at/api/admin/settings/confirmation-thresholds/history.
Payments awaiting confirmation (admin)
GET /api/admin/payments/awaiting-confirmation
Auth: Admin only
Query: page, limit, chainId (optional)
Description: Lists payments that have an on-chain transaction hash but have not yet reached sufficient confirmations (i.e. metadata.transactionSafety.status === 'pending' or escrowState is not funded/released/refunded).
Response 200:
{
"success": true,
"data": [
{
"_id": "...",
"paymentId": "...",
"status": "pending",
"amount": { "amount": 12.5, "currency": "USDC" },
"blockchain": { "network": "bsc", "transactionHash": "0x...", "confirmations": 3 },
"metadata": { "transactionSafety": { "status": "pending", "checks": [...] } },
"createdAt": "2026-05-28T..."
}
],
"pagination": { "page": 1, "limit": 25, "total": 4, "totalPages": 1 }
}
Request Network multichain registry (admin)
GET /api/admin/rn/networks
Auth: Admin only
Response 200:
{
"success": true,
"data": [
{
"chainId": 56,
"name": "BNB Smart Chain",
"shortName": "BSC",
"rpcUrl": "https://bsc-dataseed.binance.org/",
"publicRpcUrl": "https://bsc-rpc.publicnode.com",
"blockExplorer": "https://bscscan.com",
"proxyAddress": "0x0DfbEe143b42B41eFC5A6F87bFD1fFC78c2f0aC9",
"nativeCurrency": { "name": "BNB", "symbol": "BNB", "decimals": 18 },
"confirmationThreshold": 12,
"tokens": [
{ "address": "0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d", "symbol": "USDC", "decimals": 18, "name": "Binance-Peg USD Coin" },
{ "address": "0x55d398326f99059ff775485246999027b3197955", "symbol": "USDT", "decimals": 18, "name": "Binance-Peg BSC-USD" }
]
}
],
"meta": { "chainCount": 5, "tokenCount": 10 }
}
POST /api/admin/rn/networks/reload
Auth: Admin only
Description: Reloads the chain and token registries from disk (supportedChains.json and tokens.json). Returns { success: true, message: 'Registry reloaded from disk' }. Use this after updating the JSON files without restarting the server.
Note: This route is now implemented (commit
5681abf). Earlier docs incorrectly listed it as not implemented.
POST /api/admin/rn/networks/probe/:chainId
Auth: Admin only
Description: Performs a live on-chain probe for the specified chain: verifies RPC reachability, checks for deployed proxy contract bytecode (eth_getCode), and test-calls the proxy with a dummy payload to confirm it reverts meaningfully. Returns:
{
"success": true,
"data": {
"chainId": 56,
"reachable": true,
"hasCode": true,
"callValid": true,
"blockNumber": "0x...",
"latencyMs": 120
}
}
Errors: 400 if chainId is not a number; 404 if the chain is not in the registry; 500 on RPC failure.
Note: This route is now implemented (commit
5681abf). Earlier docs incorrectly listed it as not implemented.