The API layer in Velo provides a lightweight service interface for agent-assisted and application-driven flows.
The API is implemented with Fastify and is intended to expose payment-aware routes for cash-related requests.
| Method | Path | Price (USDC) | Description |
|---|---|---|---|
| GET | /health |
Free | Health check |
| GET | /api/v1/openapi.json |
Free | OpenAPI 3.1 specification |
| GET | /api/v1/services |
Free | Service catalog |
| GET | /api/v1/cash/agents |
0.001 | Provider discovery |
| POST | /api/v1/cash/request |
0.01 | Create a cash request |
| GET | /api/v1/cash/request/:id |
Free | Poll request status |
| POST | /api/v1/cash/request/:id/release |
Free | Release escrow (hand-off) |
| POST | /api/v1/cash/request/:id/refund |
Free | Refund escrow (after timeout) |
| GET | /api/v1/reputation/:address |
0.0005 | On-chain reputation lookup |
| GET | /api/v1/admin/status |
Admin auth | System status & store metrics |
All API endpoints are rate-limited per IP address to prevent abuse. The following limits are enforced:
| Endpoint | Limit | Reason |
|---|---|---|
GET /health |
100 req / 1 min | Infrastructure health check |
GET /api/v1/openapi.json |
60 req / 1 min | Free specification endpoint |
GET /api/v1/services |
60 req / 1 min | Free catalog endpoint |
GET /api/v1/cash/agents |
30 req / 1 min | Paid discovery; limit abuse |
POST /api/v1/cash/request |
20 req / 1 min | Paid escrow lock (costly) |
GET /api/v1/cash/request/:id |
60 req / 1 min | Free polling |
POST /api/v1/cash/request/:id/release |
20 req / 1 min | Free state transition |
POST /api/v1/cash/request/:id/refund |
10 req / 1 min | Free refund (after timeout) |
GET /api/v1/reputation/:address |
30 req / 1 min | Paid reputation lookup |
GET /api/v1/admin/status |
20 req / 1 min | Admin status (requires API key) |
When a client exceeds the limit, the API responds with 429 Too Many Requests and a Retry-After header indicating the number of seconds to wait before retrying.
Admin-only endpoints (e.g., GET /api/v1/admin/status) are protected by a shared API key.
Setup:
- Generate a secure key:
openssl rand -hex 32 - Set it in your environment or
.envfile:ADMIN_API_KEY=<your-generated-key> - Restart the API server.
Usage:
Include the key as a Bearer token in the Authorization header:
Authorization: Bearer <admin-api-key>
If the key is missing or invalid, the API responds with 401 Unauthorized or 403 Forbidden.
When a refund is processed via POST /api/v1/cash/request/:id/refund, the API can notify a Slack or Discord channel via a webhook URL.
Setup:
- Create an incoming webhook in your Slack workspace or Discord server.
- Set the URL in your environment or
.envfile:REFUND_WEBHOOK_URL=https://hooks.slack.com/services/.../.../... - Restart the API server.
The webhook payload includes the trade ID, amount in USDC, buyer address, and seller address. The format auto-detects whether the URL points to Discord or Slack. Leave the variable empty (or unset) to disable webhook notifications entirely.
The current implementation uses an x402-style challenge mechanism. When a valid payment header is not present, the API returns a challenge payload rather than allowing unrestricted access.
The API reads environment variables from the local environment or .env file. The most important values include the port, merchant address, and network configuration.
The API supports fee-bump transactions to sponsor transaction fees for users who don't hold XLM. This allows users to interact with the escrow contract without needing to maintain an XLM balance for transaction fees.
When a fee sponsor is configured, the API wraps user transactions in Stellar fee-bump transactions. The sponsor account pays the transaction fees while the user's account executes the contract operations. This is particularly useful for:
- New users who haven't acquired XLM yet
- Mobile-first experiences where onboarding complexity should be minimized
- Agent-mediated flows where the end user may not have a funded wallet
Set the SPONSOR_SECRET_KEY environment variable in apps/api/.env:
SPONSOR_SECRET_KEY=S...YOUR_SPONSOR_SECRET_KEY
The sponsor account must:
- Have sufficient XLM balance to cover transaction fees
- Be funded on the target network (testnet or mainnet)
- Be properly secured (this is a signing key)
- When SPONSOR_SECRET_KEY is set: The API automatically wraps transactions in fee-bump transactions for both custodial and non-custodial flows
- When SPONSOR_SECRET_KEY is unset: Users must pay their own transaction fees (standard behavior)
- Works on both testnet and mainnet: Unlike the custodial BUYER_SECRET_KEY, fee sponsorship is not restricted to testnet
The fee-bump transaction fee is calculated as:
bump_fee = inner_transaction_fee + BASE_FEE
This ensures the sponsor pays both the inner transaction's resource fees and the fee-bump operation overhead.
- The sponsor account holds XLM and can sign transactions, so it must be properly secured
- Consider using a dedicated sponsor account with limited XLM balance to limit exposure
- Monitor sponsor account balance and transaction history for unusual activity
- On mainnet, implement proper key management practices (HSM, key rotation, etc.)