Skip to main content

Overview

Below is a brief overview of how to make API calls:
  1. Send your IP address to our support team via email ([email protected]).
  2. Create the JWT token
  3. Generate the bodyhash by taking the JWT token and hashing it with SHA256 using the API Secret
  4. Sign JWTs with the Private Key
  5. Make the API call

Example Implementation

Here’s a complete example of how to implement the authentication process and make your first API call:
const axios = require("axios");
const jwt = require("jsonwebtoken");
const crypto = require("crypto");

// API configuration - replace these placeholders with actual values
const apiKey = "<<REPLACE_HERE>>";           // Your API key identifier
const audience = "<<REPLACE_HERE>>";         // JWT audience (usually the API service identifier)
const apiSecretBase64 = "<<REPLACE_HERE>>";  // Base64-encoded HMAC secret for body hashing
const hmacSecret = Buffer.from(apiSecretBase64, "base64"); // Convert base64 secret to buffer

// Your EC private key (P-256) for JWT signing
const ecPrivateKey = "<<REPLACE_HERE>>";

// API endpoint configuration
const API_PREFIX = "/api/v1/liquidity";
const BASE_URL = `https://api.mansafinance.co${API_PREFIX}`;

/**
 * Builds authentication headers required for API requests
 * Uses JWT with ES256 signing and HMAC-SHA512 body hashing for security
 */
function buildAuthHeaders(path, body = undefined) {
  // Construct the full API path
  const fullPath = `${API_PREFIX}${path}`;

  // JWT timestamp claims (Unix timestamps)
  const now = Math.floor(Date.now() / 1000);
  const nbf = now - 1;  // "Not before" - token valid from 1 second ago
  const iat = now;      // "Issued at" - current timestamp
  const exp = iat + 20; // "Expires" - token expires in 20 seconds (short-lived)
  
  // Prepare request body for hashing (empty object if no body provided)
  const rawBody = body ? JSON.stringify(body) : "{}";

  // Create HMAC-SHA512 hash of path + body + nbf timestamp
  // This prevents replay attacks and ensures request integrity
  const bodyHash = crypto
    .createHmac("sha512", hmacSecret)
    .update(fullPath + rawBody + nbf)
    .digest("base64");

  // JWT payload containing all necessary claims
  const payload = { 
    sub: apiKey,      // Subject - identifies the API client
    uri: fullPath,    // The API endpoint being accessed
    nbf,              // Not before timestamp
    iat,              // Issued at timestamp  
    exp,              // Expiration timestamp
    bodyHash          // Hash of request content for integrity verification
  };

  // Sign the JWT using ES256 algorithm (ECDSA with P-256 and SHA-256)
  const token = jwt.sign(payload, ecPrivateKey, {
    algorithm: "ES256",
    audience,  // Intended recipient of the token
  });

  // Return headers required for authenticated requests
  return {
    "x-api-key": apiKey,              // API key header
    authorization: `Bearer ${token}`, // JWT bearer token
  };
}

// HTTP client wrapper that automatically adds authentication headers
const request = {
  get: (path, config = {}) =>
    axios.get(`${BASE_URL}${path}`, {
      ...config,
      headers: buildAuthHeaders(path), // Automatically add auth headers
    }),
};

/**
 * Main function demonstrating API usage
 * Fetches active corridors with pagination
 */
async function main() {
  try {
    console.log("Fetching corridors...");
    
    // API endpoint path
    const path = "/corridors";
    
    // Make authenticated GET request with query parameters
    const response = await request.get(path, {
      params: { 
        page: 1,           // Pagination: first page
        limit: 50,         // Pagination: 50 items per page
        status: "ACTIVE"   // Filter: only active corridors
      },
    });

    // Log successful response
    console.log("Status:", response.status);
    console.log("Corridors:", response.data);
    
  } catch (err) {
    // Handle errors with detailed logging
    if (err.response) {
      // API returned an error response
      console.error("Error status:", err.response.status);
      console.error("Error data:", err.response.data);
    } else {
      // Network or other request failure
      console.error("Request failed:", err.message);
    }
  }
}

// Execute the main function
main();

This is a simplified example. In production, you’ll need to properly sign the JWT with your private key and handle all error cases.