Get started
Errors
Errors use real HTTP status codes and one JSON envelope with a stable code. Match on the code, never on the message.
The envelope
Every error response with a JSON body looks like this:
{
"error": {
"code": "quote_expired",
"message": "The quote has expired; ask for a new one.",
"request_id": "req_01JB8X2Q4M7Z3V9K5T1N6R0P2W"
}
}codeis stable and machine-readable. Branch on it.messageexplains the error to a person. It may change at any time, so don't parse it.request_idis also in theMK-Request-Idheader of every response, successful or not. Log it, and quote it when you contact us.
A 2xx status means success; anything else carries this envelope. GET /v1/giftcards/{id}/pdf answers application/pdf on success and JSON on errors.
Error codes
| Status | Code | Meaning | What to do |
|---|---|---|---|
| 400 | invalid_request | The request is malformed: bad JSON, an unknown or invalid field, or a missing header. | Fix the request. The message names the field. |
| 401 | invalid_signature | The MK-* headers are missing or malformed, the key id is unknown, or the signature doesn't match. | Check the key id and the canonical string; sign the exact bytes you send. |
| 401 | key_expired | The key has passed its expiry date. | Create a new key in the webapp. |
| 401 | key_revoked | The key was revoked. | Create a new key in the webapp. |
| 401 | timestamp_out_of_range | MK-Timestamp is more than 30 seconds from the server clock. | Sync your clock (server_time in GET /v1/status) and sign again. |
| 401 | nonce_reused | This key already used this MK-Nonce. | Sign again with a fresh random nonce. |
| 403 | insufficient_scope | The key doesn't have the scope this endpoint needs. | Use a key with the scope. Scopes can't be added to an existing key. |
| 403 | ip_not_allowed | The request came from an address outside the key's IP allowlist. | Call from an allowed address, or create a key with a different allowlist. |
| 403 | account_restricted | The account can't use the API right now (for example locked, inactive, or onboarding not finished). | Check the account in the webapp, or contact us. |
| 403 | api_access_disabled | API access is switched off. | Wait until API access is switched on; GET /v1/status shows it. |
| 403 | forbidden | This action is switched off for the API right now. | Check GET /v1/status; contact us if you need it switched on. |
| 404 | not_found | No such resource. | Check the id or asset symbol. |
| 405 | method_not_allowed | The path exists, but not with this method. | Use the method the reference lists for this path. |
| 409 | idempotency_conflict | This Idempotency-Key was used with a different request body. | Use a new Idempotency-Key for a different request. |
| 409 | idempotency_in_progress | A request with this Idempotency-Key is still being processed. | Wait a moment, then retry with the same Idempotency-Key. |
| 409 | quote_already_used | The quote was already accepted. | Look up the trade: GET /v1/quotes/{id} has its trade_id. |
| 413 | payload_too_large | The request body is larger than 8 KB. | Keep request bodies under 8 KB. |
| 415 | unsupported_media_type | Request bodies must be application/json. | Send Content-Type: application/json. |
| 422 | insufficient_funds | The available balance doesn't cover the trade, gift card or withdrawal. | Deposit, or ask for a smaller amount. |
| 422 | amount_below_minimum | The amount is below the minimum. | Raise the amount; GET /v1/assets lists the minimum. |
| 422 | amount_above_maximum | The amount is above the maximum. | Lower the amount, or split it over time. |
| 422 | limit_exceeded | A daily or 30-day limit would be exceeded. | Wait for the daily or 30-day window; GET /v1/limits shows your use. |
| 422 | key_limit_reached | The account already has as many API keys as it can (5): revoke one in Settings → API first. | Revoke a key you no longer use in Settings → API, then make a new connect code. |
| 422 | quote_expired | The quote has expired. | Create a new quote and accept it within its lifetime. |
| 422 | price_moved | The market moved too far from the quoted price. | Create a new quote. |
| 422 | asset_not_tradable | The asset can't be traded right now. | Check buy_enabled and sell_enabled in GET /v1/assets. |
| 422 | asset_not_withdrawable | The asset can't be withdrawn on this network right now. | Check the asset and network, or withdraw in the app. |
| 429 | rate_limited | Too many requests. Wait for Retry-After seconds. | Wait Retry-After seconds, then slow down. |
| 429 | too_many_concurrent_requests | Too many requests in flight for this key or account. | Wait for a request in flight to finish; Retry-After is 1. |
| 429 | key_suspended | The key is suspended, for example after sustained rate limiting. | Stop the client and fix the loop. The suspension lifts after 15 minutes. |
| 500 | internal_error | Something went wrong on our side. | Retry later. If it persists, contact us with the request_id. |
| 502 | bad_gateway | An upstream service answered unexpectedly. | Retry with backoff; a POST only with the same Idempotency-Key. |
| 503 | trading_halted | Trading is paused: switched off, or paused for this asset for a short while after a fast price move. | Retry later; GET /v1/status shows trading_enabled. |
| 503 | maintenance | The API is read-only for maintenance. | Reads still work. Retry writes later. |
| 503 | overloaded | The service is overloaded. Retry after Retry-After seconds. | Wait Retry-After seconds, then retry. |
| 503 | service_unavailable | The service is temporarily unavailable. | Retry with backoff; a POST only with the same Idempotency-Key. |
| 504 | gateway_timeout | An upstream service didn't answer in time. A POST may still complete; retry with the same Idempotency-Key. | The request may have gone through. Retry with the same Idempotency-Key. |
Each endpoint's reference page lists the codes it can return.
Handling errors
The SDKs turn every error into an ApiError with status, code, message and requestId (request_id in Python), plus retryAfter (retry_after) when the response had a Retry-After header. Subclasses group the statuses:
| Class | Status |
|---|---|
AuthenticationError | 401 |
PermissionError | 403 |
NotFoundError | 404 |
ConflictError | 409 |
ValidationError | 400, 422 |
RateLimitError | 429 |
ServiceError | 5xx |
ConnectionError | no response (network failure or timeout) |
import { ApiError, Myntkaup, RateLimitError } from "@myntkaup/api";
const client = new Myntkaup();
try {
const trade = await client.buy({ asset: "BTC", quoteAmount: "25.00" });
console.log(trade.status);
} catch (error) {
if (error instanceof RateLimitError) {
console.warn(`Slow down; retry in ${error.retryAfter} s (${error.requestId})`);
} else if (error instanceof ApiError && ["price_moved", "quote_expired"].includes(error.code)) {
// The market moved: decide whether to try again with a new quote.
} else {
throw error;
}
}import myntkaup
from myntkaup import Myntkaup
client = Myntkaup()
try:
trade = client.buy(asset="BTC", quote_amount="25.00")
print(trade["status"])
except myntkaup.RateLimitError as error:
print(f"Slow down; retry in {error.retry_after} s ({error.request_id})")
except myntkaup.ApiError as error:
if error.code not in ("price_moved", "quote_expired"):
raise
# The market moved: decide whether to try again with a new quote.Which errors to retry
- Retry after waiting:
429 rate_limited,429 too_many_concurrent_requests,503 overloadedand503 service_unavailable(honourRetry-After), and502and504. - Retry a
POSTonly with the sameIdempotency-Key. After a502,504or a dropped connection the request may have gone through; the same key returns the first result instead of doing it twice. See Idempotency. - Wait, then retry with the same key:
409 idempotency_in_progress. - Don't retry as is: every other
4xx. Change the request (or the key, or the quote) first. - Never retry:
429 key_suspended. Stop and fix the client.
The SDKs handle the first two cases for you: a GET is retried on 429 (except key_suspended), 502, 503, 504 and network errors, and a POST only when it carries an Idempotency-Key. They retry at most twice by default, with exponential backoff and jitter, and honour Retry-After.