Skip to main content

Overview

This guide walks you through making your first HTTP API requests to discover terminals, initiate a payment, and check transaction status.

Prerequisites

Before you begin, ensure you have:

API Credentials

API key and API secret provided by Modulus Labs

HTTP Client

cURL, Postman, or HTTP client library for your language

JSON Parser

Ability to parse JSON responses

Network Access

Outbound HTTPS access to the API endpoint

Quick Start Flow

1. Discover available terminals
   └─> GET /v1/terminals
   └─> Response: { "terminals": [...], "count": 2 }

2. Initiate payment (synchronous, up to 90s wait)
   └─> POST /v1/terminals/{terminalId}/payments
   └─> Response: { "transactionId": "...", "status": "SUCCESS", ... }

3. (Optional) Check transaction status
   └─> GET /v1/transactions/{transactionId}
   └─> Response: { "transactionId": "...", "status": "COMPLETED", ... }

Step-by-Step Guide

1

Set up authentication

The HTTP API uses HMAC-SHA256 authentication. Each request requires three headers:
HeaderDescription
x-api-keyYour API key
x-timestampISO 8601 timestamp
x-signatureBase64-encoded HMAC-SHA256 signature
See the Authentication page for detailed signature computation.
2

Discover available terminals

List all connected terminals in your group:
cURL
curl -X GET "https://{your-api-endpoint}/v1/terminals" \
  -H "x-api-key: your-api-key" \
  -H "x-timestamp: 2024-01-15T10:30:00.000Z" \
  -H "x-signature: <computed-signature>"
Response:
{
  "terminals": [
    {
      "connectionId": "abc123xyz",
      "terminalId": "TERM-001",
      "deviceId": "TERM-001",
      "connectedAt": "2024-01-15T10:30:00.000Z",
      "lastActivity": "2024-01-15T10:35:00.000Z",
      "status": "online",
      "metadata": {}
    }
  ],
  "count": 1,
  "timestamp": "2024-01-15T10:35:30.000Z"
}
3

Initiate a payment

Send a payment request to a terminal. This endpoint uses long-polling and waits up to 90 seconds for the terminal to respond.
cURL
curl -X POST "https://{your-api-endpoint}/v1/terminals/TERM-001/payments" \
  -H "Content-Type: application/json" \
  -H "x-api-key: your-api-key" \
  -H "x-timestamp: 2024-01-15T10:36:00.000Z" \
  -H "x-signature: <computed-signature>" \
  -d '{
    "transactionId": "TXN-20240115-001",
    "amount": "99.99",
    "currency": "USD",
    "paymentMethod": "CARD",
    "products": [
      {
        "id": "PROD-001",
        "name": "Widget",
        "price": "99.99",
        "quantity": 1
      }
    ],
    "metadata": {
      "orderId": "ORD-12345"
    }
  }'
Successful Response (200 OK):
{
  "transactionId": "TXN-20240115-001",
  "status": "SUCCESS",
  "paymentResponse": {
    "transactionId": "TXN-20240115-001",
    "status": "SUCCESS",
    "amount": "99.99",
    "currency": "USD",
    "paymentMethod": "CARD",
    "authorizationCode": "AUTH123456",
    "receiptData": "...",
    "timestamp": "2024-01-15T10:37:30.000Z"
  },
  "timestamp": "2024-01-15T10:37:30.000Z"
}
4

Check transaction status (optional)

If a payment times out or you need to verify status later:
cURL
curl -X GET "https://{your-api-endpoint}/v1/transactions/TXN-20240115-001" \
  -H "x-api-key: your-api-key" \
  -H "x-timestamp: 2024-01-15T10:40:00.000Z" \
  -H "x-signature: <computed-signature>"
Response:
{
  "transactionId": "TXN-20240115-001",
  "status": "COMPLETED",
  "request": {
    "transactionId": "TXN-20240115-001",
    "amount": "99.99",
    "currency": "USD",
    "paymentMethod": "CARD"
  },
  "response": {
    "transactionId": "TXN-20240115-001",
    "status": "SUCCESS",
    "amount": "99.99",
    "currency": "USD",
    "paymentMethod": "CARD",
    "authorizationCode": "AUTH123456",
    "timestamp": "2024-01-15T10:37:30.000Z"
  },
  "createdAt": "2024-01-15T10:37:00.000Z",
  "updatedAt": "2024-01-15T10:37:30.000Z",
  "completedAt": "2024-01-15T10:37:30.000Z",
  "timestamp": "2024-01-15T10:40:00.000Z"
}

