13 KiB
title, tags
| title | tags | ||||
|---|---|---|---|---|---|
| Payment API |
|
Payment API
The payment surface is split across four routers, all mounted under /api/payment/*:
| 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/decentralized/* |
decentralizedPaymentRoutes.ts |
DePay / Web3 confirmations |
/api/payment/shkeeper/* |
shkeeper/shkeeperRoutes.ts |
SHKeeper pay-in, webhook, release/refund |
/api/payment/shkeeper/payout* |
shkeeper/shkeeperPayoutRoutes.ts |
SHKeeper payouts to sellers |
Core model: Payment. Coordination logic to avoid race conditions when multiple sources update the same payment is in paymentCoordinator.ts.
Configuration / health
POST /api/payment/configuration
Description: Returns the payment provider configuration the SHKeeper widget needs (accepted blockchains, escrow receiver address, redirect URLs, webhook URL).
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/shkeeper/webhook"
}
GET /api/payment/health
Description: Lightweight health probe.
Auth required: No
Response 200: { success, message, endpoints: { shkeeper, decentralized, health } }
GET /api/payment/shkeeper/config
Description: Same payload as /configuration but tailored for the SHKeeper-hosted widget; includes explicit CORS * headers.
Auth required: No
Payment records (CRUD)
POST /api/payment
Description: Create a payment record (manual entry — usually the SHKeeper intent path is preferred). 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.
Auth required: Bearer JWT
Errors: 404 not found.
GET /api/payment/:id/debug
Description: Debug bundle including the raw payment, blockchain metadata, and wallet-monitor status. Auth required: Bearer JWT Notes: Intended for admin / development.
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
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
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
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
Request body: { limit?: number } (default 10)
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: Frontend verification endpoint used by the Web3 flow. Confirms a payment and updates the related PurchaseRequest. Auth required: Bearer JWT
SHKeeper - Pay-in
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). - 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.
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)
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.
POST /api/payment/shkeeper/: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/shkeeper/: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/shkeeper/:id/refund
Description: Mirror of release, but returns the escrow to the buyer. Auth required: Bearer JWT (admin)
POST /api/payment/shkeeper/: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 }
SHKeeper - Payouts
Payouts are SHKeeper-side outbound transfers (admin pays the seller from a hot wallet).
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 }
DePay / Web3 (decentralized)
POST /api/payment/decentralized/save
Description: Persists a Web3-initiated payment record. Auth required: No 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: No
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: No
POST /api/payment/decentralized/verify/:paymentId
Description: Re-verifies a single decentralized payment against the chain. Auth required: No
POST /api/payment/decentralized/verify-all-pending
Description: Iterates all pending decentralized payments and re-verifies them.
Auth required: No (typically called by a cron)
POST /api/payment/decentralized/admin-payout
Description: Pay a seller directly from an admin hot wallet (no SHKeeper). 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 */ } }
Status model
Payment uses the statuses below across all providers:
pending- intent created, awaiting on-chain settlementprocessing- settlement seen, awaiting confirmationscompleted- confirmed, escrow fundedfailed- intentionally failed (expired, declined, refused)cancelled- cancelled by user/adminreleased- escrow released to seller (shkeeperflow)refunded- escrow returned to buyer
Escrow state (escrowState): unfunded → funded → released | refunded.