This document describes the HTTP API surface exposed by the frontend backend
(src/app/api). The routes are intentionally thin stubs in the current code
base; they exist primarily for analytics hooks and development/testing.
Each entry includes the HTTP method, path, expected request body (if any), and an example response. All endpoints return JSON.
- Public browser routes return wildcard CORS without credentials.
- First-party browser routes echo only trusted Commitlabs origins and may allow credentials.
- Implemented routes answer
OPTIONSpreflight requests automatically.
See docs/backend-cors-policy.md for the full origin configuration and route classification.
All endpoints follow these conventions.
{
"success": true,
"data": { ... },
"meta": { ... } // optional pagination / additional metadata
}{
"success": false,
"error": {
"code": "TOO_MANY_REQUESTS",
"message": "Too many requests. Please try again later.",
"retryAfterSeconds": 60 // present on 429 and 503 only
}
}When a request is rate-limited, the response includes the Retry-After HTTP header:
HTTP/1.1 429 Too Many Requests
Retry-After: 60
| Status | retryAfterSeconds default |
Meaning |
|---|---|---|
| 429 | 60 s | Client exceeded rate limit |
| 503 | 30 s | Service temporarily unavailable |
Clients should wait the indicated seconds before retrying. See error-handling.md for the full client retry strategy (exponential backoff + jitter).
Purchases a marketplace listing. Requires an active session cookie. Runs preflight eligibility checks, triggers on-chain ownership transfer, and records the event in the audit log.
- Authentication: session cookie (
requireAuth) - Path parameter:
id— the marketplace listing ID - Request body: none
- Response:
200 OK: Purchase completed.401 Unauthorized: Missing or invalid session.404 Not Found: Listing does not exist.409 Conflict: Preflight failed (e.g. listing inactive, buyer is seller).502 Bad Gateway: On-chain transfer failed.
curl -X POST http://localhost:3000/api/marketplace/listings/listing_1/purchase \
-H 'Cookie: session=<token>'{
"success": true,
"data": {
"listingId": "listing_1",
"commitmentId": "cm_abc",
"buyerAddress": "GBUYER...",
"price": "52000",
"currencyAsset": "USDC",
"txHash": null,
"reference": "TODO_CHAIN_CALL_TRANSFER_OWNERSHIP"
}
}Creates a new commitment on the Stellar network.
- Headers:
Idempotency-Key: (Optional) A unique string to identify the request and prevent duplicate processing. Recommended for safe retries.
- Request body:
ownerAddress: (string, required) The Stellar address of the owner.asset: (string, required) The asset code.amount: (string, required) The amount to commit.durationDays: (number, required) The duration of the commitment in days.maxLossBps: (number, required) Maximum loss in basis points.metadata: (object, optional) Additional metadata.
- Response:
201 Created: The commitment was successfully created.409 Conflict: A request with the sameIdempotency-Keyis already in progress.429 Too Many Requests: Rate limit exceeded.
curl -X POST http://localhost:3000/api/commitments \
-H 'Content-Type: application/json' \
-d '{"asset":"XLM","amount":100}'{
"message": "Commitments creation endpoint stub - rate limiting applied",
"ip": "::1"
}Marks the commitment identified by id as settled. Currently a stub that emits CommitmentSettled events.
- Path parameter:
id(string) - Headers:
Idempotency-Key: (Optional) A unique string to identify the request and prevent duplicate processing. Replayed requests within the 24-hour replay window return the original prior result.
- Request body: optional JSON payload with additional details.
- Response: stub confirmation message.
curl -X POST http://localhost:3000/api/commitments/abc123/settle \
-H 'Content-Type: application/json' \
-d '{"finalValue":105}'{
"message": "Stub settlement endpoint for commitment abc123",
"commitmentId": "abc123"
}Triggers an early exit (with penalty) for the named commitment. Emits CommitmentEarlyExit events.
- Path parameter:
id(string) - Headers:
Idempotency-Key: (Optional) A unique string to identify the request and prevent duplicate processing. Replayed requests within the 24-hour replay window return the original prior result.
- Request body: optional JSON with penalty or reason.
- Response: stub message.
curl -X POST http://localhost:3000/api/commitments/abc123/early-exit \
-H 'Content-Type: application/json' \
-d '{"reason":"user-request"}'{
"message": "Stub early-exit endpoint for commitment abc123",
"commitmentId": "abc123"
}Returns the most recent attestations sorted by observedAt descending, with
page-based pagination metadata.
- Query parameters:
page: (integer, optional) Page number (1-based). Must be ≥ 1. Defaults to 1.pageSize: (integer, optional) Items per page. Must be 1–100. Defaults to 10.ownerAddress: (string, optional) Filter by commitment owner address. Requires a validAuthorization: Bearer <token>header.
- Response:
200 OKwith attestation list and pagination meta. - Error codes:
400 VALIDATION_ERROR—pageorpageSizeout of range, orownerAddressis blank.401 UNAUTHORIZED—ownerAddressprovided without a valid Bearer token.429 TOO_MANY_REQUESTS— Rate limit exceeded.
curl 'http://localhost:3000/api/attestations/recent?page=1&pageSize=2'{
"success": true,
"data": {
"attestations": [
{ "id": "ATT-005", "commitmentId": "CMT-005", "observedAt": "2026-04-24T10:00:00Z" },
{ "id": "ATT-004", "commitmentId": "CMT-004", "observedAt": "2026-04-23T10:00:00Z" }
],
"total": 5
},
"meta": {
"page": 1,
"pageSize": 2,
"total": 5,
"totalPages": 3,
"hasNextPage": true,
"hasPrevPage": false
}
}Filtered by owner (requires authentication):
curl 'http://localhost:3000/api/attestations/recent?ownerAddress=GAAA...WHF' \
-H 'Authorization: Bearer <token>'Records an attestation event. Stub implementation logs
AttestationReceived.
- Request body: JSON describing the attestation (e.g. signature, commitmentId).
- Response: stub message with requester IP.
curl -X POST http://localhost:3000/api/attestations \
-H 'Content-Type: application/json' \
-d '{"commitmentId":"abc123","status":"valid"}'{
"message": "Attestations recording endpoint stub - rate limiting applied",
"ip": "::1"
}Returns the authenticated owner's derived notification feed. Notifications are derived on-read from the owner's commitments and attestations (expiry warnings, violations, attestation health checks); they are not persisted.
The feed is filtered by the owner's notification delivery preferences. Each
notification has a type (expiry, violation, health_check), and only
types the owner has opted into are returned. Preferences are read from stored
user preferences (the notificationCategories field) and updated via the
PUT /api/user/preferences endpoint.
- Query parameters:
ownerAddress: (string, required) The Stellar address whose feed to return.page: (number, optional, default1) 1-indexed page number. Must be>= 1.pageSize: (number, optional, default10) Items per page. Must be1–100.
- Preference filtering:
- Notification categories the owner has set to
falseinnotificationCategoriesare excluded from the feed. - When no preferences are stored, or a category key is absent, the category is delivered by default (safe opt-in). An owner only stops receiving a category by explicitly opting out.
- Filtering is applied before pagination, so
totalreflects the count of notifications the owner can actually see — not the raw derived count.
- Notification categories the owner has set to
- Response:
200 OK: Paginated, preference-filtered feed.400 Bad Request:ownerAddressis missing, or pagination params are out of range.429 Too Many Requests: Rate limit exceeded.
curl 'http://localhost:3000/api/notifications?ownerAddress=0x123&page=1&pageSize=10'{
"success": true,
"data": {
"items": [
{
"id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"ownerAddress": "0x123",
"title": "Commitment Nearing Expiry",
"message": "Your commitment CMT-1 for XLM expires in 5 days.",
"severity": "warning",
"type": "expiry",
"read": false,
"createdAt": "2026-02-25T00:00:00.000Z",
"relatedCommitmentId": "CMT-1"
}
],
"page": 1,
"pageSize": 10,
"total": 1
}
}Returns the public protocol constants used by UX copy and calculations, including fee parameters, penalty tiers, and commitment limits. This endpoint is public and includes caching headers.
curl http://localhost:3000/api/protocol/constants{
"success": true,
"data": {
"protocolVersion": "v1",
"network": "Test SDF Network ; September 2015",
"fees": {
"networkBaseFeeStroops": 100,
"platformFeePercent": 0
},
"penalties": [...],
"commitmentLimits": { ... },
"cachedAt": "2026-02-25T00:00:00.000Z"
}
}Server-Sent Events (SSE) stream that pushes real-time commitment status updates and transitions (Active, Settled, Early Exit, Violated).
- Path parameter:
id(string) - Headers:
Accept:text/event-stream(required)
- Security: Requires an authenticated session via browser cookies.
- Protocol Details:
- Snapshot: The server emits a
snapshotevent immediately upon connection carrying the current status. - Transitions: The server emits a
status_changeevent only when a status transition is detected on-chain. - Heartbeat: The server enqueues a comment heartbeat (
: keepalive) every 20 seconds to prevent intermediates (proxies, load balancers) from dropping the idle connection.
- Snapshot: The server emits a
event: snapshot
data: {"commitmentId":"abc123","status":"Active","timestamp":"2026-05-27T01:30:00.000Z"}
: keepalive
event: status_change
data: {"commitmentId":"abc123","status":"Settled","timestamp":"2026-05-27T01:30:15.000Z"}
- Automatic Reconnection: Standard browser
EventSourcehandles connection drops and reconnection attempts automatically. - Exponential Backoff: For non-browser clients or custom connection wrappers, implement exponential backoff on reconnection failures:
- Start with an initial delay of
1 second. - Double the delay on each consecutive failure (
2s,4s,8s,16s). - Cap the maximum delay at
30 secondsto protect server resources.
- Start with an initial delay of
- Graceful Fallback: When SSE is unsupported or fails repeatedly, clients should fall back to polling the lightweight
/api/commitments/[id]/statusroute at a standard, low-frequency interval (e.g., every 10–30 seconds).
Simple health/metrics endpoint used by monitoring tools.
- Response: JSON object containing uptime, mock request/error counts, and current timestamp.
curl http://localhost:3000/api/metrics{
"status": "up",
"uptime": 123.456,
"mock_requests_total": 789,
"mock_errors_total": 2,
"timestamp": "2026-02-25T00:00:00.000Z"
}🔧 This reference will grow as the backend implements real business logic.