Bluket Developer APIv2.3.21
API DOCUMENTATION

Integrate Bluket payments

Bluket gives every approved project three distinct API credentials: a Merchant ID, a Payment API Key and a Payout API Key. The Merchant ID identifies the project; the two API keys are secret signing keys with different permissions.

Base URL https://YOUR-DOMAIN/api · API routes below are shown without the public /api reverse-proxy prefix.

Merchant ID, Payment API Key and Payout API Key

Merchant ID is the UUID of the merchant/project. It is not a password, but it is required on every authenticated Merchant API request so Bluket knows which project the signature belongs to. Send it as X-Merchant-ID. The legacy header name merchant is also accepted.

X-Merchant-ID: 79e9b5d2-....

Payment API Key is a secret HMAC key for incoming-payment operations: creating and reading invoices, static wallets, balances, payment services, payment QR, payment history, exchange-rate calculation, payment discounts and payment/wallet webhook tests.

Payout API Key is a separate secret HMAC key for money-leaving or payout-sensitive operations: creating/calculating/reading/cancelling payouts, payout history/services/webhook resend, payment refunds, blocking/refunding static addresses, internal balance transfers and payout webhook tests.

Do not interchange the two keys. A Payment API Key cannot authenticate a Payout endpoint and a Payout API Key cannot authenticate a Payment endpoint. After a Payout API Key is created/rotated, payouts are intentionally locked for the configured cooling period (24 hours in the current dashboard flow).

Keys are created from Dashboard → Merchant → API keys and are shown in plaintext only once. Store them only on your backend/server. Never put either API key in browser JavaScript, a Telegram Mini App frontend, a mobile APK, HTML or a public repository.

HMAC v2 authentication

HMAC-SHA256 v2 is enabled by default. Sign the exact raw JSON body with the key required by the endpoint.

raw_body = JSON.stringify(payload)
message = X-Timestamp + "." + X-Nonce + "." + raw_body
X-Signature = HMAC_SHA256(SELECTED_API_KEY, message).hex()

The default timestamp window is 120 seconds. The nonce must be 16–128 characters using letters, numbers or ._~-, and every accepted nonce is single-use during the replay-protection window.

X-Merchant-ID: 79e9b5d2-....
X-Timestamp: 1786785000123
X-Nonce: 6xB7q13xGk91L2mQ
X-Signature: <64 lowercase hex chars>
Content-Type: application/json
For /v1/payment, sign with the Payment API Key. For /v1/payout, /v1/payout/calc or /v1/payment/refund, sign with the Payout API Key. Merchant ID is sent in addition to the signature; it is not included as the HMAC secret.

Code examples

Node.js — reusable signer

import crypto from 'node:crypto';

function signedHeaders(merchantId, apiKey, payload) {
  const rawBody = JSON.stringify(payload);
  const timestamp = Date.now().toString();
  const nonce = crypto.randomBytes(18).toString('base64url');
  const message = `${timestamp}.${nonce}.${rawBody}`;
  const signature = crypto.createHmac('sha256', apiKey).update(message).digest('hex');
  return { rawBody, headers: {
    'content-type': 'application/json',
    'x-merchant-id': merchantId,
    'x-timestamp': timestamp,
    'x-nonce': nonce,
    'x-signature': signature
  }};
}

// Payment endpoint -> PAYMENT_API_KEY
const payment = { amount:'10', currency:'USD', order_id:'ORDER-1001' };
let req = signedHeaders(MERCHANT_ID, PAYMENT_API_KEY, payment);
await fetch(BASE_URL + '/v1/payment', { method:'POST', headers:req.headers, body:req.rawBody });

// Payout endpoint -> PAYOUT_API_KEY
const payout = { amount:'5', currency:'USDT', network:'bsc', order_id:'WD-1001', address:'0x...' };
req = signedHeaders(MERCHANT_ID, PAYOUT_API_KEY, payout);
await fetch(BASE_URL + '/v1/payout', { method:'POST', headers:req.headers, body:req.rawBody });

PHP — signature

$payload = ['amount' => '10', 'currency' => 'USD', 'order_id' => 'ORDER-1001'];
$rawBody = json_encode($payload, JSON_UNESCAPED_SLASHES);
$timestamp = (string) round(microtime(true) * 1000);
$nonce = bin2hex(random_bytes(16));
$signature = hash_hmac('sha256', $timestamp . '.' . $nonce . '.' . $rawBody, $PAYMENT_API_KEY);

$headers = [
  'Content-Type: application/json',
  'X-Merchant-ID: ' . $MERCHANT_ID,
  'X-Timestamp: ' . $timestamp,
  'X-Nonce: ' . $nonce,
  'X-Signature: ' . $signature,
];

Create a payment

Credential: Merchant ID + Payment API Key.

An invoice is idempotent by order_id within a merchant. If you omit network/currency, the hosted checkout lets the payer choose first.

POST /v1/payment

{
  "amount": "25.00",
  "currency": "USD",
  "order_id": "order_1001",
  "url_callback": "https://merchant.test/bluket/callback",
  "url_success": "https://merchant.test/order/1001",
  "url_return": "https://merchant.test/cart",
  "lifetime": 1800
}