Complete Code Examples

const crypto = require('crypto');

const API_KEY = process.env.MODULUS_API_KEY;
const API_SECRET = process.env.MODULUS_API_SECRET;
const BASE_URL = 'https://{your-api-endpoint}';

/**
 * Generate authentication headers for HTTP API requests
 */
function generateAuthHeaders(method, path, body = null) {
  const timestamp = new Date().toISOString();

  // SHA256 hash of body (empty string for GET)
  const bodyString = body ? JSON.stringify(body) : '';
  const bodyHash = crypto
    .createHash('sha256')
    .update(bodyString)
    .digest('hex');

  // Construct string to sign
  const stringToSign = `${method}\n${path}\n${timestamp}\n${bodyHash}`;

  // Compute HMAC-SHA256 signature
  const signature = crypto
    .createHmac('sha256', API_SECRET)
    .update(stringToSign)
    .digest('base64');

  return {
    'Content-Type': 'application/json',
    'x-api-key': API_KEY,
    'x-timestamp': timestamp,
    'x-signature': signature
  };
}

/**
 * Step 1: Get available terminals
 */
async function getTerminals() {
  const path = '/v1/terminals';
  const headers = generateAuthHeaders('GET', path);

  const response = await fetch(`${BASE_URL}${path}`, {
    method: 'GET',
    headers
  });

  if (!response.ok) {
    throw new Error(`Failed to get terminals: ${response.status}`);
  }

  return response.json();
}

/**
 * Step 2: Initiate a payment
 */
async function createPayment(terminalId, paymentData) {
  const path = `/v1/terminals/${terminalId}/payments`;
  const headers = generateAuthHeaders('POST', path, paymentData);

  const response = await fetch(`${BASE_URL}${path}`, {
    method: 'POST',
    headers,
    body: JSON.stringify(paymentData)
  });

  return response.json();
}

/**
 * Step 3: Check transaction status
 */
async function getTransaction(transactionId) {
  const path = `/v1/transactions/${transactionId}`;
  const headers = generateAuthHeaders('GET', path);

  const response = await fetch(`${BASE_URL}${path}`, {
    method: 'GET',
    headers
  });

  return response.json();
}

// Main flow
async function main() {
  try {
    // 1. Discover terminals
    console.log('Getting terminals...');
    const terminalsResponse = await getTerminals();
    console.log(`Found ${terminalsResponse.count} terminal(s)`);

    if (terminalsResponse.terminals.length === 0) {
      console.log('No terminals available');
      return;
    }

    const terminal = terminalsResponse.terminals[0];
    console.log(`Using terminal: ${terminal.deviceId}`);

    // 2. Initiate payment
    console.log('Initiating payment...');
    const paymentResult = await createPayment(terminal.deviceId, {
      transactionId: `TXN-${Date.now()}`,
      amount: '99.99',
      currency: 'USD',
      paymentMethod: 'CARD',
      products: [
        { id: 'PROD-001', name: 'Widget', price: '99.99', quantity: 1 }
      ],
      metadata: { orderId: 'ORD-12345' }
    });

    console.log('Payment result:', paymentResult.status);

    if (paymentResult.paymentResponse) {
      console.log('Authorization:', paymentResult.paymentResponse.authorizationCode);
    }

    // 3. Optionally check transaction status
    if (paymentResult.transactionId) {
      console.log('Checking transaction status...');
      const txn = await getTransaction(paymentResult.transactionId);
      console.log('Transaction status:', txn.status);
    }

  } catch (error) {
    console.error('Error:', error.message);
  }
}

main();

Error Handling

Handle common error scenarios:
CodeCauseSolution
UNAUTHORIZEDInvalid API keyVerify your API key
INVALID_SIGNATURESignature mismatchCheck signature computation
TIMESTAMP_EXPIREDTimestamp too oldSync system clock
CodeCauseSolution
TERMINAL_NOT_FOUNDTerminal doesn’t existRefresh terminal list
TERMINAL_OFFLINETerminal disconnectedWait for reconnection
CodeCauseSolution
PAYMENT_IN_PROGRESSAnother payment activeWait for completion
TIMEOUTNo response in 90sCheck transaction status

Next Steps