Appearance
API Reference
Complete reference for the Ezys REST API. All endpoints communicate over HTTP using JSON.
Conventions
Amounts — integer values in the currency's smallest (minor) unit, encoded as JSON strings (
amountMinor+currency+exponent), with floor rounding. See Money & Amounts for the full contract.Currencies — ISO 4217 codes for fiat (
KRW,USD); registered tickers for stablecoins (USDC).Compatibility — treat response objects as open to new fields. Ezys may add fields to a response without a breaking-change announcement, so ignore fields you do not recognize rather than rejecting the payload; a strict parser that fails on unknown keys will break on a routine additive release. Removing a field, or changing what an existing one means, is a breaking change and is announced.
Two things are explicitly not open, and are the ones to branch on:
- Closed value sets — anything documented as a closed set enumerates every value the API can send in this spec version (
events[].state, feetypeandcollection, intent rejectionreason). New values require a spec version bump and a changelog entry. - The receipt body — its field set is frozen per
_schemaVersion, so unknown fields do not appear there. See Receipts.
- Closed value sets — anything documented as a closed set enumerates every value the API can send in this spec version (
Base URL
All endpoints are served under the /v1 prefix:
Production: https://api.ezys.io/v1
Sandbox: https://api.ezys.sh/v1Authentication
All requests require an API key, passed via the X-API-Key header — see Authentication.
Endpoints
Paths are relative to the /v1 base above. Availability reflects whether the surface is implemented and deployed; coming soon surfaces are published here as the contract of record ahead of rollout. Sandbox host rollout (api.ezys.sh) is still in progress — an Available surface is not yet reachable from the sandbox base URL.
Quote (RFQ)
| Method | Endpoint | Availability | Description |
|---|---|---|---|
| POST | /quotes | Available | Request indicative quotes — returns a synchronous list of scored candidates |
| POST | /quotes/firm | Available | Request a firm, lockable quote — returns quoteId, locked all-in rate, itemized fees, and validUntil |
See the Quote API for request/response fields and lifecycle.
Intent
| Method | Endpoint | Availability | Description |
|---|---|---|---|
| POST | /intents | Available | Submit an Intent — returns accepted or rejected |
Single-step submit — there is no separate
confirmstep. See the Intent API.
Execution status & receipts
| Method | Endpoint | Availability | Description |
|---|---|---|---|
| GET | /executions/{reference} | Available | Aggregate status of one execution — phase, events[] history, failure block |
| GET | /intents/{intentId}/status | Coming soon | Lightweight intent-only status (planned public exposure) |
| GET | /executions/{reference}/receipt | Available | Normalized machine-readable receipt (offramp + payout + fees). Issued when the payout reaches completed; until then it returns 409 receipt_not_issued. Partner traffic is gated on a separate operational step — see Receipts |
| GET | /reconciliation | Coming soon | Aggregate reconciliation view over a date range |
See the Status API and Receipts & Reconciliation.
Request Format
Headers
| Header | Required | Description |
|---|---|---|
Content-Type | Yes | Must be application/json |
X-API-Key | Yes | Your API key — see Authentication |
X-Idempotency-Key | Yes (POST) | Canonical RFC 9562 UUID. Required on partner-facing POST for safe retries — see Idempotency |
Body
All request bodies must be valid JSON. The shape is per-endpoint — see the Quote API and Intent API for the exact request bodies the current endpoints accept (the illustrative pair/strategy shape below is not the literal request body of any single current endpoint).
json
{
"pair": {
"source": "USDC",
"target": "KRW"
},
"side": "sell",
"amountMinor": "1000000000",
"strategy": "instant",
"constraints": {
"maxSlippageBps": 50,
"maxFeeBps": 30
}
}Response Format
Endpoint responses are returned directly — the body is the endpoint's own result object, with no { success, data } wrapper. Errors are likewise returned as the original error object, not re-wrapped; the only exception is the infrastructure checks that run in front of the endpoints (authentication, idempotency), which use the error envelope described below.
Success
The body is the response object documented per endpoint — e.g. a quote response or an intent accepted response:
json
{
"intentId": "INT-2F8A3B1C",
"status": "accepted",
"planId": "DVP-INT-2F8A",
"solverId": "solver-1",
"path": { ... }
}Business rejections
Synchronous business rejections return 422 with the endpoint's original rejection object — status plus a machine-readable reason, as documented per endpoint (see Intent API → Rejected Response):
json
{
"intentId": "INT-2F8A3B1C",
"status": "rejected",
"reason": "no_liquidity"
}Validation errors
Malformed requests return 400 with the framework's standard error body:
json
{
"statusCode": 400,
"message": "permit.signature must be a 65-byte hex value",
"error": "Bad Request"
}Infrastructure errors
Authentication (401/403) and idempotency (400/409/503) checks run in front of the endpoints and return the error envelope:
json
{
"success": false,
"error": {
"code": "ERROR_CODE",
"message": "A human-readable description of the error."
}
}See Authentication and Idempotency for the concrete codes each layer emits.
HTTP Status Codes
| Code | Meaning |
|---|---|
200 | Request succeeded |
201 | Resource created |
202 | Accepted for asynchronous processing |
400 | Invalid request — check parameters |
401 | Authentication failed — missing or invalid API key |
403 | Insufficient permissions |
404 | Resource not found |
409 | Idempotency-Key conflict, or a matching request is still in progress — see Idempotency |
429 | Rate limit exceeded |
500 | Internal server error |
503 | Service temporarily unavailable — transient; retry with backoff |
Error Codes
For which of these errors are safe to retry and the recommended action for each, see Error Handling & Retries.
How a code surfaces depends on the layer that raises it (see Response Format): infrastructure checks (authentication, idempotency, rate limiting) carry the code in the error envelope's error.code, while business rejections surface as the rejection object's reason (see Intent API → Rejected Response) with the code below as the classification.
| Code | Description |
|---|---|
INVALID_API_KEY | The provided API key is invalid or revoked |
INVALID_PAIR | The requested currency pair is not supported |
INVALID_PARAMETER | One or more request parameters are malformed |
INVALID_STRATEGY | The specified execution strategy is not recognized |
AMOUNT_OUT_OF_RANGE | The amount exceeds the allowed min/max bounds |
CONSTRAINTS_NOT_MET | 422 — the requested constraints cannot be satisfied (status: "rejected") |
POLICY_DENIED | 422 — blocked by policy (limits or compliance); carries a closed subCode enum, one value conditionally retryable — see Policy subCodes |
INSUFFICIENT_LIQUIDITY | 422 — not enough liquidity to fulfill the request (status: "rejected"; a business outcome, never 200) |
INTENT_NOT_FOUND | No Intent exists with the given ID |
INTENT_EXPIRED | The Intent has expired and can no longer be acted upon |
INTENT_ALREADY_EXECUTING | The Intent is already in execution and cannot be cancelled |
SETTLEMENT_FAILED | The settlement (off-ramp) leg failed terminally — handle by compensation |
PROVIDER_UNAVAILABLE | 5xx — a downstream provider (e.g. oracle) is temporarily unavailable; retry with backoff |
PAYOUT_UNAVAILABLE | 5xx — the payout rail is temporarily unavailable; retry with backoff |
PAYOUT_REJECTED | 400 — the payout was rejected (configuration or request); fix and resubmit |
RATE_LIMIT_EXCEEDED | Too many requests — back off and retry |
IDEMPOTENCY_KEY_REQUIRED | 400 — the X-Idempotency-Key header is missing on a partner-facing POST. See Idempotency |
IDEMPOTENCY_KEY_INVALID | 400 — the key is not a canonical RFC 9562 UUID, or the request could not be fingerprinted |
IDEMPOTENCY_KEY_CONFLICT | 409 — the same key was reused with a different request body |
IDEMPOTENCY_KEY_PROCESSING | 409 — the original request for this key is still being processed |
SERVICE_UNAVAILABLE | 5xx — a dependency or the service is temporarily unavailable; retry with backoff |
INTERNAL_ERROR | 5xx — an unexpected server error; retry with backoff |
Rate Limits
| Tier | Limit |
|---|---|
| Standard | 100 requests / minute |
| Enterprise | Custom — contact sales |