The administrator controls the global minimum and maximum invoice lifetime. Each merchant has a default inside that range, and an individual invoice may override it with lifetime. In secure custody mode, per-request discount and underpayment-tolerance overrides are ignored; payment pricing changes require the signed-in dashboard and 2FA.

Webhook / callback signature

Callbacks are outbound requests from Bluket to your url_callback. In the current backend, payment, payout and static-wallet callbacks are all signed with the merchant's latest active Payment API Key. The Payout API Key is used to authenticate payout/refund API requests, not to verify callbacks.

Bluket sends two callback signatures for compatibility. First, the JSON body contains sign: MD5(base64(unsigned_json_body) + PAYMENT_API_KEY), where unsigned_json_body is the exact JSON payload before adding the sign field. The same compatibility signature is mirrored in the HTTP sign header.

Second, Bluket sends X-Bluket-Signature, which is HMAC-SHA256 over the final raw callback body including the sign field:

message = X-Bluket-Timestamp + "." + X-Bluket-Nonce + "." + final_raw_callback_body
X-Bluket-Signature = HMAC_SHA256(PAYMENT_API_KEY, message).hex()
merchant: <merchant UUID>
sign: <legacy compatibility signature>
X-Bluket-Timestamp: <unix ms>
X-Bluket-Nonce: <unique nonce>
X-Bluket-Signature: <64 hex chars>
X-Bluket-Event: payment|payout|wallet
X-Bluket-Delivery: <delivery UUID>
{
  "type": "payment",
  "uuid": "...",
  "order_id": "order_1001",
  "status": "paid",
  "is_final": true,
  "payer_amount": "25.14",
  "merchant_amount": "24.89",
  "commission": "0.25",
  "network": "bsc",
  "currency_payment": "USDT",
  "txid": "...",
  "sign": "compatibility-signature"
}

Fulfil orders only from a verified server-to-server callback or a separately authenticated /v1/payment/info lookup. The browser success redirect is navigation only and is never payment proof.

Payouts and refunds

Credential: Merchant ID + Payout API Key.

POST /v1/payout/calc

{
  "amount": "100",
  "currency": "USDT",
  "network": "bsc",
  "address": "0x...",
  "is_subtract": true
}

The Payout API Key is also required by /v1/payment/refund, because a refund can move funds out of custody. Secure custody mode places outgoing payouts/refunds into administrator review before blockchain signing where configured.

Payment lifecycle

checkconfirm_checkpaid / paid_over

Other final or exceptional statuses include wrong_amount, cancel, system_fail, refund_process, refund_fail and refund_paid.

Endpoint reference and required credential

POST/v1/paymentPAYMENT · Create an invoice / hosted checkout
POST/v1/payment/infoPAYMENT · Get payment status
POST/v1/payment/listPAYMENT · Payment history
POST/v1/payment/servicesPAYMENT · Supported currencies and networks
POST/v1/payment/qrPAYMENT · Get hosted invoice QR
POST/v1/payment/resendPAYMENT · Resend final payment webhook
POST/v1/payment/aml-linksPAYMENT · Get configured AML/KYC review link for a locked payment
POST/v1/payment/refundPAYOUT · Refund a paid invoice
POST/v1/walletPAYMENT · Create a static wallet
POST/v1/wallet/infoPAYMENT · Get static-wallet status
POST/v1/wallet/qrPAYMENT · Get static-wallet QR
POST/v1/wallet/block-addressPAYOUT · Block a static deposit address
POST/v1/wallet/blocked-address-refundPAYOUT · Refund a blocked static wallet; admin-restricted in secure custody mode
POST/v1/payout/calcPAYOUT · Calculate payout + platform/network fees
POST/v1/payoutPAYOUT · Create payout
POST/v1/payout/infoPAYOUT · Get payout status
POST/v1/payout/listPAYOUT · Payout history
POST/v1/payout/servicesPAYOUT · Supported payout services
POST/v1/payout/resendPAYOUT · Resend final payout webhook
POST/v1/payout/cancelPAYOUT · Cancel a review-stage payout
POST/v1/balancePAYMENT · Merchant and personal balances
POST/v1/exchange-ratePAYMENT · Calculate exchange rate
GET/v1/exchange-rate/:currency/listPUBLIC · Public rate list; no Merchant ID or API key
POST/v1/payment/discount/listPAYMENT · List payment discounts
POST/v1/payment/discount/setPAYMENT · Disabled in secure custody mode; change pricing from dashboard with 2FA
POST/v1/transfer/to-personalPAYOUT · Internal merchant → personal transfer
POST/v1/transfer/to-businessPAYOUT · Internal personal → merchant transfer
POST/v1/test-webhook/paymentPAYMENT · Test payment webhook; disabled in secure custody mode
POST/v1/test-webhook/payoutPAYOUT · Test payout webhook; disabled in secure custody mode
POST/v1/test-webhook/walletPAYMENT · Test wallet webhook; disabled in secure custody mode
PAYMENT = Merchant ID + Payment API Key. PAYOUT = Merchant ID + Payout API Key. PUBLIC = no Merchant API credential.