Comprehensive API documentation for the Volara backend service.
Base URL: http://localhost:3001 (development)
Version: 1.0.0
Authentication: SEP-10 + JWT
- Authentication
- Rates
- Transactions
- Anchors
- Callbacks
- Health & Status
- Error Handling
- Rate Limiting
- Production Additions (April 27, 2026)
Volara uses SEP-10 (Stellar Ecosystem Proposal) for wallet-based authentication.
POST /auth/challenge
Request a SEP-10 challenge to sign with your wallet.
Request Body:
{
"walletAddress": "GABC...XYZ"
}Response (200):
{
"success": true,
"data": {
"challenge": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9...",
"expiresAt": "2026-04-24T12:00:00Z"
}
}POST /auth/verify
Submit the signed challenge to receive a JWT session token.
Request Body:
{
"challenge": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9...",
"signature": "3045022100..."
}Response (200):
{
"success": true,
"data": {
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"expiresIn": 86400,
"user": {
"walletAddress": "GABC...XYZ",
"role": "user"
}
}
}The JWT token is automatically stored in an httpOnly cookie. Include it in subsequent requests.
GET /rates
Retrieve all active anchor rates.
Headers:
Authorization: Bearer <JWT_TOKEN>
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
fromCurrency |
string | No | Filter by source currency (e.g., "USD") |
toCurrency |
string | No | Filter by destination currency (e.g., "COP") |
country |
string | No | Filter by destination country |
Response (200):
{
"success": true,
"data": [
{
"anchorId": "vibrant",
"anchorName": "Vibrant",
"fromCurrency": "USD",
"toCurrency": "COP",
"feePercent": 1.5,
"fxRate": 3950.25,
"destinationCountry": "Colombia",
"lastUpdated": "2026-04-23T10:00:00Z"
}
]
}POST /rates/best
Find the cheapest route for a remittance request.
Headers:
Authorization: Bearer <JWT_TOKEN>
Content-Type: application/json
Request Body:
{
"amount": 50000,
"fromCurrency": "USD",
"toCurrency": "COP",
"destinationCountry": "Colombia"
}Response (200):
{
"success": true,
"data": {
"anchorId": "vibrant",
"anchorName": "Vibrant",
"feePercent": 1.5,
"fxRate": 3950.25,
"feeAmount": 750,
"destinationAmount": 1971312.5,
"totalCost": 750,
"savingsVsAverage": 2.3
}
}Response (404) - No Route Found:
{
"success": false,
"error": {
"code": "NO_ROUTE_FOUND",
"message": "No routes available for USD to COP in Colombia"
}
}GET /transactions
Retrieve all transactions for the authenticated user.
Headers:
Authorization: Bearer <JWT_TOKEN>
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
status |
string | No | Filter by status (pending, complete, failed) |
limit |
number | No | Number of results (default: 20, max: 100) |
offset |
number | No | Pagination offset (default: 0) |
Response (200):
{
"success": true,
"data": {
"transactions": [
{
"id": "uuid-123",
"userWallet": "GABC...XYZ",
"anchorId": "vibrant",
"fromCurrency": "USD",
"toCurrency": "COP",
"amount": 500.0,
"feePercent": 1.5,
"fxRate": 3950.25,
"destinationAmount": 1971312.5,
"status": "complete",
"sep31TransactionId": "tx_abc123",
"createdAt": "2026-04-23T10:00:00Z",
"updatedAt": "2026-04-23T10:05:00Z"
}
],
"total": 45,
"limit": 20,
"offset": 0
}
}GET /transactions/:id
Retrieve a specific transaction.
Headers:
Authorization: Bearer <JWT_TOKEN>
Response (200):
{
"success": true,
"data": {
"id": "uuid-123",
"userWallet": "GABC...XYZ",
"anchorId": "vibrant",
"fromCurrency": "USD",
"toCurrency": "COP",
"amount": 500.0,
"feePercent": 1.5,
"fxRate": 3950.25,
"destinationAmount": 1971312.5,
"status": "complete",
"sep31TransactionId": "tx_abc123",
"createdAt": "2026-04-23T10:00:00Z",
"updatedAt": "2026-04-23T10:05:00Z"
}
}Response (404):
{
"success": false,
"error": {
"code": "TRANSACTION_NOT_FOUND",
"message": "Transaction not found"
}
}POST /transactions
Initiate a new remittance transaction.
Headers:
Authorization: Bearer <JWT_TOKEN>
Content-Type: application/json
Request Body:
{
"anchorId": "vibrant",
"amount": 500.0,
"fromCurrency": "USD",
"toCurrency": "COP",
"destinationCountry": "Colombia",
"recipientDetails": {
"name": "Carlos R.",
"email": "carlos@example.com",
"phone": "+573001234567"
}
}Response (201):
{
"success": true,
"data": {
"id": "uuid-123",
"status": "pending",
"anchorId": "vibrant",
"sep31TransactionId": "tx_abc123",
"message": "Transaction initiated successfully"
}
}GET /anchors
Retrieve all registered anchors.
Headers:
Authorization: Bearer <JWT_TOKEN>
Response (200):
{
"success": true,
"data": [
{
"id": "uuid-1",
"anchorId": "vibrant",
"name": "Vibrant",
"sep31Url": "https://api.vibrant.co",
"active": true,
"supportedCorridors": [
{
"fromCurrency": "USD",
"toCurrency": "COP",
"destinationCountry": "Colombia"
},
{
"fromCurrency": "USD",
"toCurrency": "MXN",
"destinationCountry": "Mexico"
}
],
"createdAt": "2026-04-01T00:00:00Z"
}
]
}POST /anchors/register
Register a new anchor. Requires admin role.
Headers:
Authorization: Bearer <JWT_TOKEN>
Content-Type: application/json
Request Body:
{
"anchorId": "newanchor",
"name": "New Anchor",
"sep31Url": "https://api.newanchor.com",
"apiToken": "secret-token",
"accountId": "GABC...XYZ",
"supportedCorridors": [
{
"fromCurrency": "USD",
"toCurrency": "COP",
"destinationCountry": "Colombia"
}
]
}Response (201):
{
"success": true,
"data": {
"id": "uuid-2",
"anchorId": "newanchor",
"name": "New Anchor",
"active": true,
"message": "Anchor registered successfully"
}
}Response (403) - Unauthorized:
{
"success": false,
"error": {
"code": "UNAUTHORIZED",
"message": "Admin access required"
}
}GET /anchors/catalog- Public endpoint.
- If authenticated, response is personalized with
isActiveForUser.
GET /anchors/preferences/me- Requires auth.
- Returns the caller wallet's marketplace preferences.
POST /anchors/preferences/:anchorId/activate- Requires auth.
- Activates a catalog anchor for the caller.
DELETE /anchors/preferences/:anchorId- Requires auth.
- Deactivates a catalog anchor for the caller.
POST /anchors/submissions- Requires auth.
- Creates a user anchor submission for admin review.
GET /admin/anchors/submissions- Requires admin role.
- Optional query:
status=pending|approved|rejected.
POST /admin/anchors/submissions/:id/approve- Requires admin role.
- Marks a pending submission as approved and publishes it into catalog as pending integration.
POST /admin/anchors/submissions/:id/reject- Requires admin role.
- Marks a pending submission as rejected.
PATCH /admin/anchors/catalog/:id- Requires admin role.
- Supports
isPublished,availabilityStatus,rating,notes,feeEstimate,displayName.
POST /recurring-sends- Requires auth.
- Creates recurring plan (
daily,weekly,monthly).
GET /recurring-sends- Requires auth.
- Returns
plans+pendingRunsfor caller.
PATCH /recurring-sends/:id- Requires auth.
- Updates mutable plan fields owned by caller.
POST /recurring-sends/:id/pause- Requires auth.
- Pauses caller plan.
POST /recurring-sends/:id/resume- Requires auth.
- Resumes caller plan.
POST /recurring-sends/:id/cancel- Requires auth.
- Cancels caller plan.
POST /recurring-sends/runs/:runId/confirm- Requires auth.
- Confirms a pending recurring draft and executes the existing SEP-31 flow.
- Command:
cd backend && npm run bootstrap:admin -- <WALLET_ADDRESS> [CREATED_BY_WALLET] - This creates or upserts the first admin wallet in
admin_wallets.
POST /callbacks/sep31
Receive transaction status updates from anchors. This endpoint is called by anchors, not users.
Headers:
Content-Type: application/json
X-Anchor-Signature: <signature>
Request Body:
{
"transactionId": "tx_abc123",
"status": "complete",
"updatedAt": "2026-04-23T10:05:00Z",
"message": "Payment completed successfully"
}Response (200):
{
"success": true,
"message": "Callback received"
}GET /health
Check if the API is running.
Response (200):
{
"status": "ok",
"timestamp": "2026-04-23T10:00:00Z"
}GET /
Get API information.
Response (200):
{
"message": "Welcome to the RemitFlow API",
"version": "1.0.0"
}All errors follow this format:
{
"success": false,
"error": {
"code": "ERROR_CODE",
"message": "Human-readable error message",
"details": {} // Optional additional details
}
}| Code | HTTP Status | Description |
|---|---|---|
UNAUTHORIZED |
401 | Invalid or missing authentication |
FORBIDDEN |
403 | Insufficient permissions |
NOT_FOUND |
404 | Resource not found |
VALIDATION_ERROR |
400 | Invalid input data |
NO_ROUTE_FOUND |
404 | No routes available for request |
TRANSACTION_NOT_FOUND |
404 | Transaction does not exist |
ANCHOR_NOT_FOUND |
404 | Anchor does not exist |
DUPLICATE_ANCHOR |
409 | Anchor already exists |
RATE_LIMIT_EXCEEDED |
429 | Too many requests |
INTERNAL_ERROR |
500 | Server error |
- Limit: 100 requests per minute per IP
- Headers:
X-RateLimit-Limit: Maximum requests allowedX-RateLimit-Remaining: Requests remainingX-RateLimit-Reset: Time when limit resets
Response (429) - Rate Limit Exceeded:
{
"success": false,
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Too many requests. Please try again later.",
"retryAfter": 30
}
}Once the backend is running, access:
- Swagger UI: http://localhost:3001/api/docs
- OpenAPI Spec: http://localhost:3001/api/openapi.json
- ReDoc: http://localhost:3001/api/redoc
GET /metrics/overviewGET /metrics/transactions?days=30GET /metrics/retention?weeks=8
GET /anchors/catalogGET /anchors/preferences/mePOST /anchors/preferences/:anchorId/activateDELETE /anchors/preferences/:anchorIdPOST /anchors/submissions
GET /admin/anchors/submissionsPOST /admin/anchors/submissions/:id/approvePOST /admin/anchors/submissions/:id/rejectPATCH /admin/anchors/catalog/:id
POST /recurring-sendsGET /recurring-sendsPATCH /recurring-sends/:idPOST /recurring-sends/:id/pausePOST /recurring-sends/:id/resumePOST /recurring-sends/:id/cancelPOST /recurring-sends/runs/:runId/confirm
GET /indexing/summaryGET /indexing/recent?limit=25POST /indexing/reconcile-now
import axios from "axios";
const api = axios.create({
baseURL: "http://localhost:3001",
withCredentials: true,
});
// Get rates
const rates = await api.get("/rates");
// Find best route
const bestRoute = await api.post("/rates/best", {
amount: 50000,
fromCurrency: "USD",
toCurrency: "COP",
destinationCountry: "Colombia",
});
// Initiate transaction
const transaction = await api.post("/transactions", {
anchorId: "vibrant",
amount: 500.0,
fromCurrency: "USD",
toCurrency: "COP",
destinationCountry: "Colombia",
recipientDetails: {
name: "Carlos R.",
email: "carlos@example.com",
},
});# Get rates
curl -X GET http://localhost:3001/rates \
-H "Authorization: Bearer <JWT_TOKEN>"
# Find best route
curl -X POST http://localhost:3001/rates/best \
-H "Authorization: Bearer <JWT_TOKEN>" \
-H "Content-Type: application/json" \
-d '{
"amount": 50000,
"fromCurrency": "USD",
"toCurrency": "COP",
"destinationCountry": "Colombia"
}'Last Updated: April 2026
API Version: 1.0.0
Maintained By: Volara Team