API documentation
Base URL https://api.sync-convert.com/v1. All responses are JSON. All timestamps are UTC epoch milliseconds.
Authentication
Pass your API key as a bearer token. Keys come in two modes: sk_live_… bills credits against your quota, sk_test_… returns fixed mock rates and is free.
curl https://api.sync-convert.com/v1/rates/latest?base=EUR \ -H "Authorization: Bearer sk_live_xxxxxxxxxxxx"
Keys are stored hashed — we can show you the prefix and last four characters, never the whole key again. Rotate from the dashboard if you lose one.
Response envelope
Every successful response carries provenance so you can decide whether a rate is fresh enough for your use case rather than trusting us blindly.
{
"success": true,
"base": "EUR",
"rates": { "USD": 1.0842, "TRY": 47.3120 },
"as_of": 1755950412338,
"age_ms": 412,
"source_tier": "licensed_ws",
"stale": false,
"meta": { "credits_used": 1, "credits_remaining": 29873 }
}A source_tier of manual means the rate is a fixed figure we maintain by hand for a currency no connected source publishes — currently MAD. It is not live market data. A cross rate touching a manual leg is reported as manual, so you can branch on it if a pegged figure is not acceptable for your use case.
| Field | Meaning |
|---|---|
| as_of | UTC epoch milliseconds of the tick itself |
| age_ms | How long ago that tick was captured |
| source_tier | licensed_ws · exchange_ws · aggregator · ecb_reference · manual |
| stale | true when every live source is down and we are serving the last known rate |
| meta.credits_used | Credits this request consumed |
| meta.credits_remaining | Credits left in the current period |
Endpoints
| Method | Path | Description |
|---|---|---|
| GET | /rates/latest | Latest rates for a base currency, optionally filtered by symbols. |
| GET | /convert | Convert an amount between two currencies. |
| GET | /rates/historical/{date} | Rates as of a given date (YYYY-MM-DD). |
| GET | /rates/timeseries | Rate series between two dates for one or more symbols. |
| GET | /crypto/latest | Latest crypto rates against a fiat base. |
| GET | /currencies | Currencies currently enabled for your tenant. |
| GET | /usage | Credits consumed, quota and period reset time. |
| GET | /health | Service status and source health. Used to measure the SLA. |
Credit weights
You are billed in call credits, not raw requests, so a cheap lookup costs less than an expensive one. Weights are per plan and visible in your dashboard.
| Endpoint | Credits |
|---|---|
| GET /rates/latest (single base) | 1 |
| GET /convert | 1 |
| GET /rates/latest (over 20 symbols) | 2 |
| GET /crypto/latest | 2 |
| GET /rates/historical/{date} | 3 |
| GET /rates/timeseries (31 days or fewer) | 5 |
| GET /rates/timeseries (over 31 days) | 10 |
| WebSocket subscription (per pair, per day) | 10 |
Errors
Errors use a consistent shape. Messages are localised via the Accept-Language header (en, fr, ru, tr).
{
"success": false,
"error": {
"code": "CURRENCY_NOT_ENABLED",
"message": "TRY is not enabled for this tenant.",
"doc_url": "https://sync-convert.com/docs#errors"
}
}| HTTP | Code | Meaning |
|---|---|---|
| 401 | INVALID_API_KEY | Key missing, revoked or malformed. |
| 401 | DEMO_EXPIRED | The 30-day demo key has lapsed. |
| 402 | PAYMENT_REQUIRED | Subscription is past due. |
| 403 | CURRENCY_NOT_ENABLED | The currency is not enabled for this tenant. |
| 403 | PLAN_FEATURE_UNAVAILABLE | Feature not included in the current plan, e.g. WebSocket on Starter. |
| 403 | ORIGIN_NOT_ALLOWED | Browser request from a domain not on this key's allowlist. |
| 403 | DOMAIN_LIMIT_REACHED | More domains requested than the plan's active domain allowance. |
| 429 | QUOTA_EXCEEDED | Monthly credit allowance is exhausted. |
| 429 | RATE_LIMITED | Too many requests per second. |
| 503 | RATES_UNAVAILABLE | Every upstream source is unavailable. |
WebSocket
Available on Pro and above. Connect, authenticate with your API key, then subscribe to the pairs you have enabled. Ticks arrive as they land — no polling, and streaming does not consume request credits beyond the per-pair daily subscription charge.
const ws = new WebSocket("wss://stream.sync-convert.com/v1");
ws.onopen = () => {
ws.send(JSON.stringify({ type: "auth", key: "sk_live_xxxxxxxxxxxx" }));
ws.send(JSON.stringify({ type: "subscribe", pairs: ["EUR/TRY", "BTC/USD"] }));
};
ws.onmessage = (event) => {
const tick = JSON.parse(event.data);
// { pair: "EUR/TRY", rate: 47.3120, as_of: 1755950412338 }
};