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.

Institutional access only. API keys are available for corporate accounts with approved KYC. Contact business@mintarex.com to get started.

What you can do with the API

Supported currencies

TypeCurrencies
FiatUSD, EUR, GBP, CAD, AED, INR
CryptoBTC, ETH, USDT, USDC, SOL, XRP, ADA, DOGE, LTC, MATIC, TON, and 190+ more
Networks63 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:

HeaderDescription
MX-API-KEYYour public API key (e.g. mx_live_a8f3b2c1d4e5f6a7b8c9)
MX-SIGNATUREHMAC-SHA256 signature of the request (64 hex characters)
MX-TIMESTAMPCurrent Unix timestamp in seconds
MX-NONCEUnique UUID v4 per request (replay protection)
Timestamp window: Requests with a timestamp more than 30 seconds from server time will be rejected. Ensure your clock is NTP-synchronized.

Optional headers

HeaderDescription
MX-IDEMPOTENCY-KEYUUID v4 for safe retries on POST requests. Same key returns cached response within 24h.

Generating the API Key

  1. Log in to the Mintarex Dashboard with a corporate account
  2. Complete corporate KYC verification (must be approved)
  3. Navigate to Settings → API Keys
  4. Click Create API Key
  5. Select your desired permissions (scopes)
  6. Add at least one IP address to the whitelist (required for production keys)
  7. Your API key and secret will be displayed once — save the secret immediately
Save your secret! The API secret is shown only once at creation time. It cannot be recovered. If lost, create a new key.

Key format

API Key:    mx_live_a8f3b2c1d4e5f6a7b8c9d0e1   (32 characters, public)
API Secret: YWJjZGVmZ2hpamtsbW5vcH...          (64 characters, secret — save immediately)

Permission scopes

ScopeDescription
read:accountView account info, fees, limits
read:walletView balances, deposit addresses
read:tradeView trade history
read:marketView market data and instruments
trade:quoteRequest RFQ quotes
trade:executeExecute trades (accept quotes)
withdraw:cryptoSubmit crypto withdrawals (requires pre-whitelisted addresses)
withdraw:fiatSubmit fiat withdrawals
webhook:manageCreate/manage webhook endpoints
stream:marketSubscribe to price streams (SSE)
stream:accountSubscribe 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
ComponentDescriptionExample
METHODHTTP method (uppercase)GET
PATHFull path including query string/v1/account/balances?currency_type=crypto
TIMESTAMPUnix timestamp in seconds1712582345
NONCEUUID v4 (unique per request)550e8400-e29b-41d4-a716-446655440000
BODY_HASHSHA-256 hex of request bodye3b0c44298fc1c14... (empty body hash for GET)
For GET/DELETE requests: Use SHA-256 hash of empty string: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855

Step 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.

TierRead /minWrite /minQuote /minExecute /minWithdraw /min
Starter60201053
Professional1204020105
Enterprise300100603015

Endpoint classification

BucketEndpoints
ReadAll GET requests (balances, history, fees, limits)
WritePOST/DELETE requests not in other buckets (webhooks, address management)
QuotePOST /v1/rfq — requesting a quote
ExecutePOST /v1/rfq/{id}/accept — executing a trade
WithdrawPOST /v1/crypto/withdraw, POST /v1/fiat/withdraw

Rate limit headers

Every response includes IETF-standard rate limit headers:

HeaderDescription
RateLimit-LimitMaximum requests allowed in the current window
RateLimit-RemainingRequests remaining in the current window
RateLimit-ResetSeconds until the window resets
Retry-AfterSeconds 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

StatusMeaning
200Success
400Bad request (invalid parameters)
401Authentication failed
403Forbidden (IP blocked, insufficient scope, feature not enabled)
404Resource not found
413Request body too large (max 100KB)
422Unprocessable (e.g. idempotency key reused with different body)
429Rate limit exceeded
500Internal server error
502Upstream service unavailable
503Service temporarily unavailable

Authentication error codes

CodeDescription
MISSING_AUTH_HEADERSRequired headers missing (MX-API-KEY, MX-SIGNATURE, MX-TIMESTAMP, MX-NONCE)
INVALID_KEY_FORMATKey doesn't match mx_live_ or mx_test_ + 24 hex chars
INVALID_KEYAPI key not found
KEY_DISABLEDKey disabled by owner
KEY_SUSPENDEDKey suspended by administrator
KEY_REVOKEDKey permanently revoked
KEY_EXPIREDKey past expiry date
KEY_AUTO_DISABLEDKey auto-disabled due to repeated auth failures
TIMESTAMP_SKEWTimestamp outside 30-second window
NONCE_REPLAYNonce already used (possible replay attack)
INVALID_SIGNATUREHMAC signature verification failed
IP_NOT_WHITELISTEDClient IP not in key's whitelist
INSUFFICIENT_SCOPEKey lacks required permission scope
TRADING_NOT_ENABLEDTrading not enabled for this key (contact support)
WITHDRAWALS_NOT_ENABLEDWithdrawals not enabled for this key (contact support)
RATE_LIMIT_EXCEEDEDToo 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
Best practice: Always use idempotency keys for trade execution and withdrawal requests. If your connection drops mid-request, you can safely retry without risk of duplicate execution.

