Quick Start

Make your first authenticated API call to the CoinMENA Partner API in about 5 minutes.

This guide walks you through your first API call to CoinMENA — from connectivity check to a fully signed, authenticated request. Estimated time: ~5 minutes.

By the end of this guide, you will:

  • Confirm your connection to the CoinMENA Partner API
  • Understand the three headers required for authenticated requests
  • Make your first signed request and receive a valid response
🛡️

Examples target the production environment

All examples in this guide use the production base URL: https://external-api.coinmena.com. To run them against the sandbox instead, contact [email protected] for sandbox credentials and replace the base URL in the code samples.


Prerequisites

Before you start, make sure you have:

RequirementDetails
EnvironmentProduction: https://external-api.coinmena.com
Sandbox: contact [email protected] for credentials
Partner IDProvided by CoinMENA after your partner account is created
Ed25519 private keyGenerated on your side — your public key must be shared with CoinMENA before making signed requests
📘

Placeholders in the examples below

Replace your_partner_id with your actual Partner ID, and <your_generated_signature> with the Base64 signature generated by the Python or Node.js script in Step 2.


Step 1: Your First Public API Call

Confirm connectivity — no authentication required.

Public endpoints do not require signing. Let's start by fetching the list of supported assets to confirm you can reach the API.

curl https://external-api.coinmena.com/v1/public/assets

Response — 200 OK

{
  "items": [
    {
      "id": "BTC",
      "type": "crypto",
      "name_en": "Bitcoin",
      "decimal_places": 8
    },
    {
      "id": "USD",
      "type": "fiat",
      "name_en": "US Dollar",
      "decimal_places": 2
    }
  ]
}

If you see a valid response with an items array, you are connected to the API and ready for authenticated requests.


Step 2: Your First Authenticated API Call

Sign a request and call a partner endpoint.

All authenticated requests must be signed using your Ed25519 private key. An invalid, missing, or expired signature results in a 401 Unauthorized response.

The three required headers

Every signed request must include:

HeaderValue
X-Partner-IDYour partner identifier
X-TimestampCurrent Unix timestamp in milliseconds
X-SignatureBase64-encoded Ed25519 signature of the canonical string

The examples below show how to generate these headers and call GET /v1/partner/asset-pairs — a good choice for your first authenticated call because it is read-only, requires no prior setup, and confirms that your partner account is active and your signature is valid.

Language examples

Pick the language that matches your stack. All three examples do exactly the same thing.

cURL

curl -X GET "https://external-api.coinmena.com/v1/partner/asset-pairs" \
  -H "X-Partner-ID: your_partner_id" \
  -H "X-Timestamp: 1737654321000" \
  -H "X-Signature: <your_generated_signature>"
📘

The cURL example assumes the signature has already been generated. Use the Python or Node.js examples below to compute it programmatically, then paste the output into the cURL command.

Python

import time
import hashlib
import base64
import requests
from cryptography.hazmat.primitives.serialization import load_pem_private_key

with open("private_key.pem", "rb") as f:
    private_key = load_pem_private_key(f.read(), password=None)

# Build the canonical string: {TIMESTAMP}{METHOD}{PATH}{SHA256_BODY_HASH}
timestamp = str(int(time.time() * 1000))
method = "GET"
path = "/v1/partner/asset-pairs"
body = ""
body_hash = hashlib.sha256(body.encode("utf-8")).hexdigest()
canonical = f"{timestamp}{method}{path}{body_hash}"

# Sign and Base64-encode the canonical string
signature_bytes = private_key.sign(canonical.encode("utf-8"))
signature = base64.b64encode(signature_bytes).decode()

headers = {
    "X-Partner-ID": "your_partner_id",
    "X-Timestamp": timestamp,
    "X-Signature": signature,
    "Accept": "application/json"
}

# Send the signed request
response = requests.get(
    "https://external-api.coinmena.com/v1/partner/asset-pairs",
    headers=headers
)
print(response.json())

Node.js (v18+)

import crypto from "crypto";
import fs from "fs";

const privateKey = crypto.createPrivateKey(fs.readFileSync("private_key.pem", "utf8"));

// Build the canonical string: {TIMESTAMP}{METHOD}{PATH}{SHA256_BODY_HASH}
const timestamp = Date.now().toString();
const method = "GET";
const path = "/v1/partner/asset-pairs";
const body = "";
const bodyHash = crypto.createHash("sha256").update(Buffer.from(body, "utf8")).digest("hex");
const canonical = `${timestamp}${method}${path}${bodyHash}`;

// Sign and Base64-encode the canonical string
const signatureBuffer = crypto.sign(null, Buffer.from(canonical, "utf8"), privateKey);
const signature = signatureBuffer.toString("base64");

// Send the signed request using the built-in fetch API (Node.js 18+)
const response = await fetch("https://external-api.coinmena.com/v1/partner/asset-pairs", {
  method: "GET",
  headers: {
    "X-Partner-ID": "your_partner_id",
    "X-Timestamp": timestamp,
    "X-Signature": signature,
    "Accept": "application/json"
  }
});

const data = await response.json();
console.log(data);

What success looks like

A successful response returns a 200 OK with a list of asset pairs:

Response — 200 OK

{
  "items": [
    {
      "id": "BTC-USD",
      "base_id": "BTC",
      "quote_id": "USD",
      "buy": "67550.75",
      "sell": "67450.25",
      "tradable": true
    }
  ]
}

If you see items in the response, your signature validated successfully — authentication is working.

⚠️

Got a 401 Unauthorized?

A 401 means your signature, timestamp, or headers were rejected by the server. See the Authentication guide's troubleshooting section for a systematic debugging checklist.


Ready to Go Deeper?

The examples above show the minimum needed to get started. For the full signing rules, canonical string breakdown, edge cases, and a detailed troubleshooting checklist — see the Authentication guide.



What’s Next
Next StepDescription
AuthenticationFull breakdown of the signing algorithm, rules, and troubleshooting
IP WhitelistingAdd a second security layer to your integration
Error CodesReference for every error the API returns