Skip to main content

Authentication & signing

Base URL and format​

  • Endpoint: https://api.cobrex.com
  • Format: requests and responses are JSON (Content-Type: application/json where a body exists).
  • Keys: created in dashboard settings.

HTTP status codes​

RangeMeaning
200Success (in Cobrex docs, success is usually 200).
4xxClient error: signature, parameters, permissions, not found.
5xxServer error; retry later if appropriate.

Required headers​

Every protected request must include:

1. x-uid or x-mid​

  • x-uid — user id (u-…). Use for account-level operations.
  • x-mid — merchant id (m-…). Use for merchant-context operations (e.g. payout from the merchant-linked account).

Send exactly one of these, depending on the flow.

2. x-timestamp​

Current time as whole seconds since 1970-01-01 UTC (Unix time). Reduces replay risk; the server may reject stale or far-future timestamps.

const timestampSec = Math.floor(Date.now() / 1000);

Do not use raw Date.now() — those are milliseconds and will not match the expected signature.

3. x-signature​

Hex HMAC-SHA256 of the canonical string (below), keyed with your API secret.

Building the string to sign (step by step)​

  1. Full request URL — exactly as you call the API:
    https + :// + host + path + query string (if any).
    Query parameter order must match the outgoing request.
  2. Line feed LF \n.
  3. Seconds only — the same value you send in x-timestamp.
  4. If the request has a body (e.g. JSON POST):
    • \n
    • Raw body — the exact bytes sent (after JSON.stringify or equivalent).
      Whitespace and key order must match the real body.

If there is no body (typical GET): stop after step 3. Do not add an extra \n for an “empty body”.

POST example​

Canonical string (three segments separated by \n):

https://api.cobrex.com/wallet
1752675847
{"asset":["USDT","TRX"],"network":"TRON","client":"test1","callback":"https://api.cobrex.com/webhook"}

GET example​

https://api.cobrex.com/payment/p-1a9a67a1-46ce-11f1-8b35-7cc255316480
1752675847

Computing the hex signature in code​

Same idea as CryptoJS / Postman snippets, without tying to a tool:

  1. Build canonicalString as above.
  2. HMAC-SHA256 over canonicalString with API secret.
  3. Encode digest as hex (lowercase is typical for comparison).

Node.js (crypto):

const crypto = require('crypto');

function cobrexRequestSignature(canonicalString, apiSecret) {
return crypto.createHmac('sha256', apiSecret).update(canonicalString).digest('hex');
}

Use any vetted HMAC-SHA256 implementation elsewhere; the digest must match when the canonical string is identical.

Common mistakes​

IssueEffect
Milliseconds in x-timestampSignature mismatch.
Different JSON key order or spacingDifferent body → different signature. Serialize once; reuse for body and signing.
URL missing query or wrong param orderCanonical string differs from server.
Extra \n when there is no bodySignature mismatch.

Webhooks: verifying inbound requests​

Cobrex calls your URL when a payment or payout status changes. The body is JSON (payment object or payout object).

Option A — IP allowlist​

Only accept traffic from Cobrex IPs:

46.166.162.83

(Infrastructure may change — confirm the live list with support before production.)

Option B — x-signature header​

On your side:

  1. Read the raw HTTP body as text/buffer before JSON.parse (byte identity matters).

  2. Parse JSON to data for business logic.

  3. Expected signature per Cobrex webhook rules:

    expected = HMAC-SHA256( JSON.stringify(data), api_secret ).digest('hex')

    Use the secret from the dashboard (or a dedicated webhook secret if Cobrex issues one — confirm with support).

    Often it is more reliable to compute HMAC over the raw body string so you do not depend on re-stringifying JSON:

    const crypto = require('crypto');
    const expected = crypto.createHmac('sha256', apiSecret).update(rawBodyString).digest('hex');
  4. Compare expected to the x-signature header using constant-time comparison.


Next: accounts & balances, payments, payouts.