Requests that quote, create or read an order are made with your account’s API key. The catalogue endpoints and the XML rates feed are public and need no key.
Your key
Section titled “Your key”An API key has two parts:
| Part | Looks like | What it is for |
|---|---|---|
| Key ID | ktv_pk_ followed by 24 letters and digits |
Identifies the key. It is not a secret: the account API page shows it, GET /me returns it as key.public_key, and you can quote it to support. |
| Secret key | ktv_sk_ followed by 46 letters and digits |
Authenticates your requests. It is shown once, when the key is created, and never again. |
Kotova keeps only a fingerprint of the secret key, so nobody can show it to you a second time, support included. If you lose it, regenerate the key.
Creating a key
Section titled “Creating a key”You create the key on the account API page at app.kotova.io. Creating one needs:
- an account with a confirmed e-mail address that is not a disposable one;
- a referral code, which makes you an affiliate (the page offers to generate one);
- two-factor authentication with an authenticator app, turned on under Personal data in your account;
- your acceptance of the API Terms of Use.
Choose Create API key and enter the 6-digit code from your authenticator app. Backup codes cannot be used here. The page then shows the secret key once, and stays open until you confirm that you have stored it. Creating and regenerating keys is limited to 5 per hour per account.
Each time a key is created, regenerated or deleted, Kotova sends a notice to your account’s e-mail address. If you did not make the change, secure your account and delete the key.
Sending the key
Section titled “Sending the key”Send the secret key with every request to a keyed endpoint, in the Authorization
header:
Authorization: Bearer ktv_sk_…Never put the key in a URL. GET /me is a quick way to check that a key works: it
returns the key ID, your referral code, your rate limit and today’s usage.
curl -sS https://api.kotova.io/x/v1/me \ -H "Authorization: Bearer $KOTOVA_API_KEY"const res = await fetch('https://api.kotova.io/x/v1/me', { headers: { Authorization: `Bearer ${process.env.KOTOVA_API_KEY}` },});const me = await res.json();console.log(me.key.public_key, me.rate_limit.limit);import osimport requests
API_KEY = os.environ["KOTOVA_API_KEY"]res = requests.get( "https://api.kotova.io/x/v1/me", headers={"Authorization": f"Bearer {API_KEY}"}, timeout=10,)me = res.json()print(me["key"]["public_key"], me["rate_limit"]["limit"])An excerpt of the response:
{ "key": { "public_key": "ktv_pk_3f9a7c2kd8q1m4x6b2n5r7t9", "created_at": "2026-11-03T09:12:44Z", "last_used_at": "2026-11-10T10:12:01Z" }, "affiliate": { "ref_code": "KX7M2Q", "status": "active" }, "rate_limit": { "limit": 250, "remaining": 243, "window_seconds": 60, "resets_at": "2026-11-10T10:16:00Z", "weights": { "create_order": 50, "default": 1 } }, "usage_today": { "quotes": 12, "orders": 1, "reads": 40, "validations": 0, "limited": 0 }}GET /me is documented in Utilities.
Send no key to the keyless endpoints (/health, /openapi.json, /currencies,
/networks, /sources, /pairs and the rates feed). They ignore it, and a request
without one can be answered from the CDN cache.
Keep the secret on your server
Section titled “Keep the secret on your server”Anyone who has your secret key can quote and create orders in your account’s name and use up its rate limit. Keep it on your server, in an environment variable or a secret manager, and never put it in a website, a mobile app or a public code repository.
Browsers enforce this too. The keyed endpoints send CORS headers only to an allowlist
that holds the Try it consoles on https://docs.kotova.io, so a script on any
other web page cannot read their responses. That does not protect a key you ship in
an app: call the API from your server, and let your website or app talk to your
server.
The keyless endpoints answer Access-Control-Allow-Origin: *, so your web pages may
call them directly, for example to show the currency list.
One key per account
Section titled “One key per account”An account has one active key at a time. Your rate limit, your commission and your orders belong to the account rather than to the key:
- a new key starts with the same rate limit and the same commission, and the budget of the current minute is not reset;
- orders created with an earlier key stay readable with the new one, through
GET /orders/{id}andGET /orders.
Regenerating or deleting a key
Section titled “Regenerating or deleting a key”Both actions are on the account API page.
- Regenerate replaces the key: you get a new key ID and a new secret key, after confirming with a code from your authenticator app. The old key stops working.
- Delete revokes the key without a replacement. Orders already created keep running and still count for your affiliate profile. You can create a new key afterwards.
In both cases, order creation with the old key stops immediately. Its other requests
are refused within 30 seconds. Put the new secret key on your servers straight away:
requests with the old one answer 401 key_revoked.
When a key stops working
Section titled “When a key stops working”| Status | Code | Why |
|---|---|---|
| 401 | unauthorized |
No Authorization header, a value that is not a well-formed ktv_sk_ key, or a key that does not exist. |
| 401 | key_revoked |
The key was regenerated or deleted on the account API page, or revoked by Kotova. |
| 403 | affiliate_inactive |
The key exists, but its affiliate profile is inactive or has expired, or the account that created the key no longer exists or no longer owns that profile. |
Both 401 answers carry WWW-Authenticate: Bearer realm="kotova-x". While your
affiliate profile is inactive, the account API page says that API access is paused;
write to api@kotova.io to find out why.
A request refused at authentication costs nothing from your rate limit.
Failed authentication attempts
Section titled “Failed authentication attempts”Failed authentications are limited per IP address (per /64 for IPv6) to 30 a minute.
Once an address has sent 30 keys the API does not know within a minute, its requests
with keys the API cannot yet confirm may be refused with 429
rate_limited and details.reason: "auth_failures"
until the minute ends; Retry-After gives the seconds to wait. A key that has
authenticated successfully within the last hour is not held up by this limit.
How API orders are attributed
Section titled “How API orders are attributed”The key belongs to your affiliate profile. Every order created with it is attributed to that profile and earns commission like an order through your referral link. See How you earn.