docs: AML scope note, human-blocked items, Task #11 pre-flight inventory
- Add AML scope note to Handoff - RN Multichain Probe (sanctions-only vs full KYT) - Add human-blocked section with 3 precise next steps for owner - Create Task 11 Pre-flight Inventory: library choice, dev/prod flow, admin UI gaps, backend gaps, risks, acceptance criteria
This commit is contained in:
@@ -5,12 +5,12 @@ tags: [api, dispute, reference]
|
||||
|
||||
# Dispute API
|
||||
|
||||
> [!warning] Not implemented
|
||||
> The Dispute module is **documented but not yet implemented** in the backend. There is no `backend/src/services/dispute/` directory, no `backend/src/routes/disputeRoutes.ts`, and no `/api/disputes` mount in `app.ts`. The API specification below reflects the *intended* design only.
|
||||
> [!note] Current implementation
|
||||
> The Dispute module now has a Mongoose model, controller routes, dashboard routes, and release-hold helper routes mounted under `/api/disputes`. Keep this page aligned with both `backend/src/routes/disputeRoutes.ts` and `backend/src/services/dispute/disputeRoutes.ts`.
|
||||
|
||||
Endpoints are planned to live under `/api/disputes/*`. The router would be `backend/src/routes/disputeRoutes.ts` and delegate to `DisputeController` (`backend/src/controllers/disputeController.ts`). The router would apply `authenticateToken` globally — every endpoint requires `Bearer JWT`.
|
||||
Endpoints live under `/api/disputes/*`. `backend/src/routes/disputeRoutes.ts` delegates to `DisputeController` (`backend/src/controllers/disputeController.ts`) for CRUD/triage. `backend/src/services/dispute/disputeRoutes.ts` provides lightweight release-hold endpoints (`raise`, `resolve`, `status`) used by escrow release gating. The routers apply `authenticateToken` globally — every endpoint requires `Bearer JWT`.
|
||||
|
||||
Model: [[Dispute]]. A dispute references a [[PurchaseRequest]] plus optional [[Payment]] and is the input to the mediation workflow that ends in either a `resolved_buyer` or `resolved_seller` decision and triggers an escrow release or refund via the [[Payment API]].
|
||||
Model: [[Dispute]]. A dispute references a [[PurchaseRequest]] plus optional [[Payment]] context and is the input to the mediation workflow that can lead to refund, replacement, compensation, warning/ban, or no-action. Release/refund execution should go through the ledger-gated [[Payment API]] and [[Payout Flow]].
|
||||
|
||||
## Create
|
||||
|
||||
@@ -34,6 +34,18 @@ Model: [[Dispute]]. A dispute references a [[PurchaseRequest]] plus optional [[P
|
||||
- Notifies the counter-party via `POST /api/notifications` (`new-notification` socket event).
|
||||
- Pauses any in-flight payout (sets a hold flag on the related [[Payment]]).
|
||||
|
||||
### POST /api/disputes/:purchaseRequestId/raise
|
||||
|
||||
**Description:** Lightweight release-hold endpoint that marks a purchase request and related payments as disputed.
|
||||
**Auth required:** Bearer JWT (buyer who owns the request or admin)
|
||||
**Request body:** `{ reason?: string }`
|
||||
**Response 200:** `{ success, message, data }`
|
||||
|
||||
### GET /api/disputes/:purchaseRequestId/status
|
||||
|
||||
**Description:** Returns release-hold flags for a purchase request, including whether release is currently blocked.
|
||||
**Auth required:** Bearer JWT (buyer, preferred seller, or admin)
|
||||
|
||||
## Read
|
||||
|
||||
### GET /api/disputes
|
||||
@@ -88,11 +100,17 @@ Model: [[Dispute]]. A dispute references a [[PurchaseRequest]] plus optional [[P
|
||||
```
|
||||
**Response 200:** `{ success, data: { dispute, paymentAction } }`
|
||||
**Side effects:**
|
||||
- `decision === "buyer"` → triggers `POST /api/payment/shkeeper/:id/refund` flow.
|
||||
- `decision === "seller"` → triggers `POST /api/payment/shkeeper/:id/release` flow.
|
||||
- `decision === "split"` → admin executes both partial release and partial refund manually.
|
||||
- `action === "refund"` → create/approve the corresponding refund instruction through the ledger-gated payment release/refund flow.
|
||||
- `action === "no_action"` or seller-favorable outcome → clear hold only after release checks pass.
|
||||
- split outcomes require explicit partial release/refund instructions.
|
||||
- Notifies both participants and updates [[PurchaseRequest]] status to `disputed_resolved`.
|
||||
|
||||
### POST /api/disputes/:purchaseRequestId/resolve
|
||||
|
||||
**Description:** Lightweight release-hold endpoint that clears the disputed hold flags on a purchase request and related payments.
|
||||
**Auth required:** Bearer JWT (admin)
|
||||
**Response 200:** `{ success, message, data }`
|
||||
|
||||
## Evidence and messages
|
||||
|
||||
### POST /api/disputes/:id/evidence
|
||||
|
||||
@@ -35,7 +35,7 @@ Uncaught errors are formatted by [`shared/middleware/errorHandler.ts`](../../bac
|
||||
}
|
||||
```
|
||||
|
||||
Legacy routes (chiefly `/api/users` legacy paths, `/api/marketplace` legacy paths, `/api/payment/decentralized/*`, parts of `/api/payment/shkeeper/*`) return ad-hoc shapes such as `{ "error": "..." }` or `{ "success": false, "message": "..." }`. Treat any non-`2xx` response as an error and read whichever of `error` / `message` is present.
|
||||
Legacy routes (chiefly `/api/users` legacy paths, `/api/marketplace` legacy paths, and `/api/payment/decentralized/*`) return ad-hoc shapes such as `{ "error": "..." }` or `{ "success": false, "message": "..." }`. Treat any non-`2xx` response as an error and read whichever of `error` / `message` is present.
|
||||
|
||||
## HTTP status mapping
|
||||
|
||||
@@ -43,7 +43,7 @@ Legacy routes (chiefly `/api/users` legacy paths, `/api/marketplace` legacy path
|
||||
| --- | --- | --- |
|
||||
| `200 OK` | Successful read or mutation | Most `GET`s, idempotent `PUT`s/`PATCH`s |
|
||||
| `201 Created` | Resource created | `POST /api/marketplace/purchase-requests`, `POST /api/auth/register` (when user created), `POST /api/marketplace/reviews` |
|
||||
| `202 Accepted` | Async accepted (provider webhooks) | SHKeeper webhook acknowledgement |
|
||||
| `202 Accepted` | Async accepted (provider webhooks) | Request Network webhook accepted while safety checks are pending |
|
||||
| `204 No Content` | Mutations with no body to return | Rare — most endpoints return the updated object |
|
||||
| `400 Bad Request` | Validation failure, malformed input | `express-validator` errors, bad MongoIds, missing fields |
|
||||
| `401 Unauthorized` | Missing or invalid JWT | `Access token required`, `Invalid or expired token` |
|
||||
@@ -53,7 +53,7 @@ Legacy routes (chiefly `/api/users` legacy paths, `/api/marketplace` legacy path
|
||||
| `423 Locked` | Account temporarily locked | After repeated failed logins (Redis-tracked) |
|
||||
| `429 Too Many Requests` | Rate limit hit | Currently issued only by per-feature Redis limits (auth / AI); global limiter is disabled |
|
||||
| `500 Internal Server Error` | Unhandled exception | Caught by `errorHandler`; included stack trace in dev |
|
||||
| `502 Bad Gateway` | Upstream provider failure | OpenAI / SHKeeper unreachable |
|
||||
| `502 Bad Gateway` | Upstream provider failure | OpenAI / Request Network unreachable |
|
||||
|
||||
## Application error codes
|
||||
|
||||
@@ -89,11 +89,10 @@ Handled in `errorHandler`:
|
||||
|
||||
| Provider | Endpoint | Status on success | Status on signature mismatch |
|
||||
| --- | --- | --- | --- |
|
||||
| SHKeeper pay-in | `POST /api/payment/shkeeper/webhook` | 200 `{ success: true }` | 401 `{ success: false }` (then ignored) |
|
||||
| SHKeeper payout | `POST /api/payment/shkeeper/payout/webhook` | 200 / 400 with `{ success, message, data }` | 400 |
|
||||
| Request Network pay-in | `POST /api/payment/request-network/webhook` | 200 `{ success: true }` or 202 while safety checks are pending | 401 `{ success: false }` |
|
||||
| Generic payment callback | `POST /api/payment/callback` | 200 `{ success: true, message }` | 400 |
|
||||
|
||||
If a webhook is acknowledged with non-2xx, the provider re-delivers (SHKeeper retries every 60 seconds).
|
||||
If a webhook is acknowledged with non-2xx, the provider may re-deliver. Persisting delivery evidence and replay support is a launch-hardening item in [[Request Network Integration Constraints]].
|
||||
|
||||
## Client guidance
|
||||
|
||||
|
||||
@@ -1,19 +1,21 @@
|
||||
---
|
||||
title: Payment API
|
||||
tags: [api, payment, reference, shkeeper]
|
||||
tags: [api, payment, reference, request-network, escrow]
|
||||
---
|
||||
|
||||
# Payment API
|
||||
|
||||
The payment surface is split across four routers, all mounted under `/api/payment/*`:
|
||||
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`](../../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 |
|
||||
| `/api/payment/request-network/*` | [`requestNetwork/requestNetworkRoutes.ts`](../../backend/src/services/payment/requestNetwork/requestNetworkRoutes.ts) | Request Network intent creation, in-house checkout payloads, webhook processing |
|
||||
| `/api/payment/derived-destinations/*` | [`wallets/derivedDestinationRoutes.ts`](../../backend/src/services/payment/wallets/derivedDestinationRoutes.ts) | Derived destination inspection, balance checks, and sweeping |
|
||||
| `/api/payment/decentralized/*` | [`decentralizedPaymentRoutes.ts`](../../backend/src/services/payment/decentralizedPaymentRoutes.ts) | Legacy wallet-direct confirmations |
|
||||
| `/api/admin/rn/networks/*` | [`requestNetwork/networkRegistryRoutes.ts`](../../backend/src/services/payment/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`.
|
||||
|
||||
@@ -21,7 +23,7 @@ Core model: [[Payment]]. Coordination logic to avoid race conditions when multip
|
||||
|
||||
### POST /api/payment/configuration
|
||||
|
||||
**Description:** Returns the payment provider configuration the SHKeeper widget needs (accepted blockchains, escrow receiver address, redirect URLs, webhook URL).
|
||||
**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:**
|
||||
@@ -29,7 +31,7 @@ Core model: [[Payment]]. Coordination logic to avoid race conditions when multip
|
||||
{
|
||||
"accept": [{ "blockchain": "bsc", "token": "0x55d3...", "receiver": "0xa30..." }],
|
||||
"redirect": { "success": "...", "cancel": "..." },
|
||||
"webhook": "https://.../api/payment/shkeeper/webhook"
|
||||
"webhook": "https://.../api/payment/request-network/webhook"
|
||||
}
|
||||
```
|
||||
|
||||
@@ -37,18 +39,18 @@ Core model: [[Payment]]. Coordination logic to avoid race conditions when multip
|
||||
|
||||
**Description:** Lightweight health probe.
|
||||
**Auth required:** No
|
||||
**Response 200:** `{ success, message, endpoints: { shkeeper, decentralized, health } }`
|
||||
**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:** Same payload as `/configuration` but tailored for the SHKeeper-hosted widget; includes explicit CORS `*` headers.
|
||||
**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 (manual entry — usually the SHKeeper intent path is preferred).
|
||||
**Description:** Create a payment record manually. Normal buyer checkout should use `POST /api/payment/request-network/intents`.
|
||||
**Auth required:** Bearer JWT
|
||||
**Request body:**
|
||||
```ts
|
||||
@@ -139,10 +141,44 @@ Core model: [[Payment]]. Coordination logic to avoid race conditions when multip
|
||||
|
||||
### POST /api/payment/verify
|
||||
|
||||
**Description:** Frontend verification endpoint used by the Web3 flow. Confirms a payment and updates the related [[PurchaseRequest]].
|
||||
**Description:** Legacy frontend verification endpoint used by the wallet-direct Web3 flow. Confirms a payment and updates the related [[PurchaseRequest]].
|
||||
**Auth required:** Bearer JWT
|
||||
|
||||
## SHKeeper - Pay-in
|
||||
## Request Network - Pay-in
|
||||
|
||||
### POST /api/payment/request-network/intents
|
||||
|
||||
**Description:** Creates a 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.
|
||||
**Auth required:** Bearer JWT (buyer)
|
||||
**Request body:**
|
||||
```ts
|
||||
{
|
||||
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, ... } }`
|
||||
|
||||
### 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.
|
||||
|
||||
## Legacy SHKeeper - Pay-in
|
||||
|
||||
> [!warning] Historical route family
|
||||
> The current `app.ts` mounts Request Network routes, not `services/payment/shkeeper/*`. Keep this section only for legacy record migration and old operational context.
|
||||
|
||||
### POST /api/payment/shkeeper/intents
|
||||
|
||||
@@ -230,7 +266,7 @@ Core model: [[Payment]]. Coordination logic to avoid race conditions when multip
|
||||
**Description:** Counters for webhook deliveries (success / failure / duplicates).
|
||||
**Auth required:** Bearer JWT (admin)
|
||||
|
||||
## SHKeeper - Release / Refund (escrow)
|
||||
## 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`.
|
||||
|
||||
@@ -258,9 +294,9 @@ These build an admin-signed transaction off-chain and require a follow-up confir
|
||||
**Auth required:** Bearer JWT (admin)
|
||||
**Request body:** `{ txHash: string }`
|
||||
|
||||
## SHKeeper - Payouts
|
||||
## Legacy SHKeeper - Payouts
|
||||
|
||||
Payouts are SHKeeper-side outbound transfers (admin pays the seller from a hot wallet).
|
||||
Historical payouts were SHKeeper-side outbound transfers. Current routine releases should use ledger-gated release/refund orchestration instead.
|
||||
|
||||
### POST /api/payment/shkeeper/payout
|
||||
|
||||
@@ -296,7 +332,7 @@ Payouts are SHKeeper-side outbound transfers (admin pays the seller from a hot w
|
||||
**Auth required:** No (signature checked)
|
||||
**Response 200/400:** `{ success, message, data }`
|
||||
|
||||
## DePay / Web3 (decentralized)
|
||||
## Legacy Web3 Wallet-Direct
|
||||
|
||||
### POST /api/payment/decentralized/save
|
||||
|
||||
@@ -351,7 +387,7 @@ Payouts are SHKeeper-side outbound transfers (admin pays the seller from a hot w
|
||||
|
||||
### POST /api/payment/decentralized/admin-payout
|
||||
|
||||
**Description:** Pay a seller directly from an admin hot wallet (no SHKeeper).
|
||||
**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:**
|
||||
```ts
|
||||
@@ -459,7 +495,7 @@ Same result shape as above, but for a single destination.
|
||||
- `completed` - confirmed, escrow funded
|
||||
- `failed` - intentionally failed (expired, declined, refused)
|
||||
- `cancelled` - cancelled by user/admin
|
||||
- `released` - escrow released to seller (`shkeeper` flow)
|
||||
- `released` - escrow released to seller through the release/refund orchestration and custody signer
|
||||
- `refunded` - escrow returned to buyer
|
||||
|
||||
Escrow state (`escrowState`): `unfunded` → `funded` → `released` | `refunded`.
|
||||
@@ -558,7 +594,7 @@ Escrow state (`escrowState`): `unfunded` → `funded` → `released` | `refunded
|
||||
|
||||
## Related
|
||||
|
||||
- [[Payment Flow]]
|
||||
- [[Escrow Flow]]
|
||||
- [[SHKeeper Webhook Flow]]
|
||||
- [[Request Network Integration Constraints]]
|
||||
- [[Payout Flow]]
|
||||
- [[Socket Events]]
|
||||
|
||||
@@ -5,7 +5,7 @@ tags: [api, payments, trezor, safekeeping]
|
||||
|
||||
# Trezor API
|
||||
|
||||
The Trezor API is mounted at `/api/trezor`. It is optional support for hardware-backed safekeeping and does not replace SHKeeper or Request Network.
|
||||
The Trezor API is mounted at `/api/trezor`. It is optional support for hardware-backed safekeeping and does not replace Request Network checkout, the funds ledger, or the broader Safe/multisig custody roadmap.
|
||||
|
||||
Enforcement is controlled by:
|
||||
|
||||
|
||||
Reference in New Issue
Block a user