API reference
The full machine-readable spec lives at /api/v1/openapi.json — drop it into any OpenAPI viewer (Swagger UI, Stoplight, Postman, Insomnia, etc.) for an interactive explorer.
Conventions
- Base URL in production:
https://api.sorenpay.com - All authenticated requests carry
Authorization: Bearer apk_… - All POSTs and PATCHs accept
Idempotency-Key(UUIDv4, 24h cache) - Live mode money-movement routes require
workspace.kyb_status === 'approved' - All inbound webhooks verify HMAC-SHA256 over raw body with ±5min replay window
Resources
| Resource | Routes |
|---|---|
| Workspaces | POST /api/workspaces, GET /api/workspaces |
| API keys | POST/GET/DELETE /api/auth/keys |
| Cards | POST/GET /api/cards, GET/PATCH /api/cards/[id] |
| Cardholders | POST/GET /api/cardholders |
| Physical cards | POST /api/physical-cards |
| Treasury | GET /api/treasury, POST /api/treasury/deposits |
| Ramp | onramp/offramp sessions + quotes |
| Intl payments | quote + originate + lookup |
| Agents | register + submit intent + audit log |
| MCP | JSON-RPC 2.0 endpoint |
| Checkout | merchant sessions + customer flow |
| Webhooks | inbound + outbound event spec |
Errors
All errors return JSON shaped:
{
"error": "<short_machine_code>",
"detail": "Optional human-readable message"
}| Status | When |
|---|---|
| 400 | Bad request body (Zod parse failure) |
| 401 | Missing or invalid apk_ token |
| 403 | Missing required scope |
| 404 | Resource not found (or not in your workspace) |
| 409 | State conflict (e.g., kyb_required, cardholder_required) |
| 422 | Idempotency-key mismatch (different body, same key) |
| 429 | Rate limit hit; see x-ratelimit-reset-ms |
| 500 | Server error — Sentry will catch it; please retry |
Versioning
We follow the OpenAPI spec at /api/v1/openapi.json for the v1 surface.
Breaking changes will move to /api/v2/… without removing v1 for at least 12 months.