--- title: Payment API tags: [api, payment, reference, shkeeper] --- # Payment API The payment surface is split across four routers, all mounted under `/api/payment/*`: | Path prefix | File | Purpose | | --- | --- | --- | | `/api/payment/*` | [`paymentControllerRoutes.ts`](../../backend/src/services/payment/paymentControllerRoutes.ts) | New controller pattern (CRUD + configuration) | | `/api/payment/*` | [`paymentRoutes.ts`](../../backend/src/services/payment/paymentRoutes.ts) | Additional legacy endpoints (tx fetch, exports) | | `/api/payment/decentralized/*` | [`decentralizedPaymentRoutes.ts`](../../backend/src/services/payment/decentralizedPaymentRoutes.ts) | DePay / Web3 confirmations | | `/api/payment/shkeeper/*` | [`shkeeper/shkeeperRoutes.ts`](../../backend/src/services/payment/shkeeper/shkeeperRoutes.ts) | SHKeeper pay-in, webhook, release/refund | | `/api/payment/shkeeper/payout*` | [`shkeeper/shkeeperPayoutRoutes.ts`](../../backend/src/services/payment/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:** ```json { "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:** ```ts { purchaseRequestId: string; sellerOfferId: string; buyerId: string; sellerId: string; amount: { amount: number; currency: string }; blockchain?: { network: string; token: string }; metadata?: Record; } ``` **Response 201:** `{ /* Payment document */ }` ### PUT /api/payment/:id **Description:** Update a payment record (status, transactionHash, metadata). **Auth required:** Bearer JWT **Request body:** ```ts { status?: "pending" | "processing" | "completed" | "failed" | "cancelled"; transactionHash?: string; blockchain?: { ... }; metadata?: Record; } ``` ### 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:** ```ts { purchaseRequestId: string; sellerOfferId: string; amount: number; sellerId: string; token?: string; // default "USDT" network?: string; // default "bsc" metadata?: Record; } ``` **Response 200:** ```json { "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` (`OVERPAID` and `PAID` both count). - Releases or rejects [[SellerOffer]] siblings (the chosen offer becomes `accepted`, others `rejected`). - Updates [[PurchaseRequest]] status to `payment` / `processing`. - Emits `seller-offer-update` to each affected seller room and `purchase-request-update` to 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:** ```ts { purchaseRequestId: string; sellerOfferId: string; buyerId: string; sellerId: string; amount: number; recipientAddress: string; token?: string; // default "USDT" network?: string; // default "bsc" metadata?: Record; } ``` **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:** Bearer JWT (enforces `userId` ownership match) **Request body:** ```ts { purchaseRequestId: string; buyerId: string; sellerId?: string; amount: number; currency?: string; transactionHash?: string; network?: string; token?: string; walletAddress?: string; metadata?: Record; } ``` ### 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. **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 (no SHKeeper). **Auth required:** Bearer JWT (admin) **Request body:** ```ts { 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 settlement - `processing` - settlement seen, awaiting confirmations - `confirmed` - fully credited (intermediate; sometimes skipped) - `completed` - confirmed, escrow funded - `failed` - intentionally failed (expired, declined, refused) - `cancelled` - cancelled by user/admin - `released` - escrow released to seller (`shkeeper` flow) - `refunded` - escrow returned to buyer Escrow state (`escrowState`): `unfunded` → `funded` → `released` | `refunded`. ## Related - [[Payment Flow]] - [[Escrow Flow]] - [[SHKeeper Webhook Flow]] - [[Socket Events]]