SDKs and CLI
Node.js SDK
@myntkaup/api: a typed client for Node.js 18 and later, with no runtime dependencies. It signs requests, retries safely and returns the API's own JSON.
Install
npm install @myntkaup/api- ESM, with TypeScript types included.
- No runtime dependencies: signing uses
node:cryptoand requests use the globalfetch. - Server-side only. A private key never belongs in a browser.
Configure
import { Myntkaup } from "@myntkaup/api";
// Reads MYNTKAUP_API_KEY_ID and MYNTKAUP_API_PRIVATE_KEY from the environment…
const client = new Myntkaup();
// …or give everything explicitly.
const explicit = new Myntkaup({
keyId: process.env.MYNTKAUP_API_KEY_ID,
privateKey: process.env.MYNTKAUP_API_PRIVATE_KEY,
timeoutMs: 30_000,
maxRetries: 2,
});| Option | Default | Meaning |
|---|---|---|
keyId | MYNTKAUP_API_KEY_ID | The key id, mk_live_… or mk_test_…. |
privateKey | MYNTKAUP_API_PRIVATE_KEY | The private key, mk_sk_…. |
baseUrl | https://public-api.myntkaup.is; staging for a mk_test_ key | Where requests go. |
timeoutMs | 30000 | Per attempt, in milliseconds. |
maxRetries | 2 | Retries after the first attempt. |
fetch | the global fetch | Your own fetch, for tests or proxies. |
Methods
| Method | Endpoint |
|---|---|
client.status() | GET /v1/status (unsigned) |
client.me() | GET /v1/me |
client.revokeKey() | POST /v1/me/key/revoke |
client.claimKeyPairing({ code, publicKey, client }) | POST /v1/key-pairings/claim (unsigned) |
client.assets.list() | GET /v1/assets |
client.prices.list() | GET /v1/prices |
client.prices.get("BTC") | GET /v1/prices/{asset} |
client.balances.list() | GET /v1/balances |
client.limits.get() | GET /v1/limits |
client.quotes.create({ asset, side, quoteAmount }) | POST /v1/quotes |
client.quotes.get(id) | GET /v1/quotes/{id} |
client.trades.create({ quoteId, idempotencyKey? }) | POST /v1/trades |
client.trades.get(id) | GET /v1/trades/{id} |
client.trades.list(params?) | GET /v1/trades, one page |
client.trades.listAll(params?) | every page, as an async iterator |
client.transactions.list / get / listAll | GET /v1/transactions[/{id}] |
client.giftcards.create({ asset, amount, recipientName?, idempotencyKey? }) | POST /v1/giftcards |
client.giftcards.list / get / listAll | GET /v1/giftcards[/{id}] |
client.giftcards.pdf(id) | GET /v1/giftcards/{id}/pdf, as a Uint8Array |
quotes.create takes quoteAmount or baseAmount, exactly one. Each endpoint's reference page has a sample.
Fields and amounts
- Request fields are camelCase and sent as the API's snake_case:
quoteAmountbecomesquote_amount. - Responses are returned as the API sends them, in snake_case, so the JSON examples in these docs apply as they are:
quote.base_amount,trade.filled_at. - Amounts are decimal strings, in both directions. Never pass numbers.
Helpers
client.buy() and client.sell() create a quote and accept it. If the trade comes back pending, they poll it for up to 30 seconds with backoff, and return the trade.
const trade = await client.buy({ asset: "BTC", quoteAmount: "100.00" });
if (trade.status !== "filled") console.warn("Not filled yet:", trade.id, trade.status);Retries and idempotency
- Requests are retried at most
maxRetriestimes, with exponential backoff and jitter, honouringRetry-After. - A
GETis retried on429,502,503,504and network errors. APOSTis retried only when it has anIdempotency-Key. 401,403,409,422and429 key_suspendedare never retried.trades.createandgiftcards.createsend a randomIdempotency-Keyunless you passidempotencyKey;quotes.createsends one only if you pass it. See Idempotency.
Errors
Every non-2xx answer throws an ApiError with status, code, message, requestId, and retryAfter (seconds) plus the rate-limit headers when present. Network failures throw ConnectionError.
| Class | Status |
|---|---|
AuthenticationError | 401 |
PermissionError | 403 |
NotFoundError | 404 |
ConflictError | 409 |
ValidationError | 400, 422 |
RateLimitError | 429 |
ServiceError | 5xx |
import { ApiError, NotFoundError } from "@myntkaup/api";
try {
await client.trades.get("tr_01JB8X2Q4M7Z3V9K5T1N6R0P2W");
} catch (error) {
if (error instanceof NotFoundError) console.log("No such trade");
else if (error instanceof ApiError) console.error(error.code, error.requestId);
else throw error;
}Signing only
To use another HTTP client, the package exports its signing function. It returns the four MK-* headers:
import { signRequest } from "@myntkaup/api";
const body = JSON.stringify({ asset: "BTC", side: "buy", quote_amount: "100.00" });
const headers = signRequest({
keyId: process.env.MYNTKAUP_API_KEY_ID!,
privateKey: process.env.MYNTKAUP_API_PRIVATE_KEY!,
method: "POST",
pathAndQuery: "/v1/quotes",
body,
});Testing
Pass your own fetch to test code that uses the client without network access:
const client = new Myntkaup({
keyId: "mk_test_0123456789abcdefghij",
privateKey: "mk_sk_nWGxne_9WmC6hEr0kuwsxERJxWl7MmkZcDusAxyuf2A", // RFC 8032 test key, public
fetch: async () =>
Response.json({
status: "ok",
read_only: false,
trading_enabled: true,
giftcards_enabled: true,
server_time: "2026-11-03T10:15:10Z",
}),
});