https://{your-orchestrator-domain}/api/v1Complete REST API reference for OFFER-HUB — endpoints, parameters, and response schemas.
The OFFER-HUB Orchestrator exposes a RESTful JSON API. All endpoints are prefixed with /api/v1.
For local development:
All requests require authentication via a Bearer token (API Key).
Create an API key using your master key:
Response:
Save the api_key value immediately - it's only shown once!
| Scope | Permissions |
|---|---|
read | All GET endpoints |
write | POST to create/modify resources |
support | Resolve disputes, add comments |
| Header | Required | Description |
|---|---|---|
Authorization | Yes | Bearer {api_key} |
Content-Type | Yes (POST/PUT/PATCH) | application/json |
Idempotency-Key | Optional | UUID v4 for POST, PUT, and PATCH requests |
X-Request-ID | No | UUID for correlation/debugging |
| Header | Description |
|---|---|
X-Request-ID | Echo of request ID or auto-generated |
X-Idempotency-Key | Echo of key if applied |
X-RateLimit-Limit | Request limit |
X-RateLimit-Remaining | Remaining requests |
X-RateLimit-Reset | Reset timestamp |
| Code | HTTP | When to Use |
|---|---|---|
VALIDATION_ERROR | 400 | Invalid fields in request |
UNAUTHORIZED | 401 | Missing or invalid API key |
INSUFFICIENT_SCOPE | 403 | API key lacks required scope |
USER_NOT_FOUND | 404 | User does not exist |
ORDER_NOT_FOUND | 404 | Order does not exist |
INVALID_STATE | 409 | Invalid state transition |
IDEMPOTENCY_KEY_REUSED | 409 | Same key with different body |
INSUFFICIENT_FUNDS | 422 | Balance too low |
RATE_LIMITED | 429 | Too many requests |
PROVIDER_TIMEOUT | 504 | External provider timeout |
The summaries on this page cover the API surface at a glance. The endpoint groups below have dedicated pages with real DTO fields, signer roles, valid state transitions, error codes, and cURL plus TypeScript SDK examples:
| Page | Endpoints | Source in the Orchestrator repo |
|---|---|---|
| Escrow Endpoints | POST /orders/{id}/escrow, POST /orders/{id}/escrow/fund | apps/api/src/modules/orders/orders.controller.ts |
| Resolution Endpoints | POST /orders/{orderId}/resolution/release, /refund, /dispute | apps/api/src/modules/resolution/resolution.controller.ts |
| Inbound Webhooks | POST /webhooks/airtm, POST /webhooks/trustless-work | apps/api/src/modules/webhooks/webhooks.controller.ts |
| Events (SSE) | GET /events plus the event catalog | apps/api/src/modules/events/events.controller.ts |
Escrow contracts hold funds securely between buyers and sellers until project completion. The two creation and funding calls are documented end to end in Escrow Endpoints; the three settlement calls are in Resolution Endpoints.
POST /api/v1/orders/{id}/escrow
Creates a new escrow contract between buyer and seller. Funds are held until release. See Escrow Endpoints for parameters, contract roles, and the full response schema.
Request Body
| Parameter | Type | Required | Description |
|---|---|---|---|
amount | string | Yes | Amount to escrow |
currency | string | Yes | Currency code (USD, XLM, USDC) |
Response
POST /api/v1/orders/{id}/escrow/fund
Funds an existing escrow contract. See Escrow Endpoints for the reserved-balance debit, contract-type selection, and error codes.
Returns 422 INSUFFICIENT_FUNDS if the buyer has insufficient balance.
POST /api/v1/orders/{id}/resolution/release
Releases held funds from an escrow to the seller upon project completion. See Resolution Endpoints for the three on-chain steps and their signer roles.
Response
POST /api/v1/orders/{id}/resolution/refund
Refunds escrowed funds back to the buyer. See Resolution Endpoints for the two-step dispute-then-resolve flow.
POST /api/v1/orders/{id}/resolution/dispute
Opens a dispute on an escrow for resolution. See Resolution Endpoints for the OpenDisputeDto fields and how a dispute is later resolved.
Retrieve user transaction and balance history.
GET /api/v1/users/{id}/balance
Returns the user's current balance across all currencies.
curl -X GET http://localhost:4000/api/v1/users/usr_abc/balance -H "Authorization: Bearer TOKEN"Response
| Field | Type | Description |
|---|---|---|
currency | string | Currency code |
available | string | Spendable balance |
held | string | Balance locked in escrows |
GET /api/v1/users/{id}/wallet/deposit
Returns a deposit address for the user to fund their account.
Subscribers consume real-time domain events over the SSE event stream at GET /api/v1/events. Separately, the Orchestrator receives inbound webhooks from external providers (Airtm, Trustless Work) to process payment and escrow lifecycle events — see the Inbound Webhooks reference for signature verification and deduplication behavior.
POST /api/v1/withdrawals
Initiate a withdrawal from user balance.
Request Body
| Parameter | Type | Required | Description |
|---|---|---|---|
user_id | string | Yes | User requesting withdrawal |
amount | string | Yes | Amount to withdraw |
currency | string | Yes | Currency code |
destination | object | Yes | Withdrawal destination |
GET /api/v1/withdrawals/{id}
Returns withdrawal status and details.
List endpoints support cursor-based pagination:
| Param | Default | Max | Description |
|---|---|---|---|
limit | 20 | 100 | Items per page |
cursor | - | - | ID of last item from previous page |
List endpoints accept query parameter filters:
| Filter | Type | Example |
|---|---|---|
status | string | IN_PROGRESS |
buyer_id | string | usr_abc123 |
seller_id | string | usr_xyz789 |
created_after | ISO date | 2026-01-01T00:00:00Z |
created_before | ISO date | 2026-01-31T23:59:59Z |
Idempotency-Key is optional and is processed on POST, PUT, and PATCH
requests. When supplied, it must be a UUID v4 and is scoped to the API key and
request body. The guard and response lifecycle are implemented in the
orchestrator IdempotencyGuard
and
IdempotencyInterceptor.
Use a real UUID v4 for every request key:
400 VALIDATION_ERROR; the key must be a UUID v4.Idempotency-Replay: true.409 IDEMPOTENCY_KEY_REUSED.409 IDEMPOTENCY_KEY_IN_PROGRESS.Example for a reused key:
Example while the original request is still running:
Keys are retained for 24 hours. Reuse after that period is treated as a new request.
The API applies one global limit of 100 requests per 60-second window. The
counter is keyed by API key when authenticated, or by client IP when no API key
is available. There are no additional per-endpoint limits documented here.
The headers and error payload are implemented in the orchestrator
RateLimitGuard.
Every response includes:
| Header | Meaning |
|---|---|
X-RateLimit-Limit | Maximum requests in the current window (100) |
X-RateLimit-Remaining | Requests remaining in the current window |
X-RateLimit-Reset | Unix timestamp when the window expires |
Every entry below was verified against the real controllers in apps/api/src/modules. All paths are relative to the /api/v1 prefix.
| Endpoint | Method | Description |
|---|---|---|
/auth/api-keys | POST | Create API key |
/auth/api-keys | GET | List API keys |
/auth/api-keys/{id}/token | POST | Generate short-lived token |
/auth/me | GET | Current auth context |
| Endpoint | Method | Description |
|---|---|---|
/config | GET | Platform configuration (public) |
| Endpoint | Method | Description |
|---|---|---|
/health | GET | Basic health check (public) |
/health/detailed | GET | Detailed health check (public) |
| Endpoint | Method | Description |
|---|---|---|
/users | POST | Create user |
/users/{id}/airtm/link | POST | Link Airtm account |
All balance endpoints are scoped to a user: /users/{userId}/balance.
| Endpoint | Method | Description |
|---|---|---|
/users/{userId}/balance | GET | Get user balance |
/users/{userId}/balance/credit | POST | Credit available balance |
/users/{userId}/balance/debit | POST | Debit available balance |
/users/{userId}/balance/reserve | POST | Reserve funds |
/users/{userId}/balance/release | POST | Release reserved funds |
/users/{userId}/balance/cancel-reservation | POST | Cancel reservation |
/users/{userId}/balance/deduct-reserved | POST | Deduct from reserved |
/users/{userId}/balance/sync | POST | Sync with provider |
/users/{userId}/balance/verify | GET | Verify with provider |
Wallet endpoints are scoped to a user: /users/{userId}/wallet.
| Endpoint | Method | Description |
|---|---|---|
/users/{userId}/wallet | GET | Get wallet info |
/users/{userId}/wallet/deposit | GET | Get deposit address |
/users/{userId}/wallet/transactions | GET | Transaction history |
| Endpoint | Method | Description |
|---|---|---|
/topups | POST | Create top-up |
/topups | GET | List top-ups |
/topups/{id} | GET | Get top-up |
/topups/{id}/refresh | POST | Refresh status from Airtm |
/topups/{id}/cancel | POST | Cancel top-up |
/topups/{id}/callback | GET | Airtm callback (public) |
| Endpoint | Method | Description |
|---|---|---|
/orders | POST | Create order |
/orders | GET | List orders |
/orders/{id} | GET | Get order |
/orders/{id}/reserve | POST | Reserve funds |
/orders/{id}/cancel | POST | Cancel order |
/orders/{id}/milestones | GET | Get milestones |
/orders/{id}/milestones/{ref}/complete | POST | Complete milestone |
| Endpoint | Method | Description |
|---|---|---|
/orders/{id}/escrow | POST | Create escrow contract |
/orders/{id}/escrow/fund | POST | Fund escrow |
| Endpoint | Method | Description |
|---|---|---|
/orders/{id}/resolution/release | POST | Release to seller |
/orders/{id}/resolution/refund | POST | Refund to buyer |
/orders/{id}/resolution/dispute | POST | Open dispute |
| Endpoint | Method | Description |
|---|---|---|
/disputes | GET | List disputes |
/disputes/{id} | GET | Get dispute |
/disputes/{id}/assign | POST | Assign to agent |
/disputes/{id}/resolve | POST | Resolve dispute |
| Endpoint | Method | Description |
|---|---|---|
/withdrawals | POST | Create withdrawal |
/withdrawals | GET | List withdrawals |
/withdrawals/{id} | GET | Get withdrawal |
/withdrawals/{id}/commit | POST | Commit withdrawal |
/withdrawals/{id}/refresh | POST | Refresh status from Airtm |
| Endpoint | Method | Description |
|---|---|---|
/events | GET | SSE event stream |
| Endpoint | Method | Description |
|---|---|---|
/webhooks/airtm | POST | Receive Airtm webhooks |
/webhooks/trustless-work | POST | Receive Trustless Work webhooks |
| Endpoint | Method | Description |
|---|---|---|
/audit/logs | GET | List audit entries |
The API uses path versioning:
v1 is the current stable version