Base URL: http://localhost:3000 (local) or your deployed backend.
All request bodies are JSON (Content-Type: application/json).
All responses are JSON.
Machine-readable spec: A Swagger/OpenAPI 3.0 spec is served at
GET /api-docs/swagger.json(raw JSON) andGET /api-docs(interactive Swagger UI).Rate limits: All endpoints are subject to per-IP rate limiting. See docs/rate-limits.md for default limits, configuration, and the 429 response shape.
Returns service health status.
Response 200
{ "status": "ok" }Checks Soroban RPC reachability and current ledger.
Response 200
{
"rpc": "reachable",
"network": "mainnet",
"ledger": 54321678
}| Status | Description |
|---|---|
503 |
Soroban RPC unreachable |
500 |
Unexpected server error |
Fetch the on-chain status of an invoice by its numeric ID.
| Parameter | Type | Description |
|---|---|---|
id |
string | Positive integer string |
Response 200
{
"invoice_id": "42",
"status": "Pending"
}| Status | Description |
|---|---|
400 |
id is not a positive integer |
404 |
Invoice not found on-chain |
503 |
Missing required environment variables |
500 |
Unexpected server error |
Create a new invoice by submitting create_invoice to the Soroban RPC.
{
"merchant_address": "G...",
"token": "USDC",
"amount": 1000000,
"due_date": 1720000000
}| Field | Type | Description |
|---|---|---|
merchant_address |
string | Valid Stellar public key (G…) |
token |
string | Token identifier |
amount |
number | Positive number (in stroops / smallest unit) |
due_date |
number | Future Unix timestamp (seconds) for the due date |
Response 201
{
"invoice_id": "1",
"status": "Pending"
}| Status | Description |
|---|---|
400 |
Validation error — see error field for detail |
422 |
Soroban simulation or transaction failure |
503 |
Missing required environment variables |
504 |
Transaction confirmation timeout |
500 |
Unexpected server error |
Raise a dispute linked to a settlement, transitioning it to OnHold.
{
"claimant_address": "G...",
"settlement_id": "5",
"reason": "Goods not delivered"
}| Field | Type | Required | Description |
|---|---|---|---|
claimant_address |
string | Yes | Valid Stellar public key of the disputing party |
settlement_id |
string | Yes | Positive integer string identifying settlement |
reason |
string | No | Human-readable reason for the dispute |
Response 201
{
"dispute_id": "5-1720000000000",
"settlement_id": "5",
"claimant_address": "G...",
"status": "Raised",
"settlement_status": "OnHold"
}| Status | Description |
|---|---|
400 |
Validation error — see error field for detail |
503 |
Missing required environment variables |
500 |
Unexpected server error |
Returns all settlements with Pending status from the indexed database.
Response 200
[
{
"id": 1,
"merchant_address": "G...",
"amount": "5000000",
"approvals": ["G..."],
"approval_weight": 1,
"status": "Pending",
"hold_reason": null
}
]| Status | Description |
|---|---|
500 |
Database error |
Approve a pending settlement by submitting approve_settlement to the treasury contract.
{ "settlement_id": 1 }| Field | Type | Description |
|---|---|---|
settlement_id |
number | Positive integer settlement ID |
Response 200
{
"id": 1,
"merchant_address": "G...",
"amount": "5000000",
"approvals": ["G..."],
"approval_weight": 2,
"status": "Pending",
"hold_reason": null,
"tx_hash": "abc123..."
}| Status | Description |
|---|---|
400 |
settlement_id is not a positive integer |
503 |
Missing required environment variables |
500 |
Unexpected server error |
Execute a fully-approved settlement after verifying the treasury USDC balance.
{
"settlement_id": 1,
"token_contract": "C..."
}| Field | Type | Required | Description |
|---|---|---|---|
settlement_id |
number | Yes | Positive integer settlement ID |
token_contract |
string | No | Token contract address — defaults to USDC_CONTRACT_ID env var |
Response 200
{
"tx_hash": "abc123...",
"settlement_id": 1,
"balance_checked": "10000000",
"amount_required": "5000000"
}| Status | Description |
|---|---|
400 |
settlement_id is not a positive integer |
409 |
Settlement is not in Pending status |
422 |
Insufficient treasury balance or simulation failure |
503 |
Missing required environment variables |
500 |
Unexpected server error |
Returns the current approval threshold from the treasury contract.
Response 200
{ "threshold": 2 }| Status | Description |
|---|---|
422 |
Soroban simulation failure |
503 |
Missing required environment variables |
500 |
Unexpected server error |
Update the treasury approval threshold.
{ "threshold": 3 }| Field | Type | Description |
|---|---|---|
threshold |
number | Positive integer ≥ 1 |
Response 200
{
"threshold": 3,
"tx_hash": "abc123..."
}| Status | Description |
|---|---|
400 |
threshold is not a positive integer |
422 |
Soroban simulation or transaction failure |
503 |
Missing required environment variables |
500 |
Unexpected server error |
Returns all settlements that are currently on hold. A hold is placed when a signer flags a settlement as requiring manual review before execution can proceed.
Query parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
page |
number | No | Page number (1-based, default: 1) |
limit |
number | No | Results per page (default: 20, max: 100) |
Response 200
{
"settlements": [
{
"id": 7,
"merchant_address": "G...",
"amount": "5000000",
"approvals": [],
"approval_weight": 0,
"status": "OnHold",
"hold_reason": "Merchant KYC under review"
}
]
}| Status | Description |
|---|---|
500 |
Database error |
Releases a held settlement, restoring it to Pending so the normal approval and
execution flow can resume. Calls release_hold on the treasury contract.
See also: release_hold in the Contract Interaction Guide.
{ "settlement_id": 7 }| Field | Type | Description |
|---|---|---|
settlement_id |
number | Positive integer settlement ID |
Response 200
{
"id": 7,
"merchant_address": "G...",
"amount": "5000000",
"approvals": [],
"approval_weight": 0,
"status": "Pending",
"hold_reason": null,
"tx_hash": "abc123..."
}| Status | Description |
|---|---|
400 |
settlement_id is not a positive integer |
409 |
Settlement is not currently on hold |
422 |
Soroban simulation or transaction failure |
503 |
Missing required environment variables |
500 |
Unexpected server error |
Escalates a held settlement to the on-chain dispute-resolution flow.
Calls raise_dispute on the treasury contract and begins a multi-sig governance
vote among the configured signers.
See also: raise_dispute in the Contract Interaction Guide.
{
"settlement_id": 7,
"reason": "Merchant disputes the invoice amount"
}| Field | Type | Required | Description |
|---|---|---|---|
settlement_id |
number | Yes | Positive integer settlement ID |
reason |
string | No | Human-readable reason for escalation (max 512 chars) |
Response 200
{
"dispute_id": "7-1720000001000",
"settlement_id": "7",
"status": "Raised",
"settlement_status": "OnHold",
"tx_hash": "abc123..."
}| Status | Description |
|---|---|
400 |
settlement_id is not a positive integer |
422 |
Soroban simulation or transaction failure |
503 |
Missing required environment variables |
500 |
Unexpected server error |
Returns the current invoice grace window in seconds.
Response 200
{ "grace_window_seconds": 86400 }| Status | Description |
|---|---|
422 |
Soroban simulation failure |
503 |
Missing required environment variables |
500 |
Unexpected server error |
Update the invoice grace window.
{ "grace_window_seconds": 172800 }| Field | Type | Description |
|---|---|---|
grace_window_seconds |
number | Positive integer number of seconds |
Response 200
{
"grace_window_seconds": 172800,
"tx_hash": "abc123..."
}| Status | Description |
|---|---|
400 |
grace_window_seconds is not a positive integer |
422 |
Soroban simulation or transaction failure |
503 |
Missing required environment variables |
500 |
Unexpected server error |
Returns the paginated, consolidated audit trail emitted by the compliance contract.
The service indexes address_allowed, address_allowed_until, address_blocked, and
address_cleared events in MongoDB.
| Parameter | Type | Required | Description |
|---|---|---|---|
address |
string | No | Stellar public key filter |
event_type |
string | No | One of the four compliance event types |
from_ledger |
integer | No | Inclusive lower ledger bound |
to_ledger |
integer | No | Inclusive upper ledger bound |
page |
integer | No | 1-based page, default 1 |
limit |
integer | No | Page size, default 20, maximum 100 |
Response 200
{
"events": [
{
"event_id": "paging-token",
"event_type": "address_cleared",
"address": "G...",
"expires_at": null,
"ledger": 123,
"ledger_closed_at": "2026-08-27T12:00:00.000Z",
"transaction_hash": "abc123...",
"contract_id": "C...",
"paging_token": "paging-token",
"created_at": "2026-08-27T12:00:01.000Z"
}
],
"page": 1,
"limit": 20,
"total": 1,
"has_more": false
}| Status | Description |
|---|---|
400 |
Invalid query parameter |
503 |
MongoDB unavailable |
500 |
Unexpected server error |
COMEBACKHERE signs every outbound webhook POST with HMAC-SHA256 so your endpoint can verify payload authenticity before processing it.
For the full payload reference, retry schedule, idempotency guidance, and language-specific verification examples, see Webhook Payload Reference. Security note: this is a security-sensitive feature. Treat your signing secret with the same care as a private key. Rotate it immediately if it is ever exposed.
| Header | Value |
|---|---|
X-COMEBACKHERE-Signature |
Lowercase hex-encoded HMAC-SHA256 digest |
The digest is computed over the raw JSON request body (exactly as sent over
the wire) using the WEBHOOK_SIGNING_SECRET environment variable as the key.
import { createHmac, timingSafeEqual } from "crypto"
function verifyWebhook(
rawBody: string, // The unparsed request body string
signature: string, // Value of X-COMEBACKHERE-Signature header
secret: string, // Your WEBHOOK_SIGNING_SECRET
): boolean {
const expected = createHmac("sha256", secret).update(rawBody, "utf8").digest("hex")
const expectedBuf = Buffer.from(expected, "hex")
const actualBuf = Buffer.from(signature, "hex")
if (expectedBuf.length !== actualBuf.length) return false
return timingSafeEqual(expectedBuf, actualBuf)
}Always use a constant-time comparison (e.g. crypto.timingSafeEqual) when
comparing signatures to prevent timing side-channel attacks.
All events share a common event field plus event-specific fields:
{
"event": "settlement_executed",
"settlement_id": 1,
"tx_hash": "abc123..."
}| Event | Extra fields |
|---|---|
settlement_proposed |
settlement_id, merchant_address, amount, token, tx_hash |
settlement_approved |
settlement_id, signer, approval_weight, tx_hash |
settlement_executed |
settlement_id, tx_hash |
| Variable | Description |
|---|---|
WEBHOOK_URL |
Merchant endpoint that receives webhook POSTs |
WEBHOOK_SIGNING_SECRET |
HMAC-SHA256 signing secret (minimum 32 characters recommended) |
Set both variables in your deployment environment. If WEBHOOK_URL is not set,
webhook delivery is skipped silently (no error).
All error responses share this shape:
{ "error": "Human-readable description of the error." }| Variable | Description |
|---|---|
SOROBAN_RPC_URL |
Soroban RPC endpoint (e.g. http://localhost:8000/soroban/rpc) |
INVOICE_CONTRACT_ID |
Deployed invoice contract address |
TREASURY_CONTRACT_ID |
Deployed treasury contract address |
USDC_CONTRACT_ID |
USDC token contract address |
SETTLEMENT_CONTRACT_ID |
Settlement contract address (disputes) |
SIGNER_SECRET_KEY |
Stellar secret key for signing transactions |
NETWORK_PASSPHRASE |
Stellar network passphrase |
WEBHOOK_URL |
Merchant webhook endpoint URL |
WEBHOOK_SIGNING_SECRET |
HMAC-SHA256 signing secret for outbound webhooks |
PORT |
HTTP server port (default 3000) |