Get Balances

GET /v1/account/balances

Returns all wallet balances. Requires read:wallet scope.

Query parameters

ParameterTypeRequiredDescription
currency_typestringNofiat or crypto
include_emptybooleanNoInclude 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.

Zero slippage. Once quoted, the price is locked. You get exactly the quoted price when you accept.
All-in pricing. The quoted price includes our OTC spread. There are no separate fees or hidden charges. The price you see is the price you pay.

Request

{ "base": "BTC", "quote": "USD", "side": "buy", "amount": "1000.00", "amount_type": "quote" }
FieldTypeRequiredDescription
basestringYesBase currency (BTC, ETH, etc.)
quotestringYesQuote currency (USD, EUR, AED, etc.)
sidestringYesbuy or sell
amountstringYesTrade amount (decimal string, must be finite and positive)
amount_typestringYesbase 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

FieldTypeDescription
quote_idstringUnique quote identifier (UUID)
pricestringExecutable price with spread included (all-in, no separate fee)
base_amountstringAmount of base currency in the trade
quote_amountstringAmount of quote currency in the trade
expires_atstringISO 8601 timestamp when the quote expires
expires_in_msintegerMilliseconds until expiry (typically 30000)
signaturestringHMAC signature — echo this back when accepting
Note: The 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"
}
FieldTypeRequiredDescription
basestringYesBase currency (must match the quote)
quotestringYesQuote currency (must match the quote)
sidestringYesbuy or sell (must match the quote)
idempotency_keystringYesUUID v4 for safe retries (max 128 chars)
quoted_pricestringYesEcho from the quote response
quoted_base_amountstringYesEcho from the quote response
quoted_quote_amountstringYesEcho from the quote response
quote_timestampstringYesTimestamp from when the quote was received
quote_signaturestringYesSignature 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

ParameterTypeDescription
basestringFilter by base currency (e.g. BTC)
quotestringFilter by quote currency (e.g. USD)
sidestringFilter by side (buy or sell)
limitintegerResults per page (default 50, max 200)
offsetintegerResults to skip
fromstringStart date (ISO 8601)
tostringEnd 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

ParameterTypeRequiredDescription
coinstringYesCoin symbol (e.g. BTC, USDT)
networkstringYesNetwork (e.g. bitcoin, tron, ethereum)

Response

{
  "coin": "USDT",
  "network": "tron",
  "address": "TN3W4H6rK2ce4vX9YnFQHwKENnHjoxb3m9",
  "tag": null,
  "requires_tag": false,
  "min_deposit": "1.00000000",
  "confirmations_required": 20
}
Tag/Memo: Some networks (XRP, XLM, BNB, ATOM) require a tag or memo in addition to the address. Check the 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"
}
Address whitelisting required. Withdrawals can only be sent to pre-whitelisted addresses. New addresses have a 24-hour cooling period before they can be used. Add addresses via the dashboard or the address management endpoints.

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"
}
Bank accounts: Fiat withdrawals can only go to bank accounts previously registered and verified via the dashboard. The API does not allow adding new bank accounts — add them through the dashboard first, then use them via the API.

Webhooks

Register HTTPS endpoints to receive push notifications for trades, deposits, withdrawals, and account events.

How it works

  1. Register a webhook URL via POST /v1/webhooks
  2. Subscribe to specific event types
  3. Mintarex signs each delivery with HMAC-SHA256 using your webhook secret
  4. Your server verifies the signature and responds with 200 OK within 10 seconds
  5. Failed deliveries retry with exponential backoff (30s, 1m, 2m, 4m, 8m, 16m, 32m, 64m — max 8 attempts)

Webhook delivery headers

HeaderDescription
X-Mintarex-SignatureHMAC-SHA256 of the request body using your webhook secret
X-Mintarex-TimestampUnix timestamp of the delivery
X-Mintarex-EventEvent 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

EventDescription
trade.executedRFQ order was filled successfully
trade.failedRFQ order was rejected (insufficient balance, expired quote, etc.)
deposit.detectedCrypto deposit seen on-chain (unconfirmed)
deposit.confirmedDeposit reached required confirmations and credited to balance
withdrawal.broadcastingWithdrawal approved, transaction broadcasting to network
withdrawal.completedWithdrawal confirmed on-chain or fiat sent
withdrawal.failedWithdrawal failed or was rejected
account.balance_updatedAccount 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

ParameterTypeDescription
instrumentsstringComma-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

Changelog

2026-04-09 — v1.0.0 (Initial Release)

Support

Need help integrating? We're here to help.

Response time: We typically respond to integration support requests within 4 business hours.

© 2026 Mintarex. All rights reserved.