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
Quickstart 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:
See the Authentication page for detailed signature computation.
| Header | Description |
|---|---|
x-api-key | Your API key |
x-timestamp | ISO 8601 timestamp |
x-signature | Base64-encoded HMAC-SHA256 signature |
2
Discover available terminals
List all connected terminals in your group:Response:
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>"
{
"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.Successful Response (200 OK):
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"
}
}'
{
"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:Response:
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>"
{
"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();
import hashlib
import hmac
import base64
import json
import os
import time
from datetime import datetime, timezone
import requests
API_KEY = os.getenv('MODULUS_API_KEY')
API_SECRET = os.getenv('MODULUS_API_SECRET')
BASE_URL = 'https://{your-api-endpoint}'
def generate_auth_headers(method: str, path: str, body: dict = None) -> dict:
"""Generate authentication headers for HTTP API requests."""
timestamp = datetime.now(timezone.utc).strftime('%Y-%m-%dT%H:%M:%S.000Z')
# SHA256 hash of body (empty string for GET)
body_string = json.dumps(body) if body else ''
body_hash = hashlib.sha256(body_string.encode()).hexdigest()
# Construct string to sign
string_to_sign = f'{method}\n{path}\n{timestamp}\n{body_hash}'
# Compute HMAC-SHA256 signature
signature = base64.b64encode(
hmac.new(
API_SECRET.encode(),
string_to_sign.encode(),
hashlib.sha256
).digest()
).decode()
return {
'Content-Type': 'application/json',
'x-api-key': API_KEY,
'x-timestamp': timestamp,
'x-signature': signature
}
def get_terminals():
"""Step 1: Get available terminals."""
path = '/v1/terminals'
headers = generate_auth_headers('GET', path)
response = requests.get(f'{BASE_URL}{path}', headers=headers)
response.raise_for_status()
return response.json()
def create_payment(terminal_id: str, payment_data: dict):
"""Step 2: Initiate a payment."""
path = f'/v1/terminals/{terminal_id}/payments'
headers = generate_auth_headers('POST', path, payment_data)
response = requests.post(
f'{BASE_URL}{path}',
headers=headers,
json=payment_data
)
return response.json()
def get_transaction(transaction_id: str):
"""Step 3: Check transaction status."""
path = f'/v1/transactions/{transaction_id}'
headers = generate_auth_headers('GET', path)
response = requests.get(f'{BASE_URL}{path}', headers=headers)
return response.json()
def main():
try:
# 1. Discover terminals
print('Getting terminals...')
terminals_response = get_terminals()
print(f"Found {terminals_response['count']} terminal(s)")
if not terminals_response['terminals']:
print('No terminals available')
return
terminal = terminals_response['terminals'][0]
print(f"Using terminal: {terminal['deviceId']}")
# 2. Initiate payment
print('Initiating payment...')
payment_result = create_payment(terminal['deviceId'], {
'transactionId': f'TXN-{int(time.time() * 1000)}',
'amount': '99.99',
'currency': 'USD',
'paymentMethod': 'CARD',
'products': [
{'id': 'PROD-001', 'name': 'Widget', 'price': '99.99', 'quantity': 1}
],
'metadata': {'orderId': 'ORD-12345'}
})
print(f"Payment result: {payment_result.get('status')}")
if payment_result.get('paymentResponse'):
print(f"Authorization: {payment_result['paymentResponse'].get('authorizationCode')}")
# 3. Optionally check transaction status
if payment_result.get('transactionId'):
print('Checking transaction status...')
txn = get_transaction(payment_result['transactionId'])
print(f"Transaction status: {txn['status']}")
except Exception as e:
print(f'Error: {e}')
if __name__ == '__main__':
main()
Error Handling
Handle common error scenarios:Authentication Errors (401)
Authentication Errors (401)
| Code | Cause | Solution |
|---|---|---|
UNAUTHORIZED | Invalid API key | Verify your API key |
INVALID_SIGNATURE | Signature mismatch | Check signature computation |
TIMESTAMP_EXPIRED | Timestamp too old | Sync system clock |
Terminal Errors (404, 503)
Terminal Errors (404, 503)
| Code | Cause | Solution |
|---|---|---|
TERMINAL_NOT_FOUND | Terminal doesn’t exist | Refresh terminal list |
TERMINAL_OFFLINE | Terminal disconnected | Wait for reconnection |
Payment Errors (409, 504)
Payment Errors (409, 504)
| Code | Cause | Solution |
|---|---|---|
PAYMENT_IN_PROGRESS | Another payment active | Wait for completion |
TIMEOUT | No response in 90s | Check transaction status |
Next Steps
Endpoints Reference
Complete HTTP endpoint documentation
Authentication
Detailed HMAC signature guide
Data Types
Shared data type reference
Core Concepts
Device enforcement and reconnection