Welcome
The Mintarex API provides programmatic access to OTC crypto trading, wallet management, and real-time market data for institutional clients.
Mintarex is an OTC (over-the-counter) trading platform — not an exchange. We use a Request-for-Quote (RFQ) model: you request a price, we lock it, you execute with zero slippage. This is what treasury desks, payment processors, and remittance companies need.
What you can do with the API
- Trade — Request RFQ quotes and execute trades across 200+ crypto pairs and 6 fiat currencies (USD, EUR, GBP, CAD, AED, INR)
- Wallets — Check balances, get deposit addresses, submit withdrawals across 63 blockchain networks
- Market Data — Real-time price feeds via Server-Sent Events (SSE)
- Webhooks — Receive push notifications for trade fills, deposits, and withdrawals
- Account — View balances, fee rates, and transaction limits
Supported currencies
| Type | Currencies |
|---|---|
| Fiat | USD, EUR, GBP, CAD, AED, INR |
| Crypto | BTC, ETH, USDT, USDC, SOL, XRP, ADA, DOGE, LTC, MATIC, TON, and 190+ more |
| Networks | 63 blockchain networks (62 EVM + Bitcoin, Solana, Cardano, XRP, TON, Tron, etc.) |
Base URL
All API requests are made to:
https://institutional.mintarex.com/v1
All requests must use HTTPS. HTTP requests are automatically redirected.
Health check
GET https://institutional.mintarex.com/health
Response:
{
"ok": true,
"service": "mintarex-otc-gateway",
"version": "0.0.1",
"timestamp": "2026-04-09T09:33:04.593Z",
"uptime_seconds": 3600
}
Authentication
Every API request must include four authentication headers:
| Header | Description |
|---|---|
MX-API-KEY | Your public API key (e.g. mx_live_a8f3b2c1d4e5f6a7b8c9) |
MX-SIGNATURE | HMAC-SHA256 signature of the request (64 hex characters) |
MX-TIMESTAMP | Current Unix timestamp in seconds |
MX-NONCE | Unique UUID v4 per request (replay protection) |
Optional headers
| Header | Description |
|---|---|
MX-IDEMPOTENCY-KEY | UUID v4 for safe retries on POST requests. Same key returns cached response within 24h. |
Generating the API Key
- Log in to the Mintarex Dashboard with a corporate account
- Complete corporate KYC verification (must be approved)
- Navigate to Settings → API Keys
- Click Create API Key
- Select your desired permissions (scopes)
- Add at least one IP address to the whitelist (required for production keys)
- Your API key and secret will be displayed once — save the secret immediately
Key format
API Key: mx_live_a8f3b2c1d4e5f6a7b8c9d0e1 (32 characters, public) API Secret: YWJjZGVmZ2hpamtsbW5vcH... (64 characters, secret — save immediately)
Permission scopes
| Scope | Description |
|---|---|
read:account | View account info, fees, limits |
read:wallet | View balances, deposit addresses |
read:trade | View trade history |
read:market | View market data and instruments |
trade:quote | Request RFQ quotes |
trade:execute | Execute trades (accept quotes) |
withdraw:crypto | Submit crypto withdrawals (requires pre-whitelisted addresses) |
withdraw:fiat | Submit fiat withdrawals |
webhook:manage | Create/manage webhook endpoints |
stream:market | Subscribe to price streams (SSE) |
stream:account | Subscribe to account event streams (SSE) |
IP whitelisting
Production keys require at least one IP address. Requests from non-whitelisted IPs are rejected with 403 IP_NOT_WHITELISTED. Supports IPv4, IPv6, and CIDR notation (e.g. 203.0.113.0/24).
Signing Requests
Every authenticated request must be signed with HMAC-SHA256 using your API secret.
Step 1: Build the canonical string
Concatenate with newline (\n) separator:
canonical = METHOD + "\n" + PATH + "\n" + TIMESTAMP + "\n" + NONCE + "\n" + BODY_HASH
| Component | Description | Example |
|---|---|---|
METHOD | HTTP method (uppercase) | GET |
PATH | Full path including query string | /v1/account/balances?currency_type=crypto |
TIMESTAMP | Unix timestamp in seconds | 1712582345 |
NONCE | UUID v4 (unique per request) | 550e8400-e29b-41d4-a716-446655440000 |
BODY_HASH | SHA-256 hex of request body | e3b0c44298fc1c14... (empty body hash for GET) |
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855Step 2: Compute the HMAC
signature = HMAC-SHA256(api_secret, canonical_string).hex() // 64 hex characters
Step 3: Send the headers
MX-API-KEY: mx_live_a8f3b2c1d4e5f6a7b8c9d0e1 MX-TIMESTAMP: 1712582345 MX-NONCE: 550e8400-e29b-41d4-a716-446655440000 MX-SIGNATURE: 7d9b2c5f8a1e4b6d9c2e5f8a1b4c7d0e3f6a9b2c5f8a1e4b6d9c2e5f8a1b4c7
Code Samples
Complete signing and request examples in 5 languages.
Node.js
const crypto = require('node:crypto');
const https = require('node:https');
const API_KEY = 'mx_live_your_key_here';
const API_SECRET = 'your_secret_here';
const BASE = 'https://institutional.mintarex.com';
function signedRequest(method, path, body = '') {
const timestamp = Math.floor(Date.now() / 1000).toString();
const nonce = crypto.randomUUID();
const bodyStr = typeof body === 'object' ? JSON.stringify(body) : body;
const bodyHash = crypto.createHash('sha256').update(bodyStr).digest('hex');
const canonical = [method, path, timestamp, nonce, bodyHash].join('\n');
const signature = crypto.createHmac('sha256', API_SECRET).update(canonical).digest('hex');
return {
headers: {
'MX-API-KEY': API_KEY, 'MX-TIMESTAMP': timestamp,
'MX-NONCE': nonce, 'MX-SIGNATURE': signature,
'Content-Type': 'application/json',
},
body: bodyStr,
};
}
// GET example
const { headers } = signedRequest('GET', '/v1/account/balances');
https.get(new URL('/v1/account/balances', BASE), { headers }, (res) => {
let d = ''; res.on('data', c => d += c);
res.on('end', () => console.log(JSON.parse(d)));
});
// POST example (request a quote)
const quoteBody = { base: 'BTC', quote: 'USD', side: 'buy', amount: '1000', amount_type: 'quote' };
const req = signedRequest('POST', '/v1/rfq', quoteBody);
const r = https.request(new URL('/v1/rfq', BASE), {
method: 'POST', headers: req.headers,
}, (res) => {
let d = ''; res.on('data', c => d += c);
res.on('end', () => console.log(JSON.parse(d)));
});
r.write(req.body); r.end();
Python
import hashlib, hmac, json, time, uuid, requests
API_KEY = 'mx_live_your_key_here'
API_SECRET = 'your_secret_here'
BASE = 'https://institutional.mintarex.com'
def signed_request(method, path, body=None):
timestamp = str(int(time.time()))
nonce = str(uuid.uuid4())
body_str = json.dumps(body) if body else ''
body_hash = hashlib.sha256(body_str.encode()).hexdigest()
canonical = f"{method}\n{path}\n{timestamp}\n{nonce}\n{body_hash}"
signature = hmac.new(API_SECRET.encode(), canonical.encode(), hashlib.sha256).hexdigest()
headers = {
'MX-API-KEY': API_KEY, 'MX-TIMESTAMP': timestamp,
'MX-NONCE': nonce, 'MX-SIGNATURE': signature,
'Content-Type': 'application/json',
}
return headers, body_str
# GET example
headers, _ = signed_request('GET', '/v1/account/balances')
resp = requests.get(f'{BASE}/v1/account/balances', headers=headers)
print(resp.json())
# POST example (request a quote)
body = {'base': 'BTC', 'quote': 'USD', 'side': 'buy', 'amount': '1000', 'amount_type': 'quote'}
headers, data = signed_request('POST', '/v1/rfq', body)
resp = requests.post(f'{BASE}/v1/rfq', headers=headers, data=data)
print(resp.json())
Go
package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"fmt"
"io"
"net/http"
"strings"
"time"
"github.com/google/uuid"
)
const (
apiKey = "mx_live_your_key_here"
apiSecret = "your_secret_here"
baseURL = "https://institutional.mintarex.com"
)
func signRequest(method, path, body string) http.Header {
timestamp := fmt.Sprintf("%d", time.Now().Unix())
nonce := uuid.New().String()
h := sha256.Sum256([]byte(body))
bodyHash := hex.EncodeToString(h[:])
canonical := strings.Join([]string{method, path, timestamp, nonce, bodyHash}, "\n")
mac := hmac.New(sha256.New, []byte(apiSecret))
mac.Write([]byte(canonical))
signature := hex.EncodeToString(mac.Sum(nil))
headers := http.Header{}
headers.Set("MX-API-KEY", apiKey)
headers.Set("MX-TIMESTAMP", timestamp)
headers.Set("MX-NONCE", nonce)
headers.Set("MX-SIGNATURE", signature)
headers.Set("Content-Type", "application/json")
return headers
}
func main() {
path := "/v1/account/balances"
req, _ := http.NewRequest("GET", baseURL+path, nil)
req.Header = signRequest("GET", path, "")
resp, err := http.DefaultClient.Do(req)
if err != nil { panic(err) }
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))
}
Java
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.URI;
import java.net.http.*;
import java.security.MessageDigest;
import java.time.Instant;
import java.util.UUID;
public class MintarexApi {
static final String API_KEY = "mx_live_your_key_here";
static final String API_SECRET = "your_secret_here";
static final String BASE_URL = "https://institutional.mintarex.com";
static String sha256(String data) throws Exception {
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] hash = md.digest(data.getBytes("UTF-8"));
StringBuilder sb = new StringBuilder();
for (byte b : hash) sb.append(String.format("%02x", b));
return sb.toString();
}
static String hmacSha256(String key, String data) throws Exception {
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(key.getBytes("UTF-8"), "HmacSHA256"));
byte[] hash = mac.doFinal(data.getBytes("UTF-8"));
StringBuilder sb = new StringBuilder();
for (byte b : hash) sb.append(String.format("%02x", b));
return sb.toString();
}
public static void main(String[] args) throws Exception {
String method = "GET";
String path = "/v1/account/balances";
String timestamp = String.valueOf(Instant.now().getEpochSecond());
String nonce = UUID.randomUUID().toString();
String bodyHash = sha256("");
String canonical = method + "\n" + path + "\n" + timestamp + "\n" + nonce + "\n" + bodyHash;
String signature = hmacSha256(API_SECRET, canonical);
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(BASE_URL + path))
.header("MX-API-KEY", API_KEY)
.header("MX-TIMESTAMP", timestamp)
.header("MX-NONCE", nonce)
.header("MX-SIGNATURE", signature)
.GET().build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
}
}
C#
using System.Security.Cryptography;
using System.Text;
var apiKey = "mx_live_your_key_here";
var apiSecret = "your_secret_here";
var baseUrl = "https://institutional.mintarex.com";
string Sha256(string data) {
var bytes = SHA256.HashData(Encoding.UTF8.GetBytes(data));
return Convert.ToHexString(bytes).ToLower();
}
string HmacSha256(string key, string data) {
using var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(key));
var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(data));
return Convert.ToHexString(hash).ToLower();
}
var method = "GET";
var path = "/v1/account/balances";
var timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString();
var nonce = Guid.NewGuid().ToString();
var bodyHash = Sha256("");
var canonical = $"{method}\n{path}\n{timestamp}\n{nonce}\n{bodyHash}";
var signature = HmacSha256(apiSecret, canonical);
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, baseUrl + path);
request.Headers.Add("MX-API-KEY", apiKey);
request.Headers.Add("MX-TIMESTAMP", timestamp);
request.Headers.Add("MX-NONCE", nonce);
request.Headers.Add("MX-SIGNATURE", signature);
var response = await client.SendAsync(request);
Console.WriteLine(await response.Content.ReadAsStringAsync());
PHP
<?php
$apiKey = 'mx_live_your_key_here';
$apiSecret = 'your_secret_here';
$baseUrl = 'https://institutional.mintarex.com';
function signedRequest($method, $path, $body = '') {
global $apiKey, $apiSecret;
$timestamp = (string)time();
$nonce = sprintf('%s-%s-%s-%s-%s',
bin2hex(random_bytes(4)), bin2hex(random_bytes(2)),
bin2hex(random_bytes(2)), bin2hex(random_bytes(2)),
bin2hex(random_bytes(6)));
$bodyHash = hash('sha256', $body);
$canonical = implode("\n", [$method, $path, $timestamp, $nonce, $bodyHash]);
$signature = hash_hmac('sha256', $canonical, $apiSecret);
return [
'MX-API-KEY: ' . $apiKey,
'MX-TIMESTAMP: ' . $timestamp,
'MX-NONCE: ' . $nonce,
'MX-SIGNATURE: ' . $signature,
'Content-Type: application/json',
];
}
// GET example
$path = '/v1/account/balances';
$headers = signedRequest('GET', $path);
$ch = curl_init($baseUrl . $path);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
echo $response;
// POST example
$path = '/v1/rfq';
$body = json_encode(['base'=>'BTC','quote'=>'USD','side'=>'buy','amount'=>'1000','amount_type'=>'quote']);
$headers = signedRequest('POST', $path, $body);
$ch = curl_init($baseUrl . $path);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
echo $response;
?>
cURL
# Set credentials
API_KEY="mx_live_your_key_here"
API_SECRET="your_secret_here"
# Build signature components
METHOD="GET"
PATH="/v1/account/balances"
TIMESTAMP=$(date +%s)
NONCE=$(python3 -c "import uuid; print(uuid.uuid4())")
BODY_HASH=$(echo -n "" | sha256sum | cut -d' ' -f1)
# Sign
CANONICAL=$(printf "%s\n%s\n%s\n%s\n%s" "$METHOD" "$PATH" "$TIMESTAMP" "$NONCE" "$BODY_HASH")
SIGNATURE=$(echo -ne "$CANONICAL" | openssl dgst -sha256 -hmac "$API_SECRET" | cut -d' ' -f2)
# Request
curl -s "https://institutional.mintarex.com${PATH}" \
-H "MX-API-KEY: ${API_KEY}" \
-H "MX-TIMESTAMP: ${TIMESTAMP}" \
-H "MX-NONCE: ${NONCE}" \
-H "MX-SIGNATURE: ${SIGNATURE}" | python3 -m json.tool
Rate Limits
Rate limits are enforced per API key using a sliding window. Limits vary by endpoint type and your account tier.
| Tier | Read /min | Write /min | Quote /min | Execute /min | Withdraw /min |
|---|---|---|---|---|---|
| Starter | 60 | 20 | 10 | 5 | 3 |
| Professional | 120 | 40 | 20 | 10 | 5 |
| Enterprise | 300 | 100 | 60 | 30 | 15 |
Endpoint classification
| Bucket | Endpoints |
|---|---|
| Read | All GET requests (balances, history, fees, limits) |
| Write | POST/DELETE requests not in other buckets (webhooks, address management) |
| Quote | POST /v1/rfq — requesting a quote |
| Execute | POST /v1/rfq/{id}/accept — executing a trade |
| Withdraw | POST /v1/crypto/withdraw, POST /v1/fiat/withdraw |
Rate limit headers
Every response includes IETF-standard rate limit headers:
| Header | Description |
|---|---|
RateLimit-Limit | Maximum requests allowed in the current window |
RateLimit-Remaining | Requests remaining in the current window |
RateLimit-Reset | Seconds until the window resets |
Retry-After | Seconds to wait before retrying (only on 429 responses) |
Error Codes
All errors return JSON:
{ "error": { "code": "INVALID_SIGNATURE", "message": "Request signature verification failed" } }
HTTP status codes
| Status | Meaning |
|---|---|
| 200 | Success |
| 400 | Bad request (invalid parameters) |
| 401 | Authentication failed |
| 403 | Forbidden (IP blocked, insufficient scope, feature not enabled) |
| 404 | Resource not found |
| 413 | Request body too large (max 100KB) |
| 422 | Unprocessable (e.g. idempotency key reused with different body) |
| 429 | Rate limit exceeded |
| 500 | Internal server error |
| 502 | Upstream service unavailable |
| 503 | Service temporarily unavailable |
Authentication error codes
| Code | Description |
|---|---|
MISSING_AUTH_HEADERS | Required headers missing (MX-API-KEY, MX-SIGNATURE, MX-TIMESTAMP, MX-NONCE) |
INVALID_KEY_FORMAT | Key doesn't match mx_live_ or mx_test_ + 24 hex chars |
INVALID_KEY | API key not found |
KEY_DISABLED | Key disabled by owner |
KEY_SUSPENDED | Key suspended by administrator |
KEY_REVOKED | Key permanently revoked |
KEY_EXPIRED | Key past expiry date |
KEY_AUTO_DISABLED | Key auto-disabled due to repeated auth failures |
TIMESTAMP_SKEW | Timestamp outside 30-second window |
NONCE_REPLAY | Nonce already used (possible replay attack) |
INVALID_SIGNATURE | HMAC signature verification failed |
IP_NOT_WHITELISTED | Client IP not in key's whitelist |
INSUFFICIENT_SCOPE | Key lacks required permission scope |
TRADING_NOT_ENABLED | Trading not enabled for this key (contact support) |
WITHDRAWALS_NOT_ENABLED | Withdrawals not enabled for this key (contact support) |
RATE_LIMIT_EXCEEDED | Too many requests — check RateLimit-* headers |
Idempotency
For safe retries on POST requests (orders, withdrawals), include the MX-IDEMPOTENCY-KEY header with a UUID v4.
MX-IDEMPOTENCY-KEY: 550e8400-e29b-41d4-a716-446655440001
- Same key + same body within 24h: returns the cached response from the first request
- Same key + different body: returns
422 Unprocessable Entity - Keys expire after 24 hours
Pagination
List endpoints (trades, deposits, withdrawals) support cursor-based pagination.
Query parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
limit | integer | 50 | Number of results per page (max 200) |
offset | integer | 0 | Number of results to skip |
from | string | — | Start date (ISO 8601, e.g. 2026-01-01T00:00:00Z) |
to | string | — | End date (ISO 8601) |
sort | string | desc | Sort order: asc or desc |
Example
GET /v1/trades?limit=20&offset=0&from=2026-04-01T00:00:00Z&sort=desc
Response envelope
{
"data": [ ... ],
"pagination": {
"total": 145,
"limit": 20,
"offset": 0,
"has_more": true
}
}
Get Balances
GET /v1/account/balances
Returns all wallet balances. Requires read:wallet scope.
Query parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
currency_type | string | No | fiat or crypto |
include_empty | boolean | No | Include zero-balance wallets (default: true) |
Response
{
"balances": [
{
"currency": "BTC",
"currency_type": "crypto",
"available": "1.25000000",
"locked": "0.10000000",
"pending_in": "0.05000000",
"pending_out": "0.00000000",
"total": "1.35000000",
"usd_value": "88290.15",
"usd_price": "65400.11"
},
{
"currency": "USD",
"currency_type": "fiat",
"available": "50000.00",
"locked": "0.00",
"pending_in": "0.00",
"pending_out": "0.00",
"total": "50000.00"
}
],
"timestamp": "2026-04-09T10:30:00.000Z"
}
Get Single Balance
GET /v1/account/balance/{currency}
Returns balance for a specific currency across all wallet types. Requires read:wallet scope.
Response
{
"currency": "USDT",
"currency_type": "crypto",
"total_available": "125000.00000000",
"total_locked": "5000.00000000",
"total": "130000.00000000",
"by_wallet_type": [
{ "wallet_type": "funding", "available": "125000.00000000", "locked": "5000.00000000" }
],
"timestamp": "2026-04-09T10:30:00.000Z"
}
Get Fee Rates
GET /v1/account/fees
Returns your account's fee rates (may differ from defaults for VIP/institutional accounts). Requires read:account scope.
{
"trading_fee_rate": "0.005",
"fiat_withdrawal_fee_rate": "0.001",
"note": "Fee rates expressed as decimals (0.005 = 0.5%)",
"timestamp": "2026-04-09T10:30:00.000Z"
}
Get Transaction Limits
GET /v1/account/limits
Returns daily and monthly transaction limits by type. Requires read:account scope.
{
"limits": {
"bank_deposit": { "min_amount": "100.00", "max_amount": "1000000.00", "daily_limit": "1000000.00", "monthly_limit": "5000000.00" },
"crypto_withdrawal": { "min_amount": "10.00", "max_amount": "500000.00", "daily_limit": "500000.00", "monthly_limit": "2000000.00" },
"fiat_withdrawal": { "min_amount": "100.00", "max_amount": "500000.00", "daily_limit": "500000.00", "monthly_limit": "2000000.00" }
},
"account_type": "corporate",
"timestamp": "2026-04-09T10:30:00.000Z"
}
Request Quote (RFQ)
POST /v1/rfq
Request a locked-price quote. Valid for 15-30 seconds. Requires trade:quote scope.
Request
{ "base": "BTC", "quote": "USD", "side": "buy", "amount": "1000.00", "amount_type": "quote" }
| Field | Type | Required | Description |
|---|---|---|---|
base | string | Yes | Base currency (BTC, ETH, etc.) |
quote | string | Yes | Quote currency (USD, EUR, AED, etc.) |
side | string | Yes | buy or sell |
amount | string | Yes | Trade amount (decimal string, must be finite and positive) |
amount_type | string | Yes | base or quote — which currency the amount is in |
Response
{
"quote_id": "550e8400-e29b-41d4-a716-446655440000",
"base": "BTC",
"quote": "USD",
"side": "buy",
"price": "72014.25000000",
"base_amount": "0.01388614",
"quote_amount": "1000.00",
"expires_at": "2026-04-09T14:32:18Z",
"expires_in_ms": 30000,
"signature": "c64c9c5ca97b7b1c..."
}
Response fields
| Field | Type | Description |
|---|---|---|
quote_id | string | Unique quote identifier (UUID) |
price | string | Executable price with spread included (all-in, no separate fee) |
base_amount | string | Amount of base currency in the trade |
quote_amount | string | Amount of quote currency in the trade |
expires_at | string | ISO 8601 timestamp when the quote expires |
expires_in_ms | integer | Milliseconds until expiry (typically 30000) |
signature | string | HMAC signature — echo this back when accepting |
price field is NOT the raw market price. It includes the OTC spread. Market/indicative prices are available via GET /v1/instruments and the price stream.Accept Quote
POST /v1/rfq/{quote_id}/accept
Execute a previously received quote before it expires. Requires trade:execute scope.
Request
{
"base": "BTC",
"quote": "USD",
"side": "buy",
"idempotency_key": "unique-uuid-v4",
"quoted_price": "72014.25000000",
"quoted_base_amount": "0.01388614",
"quoted_quote_amount": "1000.00",
"quote_timestamp": "2026-04-09T14:31:48.000Z",
"quote_signature": "echo_from_quote_response"
}
| Field | Type | Required | Description |
|---|---|---|---|
base | string | Yes | Base currency (must match the quote) |
quote | string | Yes | Quote currency (must match the quote) |
side | string | Yes | buy or sell (must match the quote) |
idempotency_key | string | Yes | UUID v4 for safe retries (max 128 chars) |
quoted_price | string | Yes | Echo from the quote response |
quoted_base_amount | string | Yes | Echo from the quote response |
quoted_quote_amount | string | Yes | Echo from the quote response |
quote_timestamp | string | Yes | Timestamp from when the quote was received |
quote_signature | string | Yes | Signature from the quote response (verified server-side) |
Response (200 — filled)
{
"trade_id": "tr_550e8400e29b41d4a716446655440001",
"status": "filled",
"filled_at": "2026-04-09T14:32:01Z",
"base": "BTC",
"quote": "USD",
"side": "buy",
"price": "72014.25000000",
"base_amount": "0.01388614",
"quote_amount": "1000.00"
}
Get Trade History
GET /v1/trades
Paginated list of executed trades. Requires read:trade scope.
Query parameters
| Parameter | Type | Description |
|---|---|---|
base | string | Filter by base currency (e.g. BTC) |
quote | string | Filter by quote currency (e.g. USD) |
side | string | Filter by side (buy or sell) |
limit | integer | Results per page (default 50, max 200) |
offset | integer | Results to skip |
from | string | Start date (ISO 8601) |
to | string | End date (ISO 8601) |
Response
{
"data": [
{
"trade_id": "tr_550e8400...",
"base": "BTC", "quote": "USD", "side": "buy",
"price": "72014.25", "base_amount": "0.01388614",
"quote_amount": "1000.00",
"status": "filled", "created_at": "2026-04-09T14:32:01Z"
}
],
"pagination": { "total": 23, "limit": 50, "offset": 0, "has_more": false }
}
Get Trade Detail
GET /v1/trade/{trade_id}
Returns details of a single trade. Requires read:trade scope.
Get Deposit Address
GET /v1/crypto/deposit-address?coin={symbol}&network={network}
Returns (or creates) a deposit address for the specified coin and network. Requires read:wallet scope.
Query parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
coin | string | Yes | Coin symbol (e.g. BTC, USDT) |
network | string | Yes | Network (e.g. bitcoin, tron, ethereum) |
Response
{
"coin": "USDT",
"network": "tron",
"address": "TN3W4H6rK2ce4vX9YnFQHwKENnHjoxb3m9",
"tag": null,
"requires_tag": false,
"min_deposit": "1.00000000",
"confirmations_required": 20
}
requires_tag field.Submit Crypto Withdrawal
POST /v1/crypto/withdraw
Submit a crypto withdrawal. The destination address must be pre-whitelisted (this replaces 2FA for API clients). Requires withdraw:crypto scope.
Request
{
"coin": "USDT",
"network": "tron",
"amount": "500.00",
"address_id": "addr_550e8400...",
"idempotency_key": "unique-uuid-v4"
}
Response
{
"withdrawal_id": "wd_550e8400...",
"status": "pending_review",
"coin": "USDT", "network": "tron",
"amount": "500.00000000",
"network_fee": "1.00000000",
"estimated_completion": "1-3 business hours"
}
Get Crypto Deposits
GET /v1/crypto/deposits
Paginated list of crypto deposits. Requires read:wallet scope. Supports all pagination parameters.
Response
{
"data": [
{
"deposit_id": "dep_550e8400...",
"coin": "BTC", "network": "bitcoin",
"amount": "0.50000000",
"tx_hash": "abc123...",
"confirmations": 6, "required_confirmations": 3,
"status": "confirmed",
"detected_at": "2026-04-09T10:00:00Z",
"confirmed_at": "2026-04-09T10:45:00Z"
}
],
"pagination": { "total": 5, "limit": 50, "offset": 0, "has_more": false }
}
Get Crypto Withdrawals
GET /v1/crypto/withdrawals
Paginated list of crypto withdrawals. Requires read:wallet scope. Supports all pagination parameters.
Response
{
"data": [
{
"withdrawal_id": "wd_550e8400...",
"coin": "USDT", "network": "tron",
"amount": "500.00000000", "network_fee": "1.00000000",
"destination": "TN3W4H6rK2ce4vX9...",
"tx_hash": "def456...",
"status": "completed",
"submitted_at": "2026-04-09T11:00:00Z",
"completed_at": "2026-04-09T11:15:00Z"
}
],
"pagination": { "total": 3, "limit": 50, "offset": 0, "has_more": false }
}
Initiate Fiat Deposit
POST /v1/fiat/deposit/initiate
Get bank wire instructions for depositing fiat currency. Requires read:wallet scope.
Request
{ "currency": "USD", "amount": "50000.00" }
Response
{
"deposit_id": "dep_fiat_550e8400...",
"currency": "USD", "amount": "50000.00",
"bank_name": "Partner Bank",
"account_name": "Mintarex Ltd",
"account_number": "****1234",
"routing_number": "021000021",
"swift_bic": "BOFAUS3N",
"reference": "MNX-D260409-0001",
"instructions": "Include the reference code in your wire transfer memo",
"expires_at": "2026-04-12T00:00:00Z"
}
Submit Fiat Withdrawal
POST /v1/fiat/withdraw
Submit a fiat withdrawal to a pre-registered bank account. Requires withdraw:fiat scope.
Request
{
"currency": "USD",
"amount": "10000.00",
"payment_method_id": "pm_550e8400...",
"idempotency_key": "unique-uuid-v4"
}
Response
{
"withdrawal_id": "fwd_550e8400...",
"status": "pending",
"currency": "USD",
"amount": "10000.00",
"estimated_arrival": "1-3 business days"
}
Webhooks
Register HTTPS endpoints to receive push notifications for trades, deposits, withdrawals, and account events.
How it works
- Register a webhook URL via
POST /v1/webhooks - Subscribe to specific event types
- Mintarex signs each delivery with HMAC-SHA256 using your webhook secret
- Your server verifies the signature and responds with
200 OKwithin 10 seconds - Failed deliveries retry with exponential backoff (30s, 1m, 2m, 4m, 8m, 16m, 32m, 64m — max 8 attempts)
Webhook delivery headers
| Header | Description |
|---|---|
X-Mintarex-Signature | HMAC-SHA256 of the request body using your webhook secret |
X-Mintarex-Timestamp | Unix timestamp of the delivery |
X-Mintarex-Event | Event type (e.g. trade.executed) |
Delivery payload
{
"id": "evt_550e8400...",
"type": "trade.executed",
"created_at": "2026-04-09T14:32:01Z",
"data": {
"trade_id": "tr_550e8400...",
"base": "BTC", "quote": "USD",
"price": "65432.10", "base_amount": "0.01521"
}
}
Webhook Event Types
| Event | Description |
|---|---|
trade.executed | RFQ order was filled successfully |
trade.failed | RFQ order was rejected (insufficient balance, expired quote, etc.) |
deposit.detected | Crypto deposit seen on-chain (unconfirmed) |
deposit.confirmed | Deposit reached required confirmations and credited to balance |
withdrawal.broadcasting | Withdrawal approved, transaction broadcasting to network |
withdrawal.completed | Withdrawal confirmed on-chain or fiat sent |
withdrawal.failed | Withdrawal failed or was rejected |
account.balance_updated | Account balance changed (any reason) |
Verifying Webhook Signatures
Always verify the X-Mintarex-Signature header before processing.
Node.js
const crypto = require('node:crypto');
function verifyWebhook(rawBody, signature, secret) {
const expected = crypto.createHmac('sha256', secret).update(rawBody).digest('hex');
return crypto.timingSafeEqual(Buffer.from(signature, 'hex'), Buffer.from(expected, 'hex'));
}
app.post('/webhook', express.raw({ type: '*/*' }), (req, res) => {
if (!verifyWebhook(req.body, req.headers['x-mintarex-signature'], WEBHOOK_SECRET)) {
return res.status(401).send('Invalid signature');
}
const event = JSON.parse(req.body);
console.log(event.type, event.data);
res.status(200).send('OK');
});
Python
import hmac, hashlib
def verify_webhook(body: bytes, signature: str, secret: str) -> bool:
expected = hmac.new(secret.encode(), body, hashlib.sha256).hexdigest()
return hmac.compare_digest(signature, expected)
# In Flask:
@app.route('/webhook', methods=['POST'])
def webhook():
if not verify_webhook(request.data, request.headers['X-Mintarex-Signature'], WEBHOOK_SECRET):
return 'Invalid signature', 401
event = request.json
print(event['type'], event['data'])
return 'OK', 200
Price Stream (SSE)
GET /v1/stream/prices?instruments=BTC_USD,ETH_USD
Real-time price updates via Server-Sent Events. Requires stream:market scope. The connection stays open and pushes updates as prices change.
Query parameters
| Parameter | Type | Description |
|---|---|---|
instruments | string | Comma-separated pairs (e.g. BTC_USD,ETH_EUR,SOL_AED) |
Node.js example
const EventSource = require('eventsource');
const url = 'https://institutional.mintarex.com/v1/stream/prices?instruments=BTC_USD,ETH_USD';
const es = new EventSource(url, {
headers: { 'MX-API-KEY': API_KEY, 'MX-TIMESTAMP': ..., 'MX-NONCE': ..., 'MX-SIGNATURE': ... }
});
es.onmessage = (event) => {
const data = JSON.parse(event.data);
console.log(data.instrument, data.price, data.change_24h);
};
Account Stream (SSE)
GET /v1/stream/account
Real-time account events (balance changes, trade fills, withdrawal status) via SSE. Requires stream:account scope.
Event types
balance.updated— balance changedtrade.filled— trade executeddeposit.confirmed— deposit creditedwithdrawal.status— withdrawal status change
Changelog
2026-04-09 — v1.0.0 (Initial Release)
- Account endpoints: balances, single balance, fees, limits
- RFQ trading: quote with all-in spread pricing + accept flow
- Trade history: paginated list + single trade detail
- Public reference data: instruments (4,066 pairs), networks, fee schedule
- Crypto wallet: deposit addresses, deposits, withdrawals with address whitelisting
- Fiat: deposit initiation, withdrawals
- HMAC-SHA256 authentication with nonce + timestamp replay protection
- AES-256-GCM encrypted API key storage with HKDF key derivation
- All-in pricing model: OTC spread baked into quoted price, no separate fees
- Price feed via Varnish cache (same source as dashboard Markets page)
- Webhook delivery with HMAC signature verification
- SSE streaming for prices and account events
- IETF-standard rate limit headers (RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset)
- Full request audit logging to api_request_log table
- Code samples in 7 languages: Node.js, Python, Go, Java, C#, PHP, cURL
Support
Need help integrating? We're here to help.
- Email: business@mintarex.com
- API Status: institutional.mintarex.com/health
- Website: mintarex.com
© 2026 Mintarex. All rights reserved.