Sabong API v1.0

Overview

Introduction

The provides a secure, signature-based authentication system for managing users, wallets, and transactions. All endpoints require signature authentication to ensure request integrity and prevent tampering.

Base URL

https://wdcf.xerve.online/api/v1

Authentication

All endpoints require Signature-based Authentication. Each request must include signature headers to verify the request origin and integrity.

Required Headers

HeaderDescriptionExample
x-signatureHMAC-SHA256 signature of the requesta1b2c3d4e5f6...
x-timestampUnix timestamp in seconds when request was generated1706802000

How Signature Authentication Works

The signature authentication ensures:

  1. Request Integrity - The request hasn't been tampered with in transit
  2. Origin Verification - Only clients with the valid secret can generate valid signatures
  3. Replay Protection - Requests with old timestamps are rejected (5-minute validity window)

Signature Generation Algorithm

The signature is generated using HMAC-SHA256 with the following components:

StringToSign = METHOD + PATH + TIMESTAMP + PAYLOAD
Signature = HMAC-SHA256(StringToSign, CLIENT_SECRET)

Components Breakdown

ComponentDescriptionExample
METHODHTTP method in UPPERCASEPOST, GET
PATHFull API path without query strings/api/v1/generate-auth-token
TIMESTAMPUnix timestamp in seconds1706802000
PAYLOADRequest body (POST) or query string (GET)See below
CLIENT_SECRETYour secret key (keep secure!)your-secret-key

Payload Serialization

For POST requests:

  • Serialize the body object as a JSON string
  • Example: {"clientId":"CLIENT_001","amount":100}

For GET requests:

  • Sort query parameters alphabetically by key
  • Format as key=value pairs joined by &
  • Example: clientId=CLIENT_001&limit=10

Code Examples

Node.js / TypeScript

import crypto from 'crypto';

function generateSignature({
  method,
  path,
  payload,
  secret,
  timestamp
}: {
  method: string;
  path: string;
  payload: any;
  secret: string;
  timestamp: number;
}): string {
  const upperMethod = method.toUpperCase();
  
  // Remove trailing slash if present (except for root "/")
  const cleanPath = path.endsWith('/') && path.length > 1 
    ? path.slice(0, -1) 
    : path;
  
  // Serialize payload based on method
  let payloadString = '';
  if (upperMethod === 'GET') {
    // Sort keys alphabetically for GET requests
    const sortedKeys = Object.keys(payload || {}).sort();
    const queryParts = sortedKeys.map(key => `${key}=${payload[key]}`);
    payloadString = queryParts.join('&');
  } else {
    // JSON stringify for POST requests
    payloadString = typeof payload === 'string' 
      ? payload 
      : JSON.stringify(payload);
  }
  
  // Build string to sign
  const stringToSign = `${upperMethod}${cleanPath}${timestamp}${payloadString}`;
  
  // Generate HMAC-SHA256 signature
  return crypto
    .createHmac('sha256', secret)
    .update(stringToSign)
    .digest('hex');
}

// Example usage
const timestamp = Math.floor(Date.now() / 1000);
const signature = generateSignature({
  method: 'POST',
  path: '/api/v1/generate-auth-token',
  payload: {
    clientId: 'CLIENT_001',
    username: 'testuser',
    displayName: 'Test User',
    ipAddress: '192.168.1.100'
  },
  secret: 'your-client-secret',
  timestamp
});

console.log('Signature:', signature);
console.log('Timestamp:', timestamp);

Python

import hmac
import hashlib
import json
import time

def generate_signature(method, path, payload, secret, timestamp):
    # Clean path (remove trailing slash)
    clean_path = path.rstrip('/') if len(path) > 1 else path
    
    # Serialize payload
    if method.upper() == 'GET':
        # Sort keys alphabetically for GET
        sorted_keys = sorted(payload.keys())
        payload_string = '&'.join([f"{k}={payload[k]}" for k in sorted_keys])
    else:
        # JSON stringify for POST
        payload_string = json.dumps(payload) if isinstance(payload, dict) else payload
    
    # Build string to sign
    string_to_sign = f"{method.upper()}{clean_path}{timestamp}{payload_string}"
    
    # Generate signature
    return hmac.new(
        secret.encode('utf-8'),
        string_to_sign.encode('utf-8'),
        hashlib.sha256
    ).hexdigest()

# Example usage
timestamp = int(time.time())
signature = generate_signature(
    method='POST',
    path='/api/v1/generate-auth-token',
    payload={
        'clientId': 'CLIENT_001',
        'username': 'testuser',
        'displayName': 'Test User',
        'ipAddress': '192.168.1.100'
    },
    secret='your-client-secret',
    timestamp=timestamp
)

print(f'Signature: {signature}')
print(f'Timestamp: {timestamp}')

PHP

<?php
function generateSignature($method, $path, $payload, $secret, $timestamp) {
    // Clean path
    $cleanPath = (strlen($path) > 1 && substr($path, -1) === '/') 
        ? substr($path, 0, -1) 
        : $path;
    
    // Serialize payload
    $payloadString = '';
    if (strtoupper($method) === 'GET') {
        // Sort keys alphabetically for GET
        ksort($payload);
        $parts = [];
        foreach ($payload as $key => $value) {
            $parts[] = "{$key}={$value}";
        }
        $payloadString = implode('&', $parts);
    } else {
        // JSON stringify for POST
        $payloadString = is_string($payload) ? $payload : json_encode($payload);
    }
    
    // Build string to sign
    $stringToSign = strtoupper($method) . $cleanPath . $timestamp . $payloadString;
    
    // Generate signature
    return hash_hmac('sha256', $stringToSign, $secret);
}

// Example usage
$timestamp = time();
$signature = generateSignature(
    'POST',
    '/api/v1/generate-auth-token',
    [
        'clientId' => 'CLIENT_001',
        'username' => 'testuser',
        'displayName' => 'Test User',
        'ipAddress' => '192.168.1.100'
    ],
    'your-client-secret',
    $timestamp
);

echo "Signature: {$signature}\n";
echo "Timestamp: {$timestamp}\n";
?>

Making Authenticated Requests

Include the generated signature and timestamp in your request headers:

curl -X POST https://wdcf.xerve.online/api/v1/generate-auth-token \
  -H "Content-Type: application/json" \
  -H "x-signature: YOUR_GENERATED_SIGNATURE" \
  -H "x-timestamp: 1706802000" \
  -d '{
    "clientId": "CLIENT_001",
    "username": "testuser",
    "displayName": "Test User",
    "ipAddress": "192.168.1.100"
  }'

Available Endpoints

Authentication & Users

MethodEndpointDescriptionDocumentation
POST/api/v1/generate-auth-tokenGenerate a time-limited auth token for user login. Creates a new user if clientId doesn't exist, or updates existing user. Returns a login link and token.View Docs

Wallet Operations

MethodEndpointDescriptionDocumentation
GET/api/v1/get-balanceRetrieve the current balance for a user by clientId. Returns balance amount and last update timestamp.View Docs
POST/api/v1/credit-balanceAdd funds to a user's wallet. Creates a credit transaction and updates balance atomically.View Docs
POST/api/v1/debit-balanceDeduct funds from a user's wallet. Creates a debit transaction and updates balance atomically.View Docs

Transactions

MethodEndpointDescriptionDocumentation
GET/api/v1/get-transactionsRetrieve paginated transaction history for a user. Supports filtering by date, type (credit/debit), sorting, and pagination.View Docs

System Health

MethodEndpointDescription
GET/api/v1/healthHealth check endpoint. Returns server status, timestamp, and uptime. Useful for monitoring.
POST/api/v1/healthHealth check with body echo. Returns the same as GET plus echoes back the request body for testing signature validation.

Common Request/Response Patterns

Success Response Format

{
  "status": "success",
  "message": "Operation completed successfully",
  "data": { ... }
}

Error Response Format

{
  "status": "failed",
  "message": "Error description",
  "data": {
    "error": "Detailed error message",
    "errors": { ... }  // Validation errors (optional)
  }
}

Error Codes

HTTP StatusCodeDescription
400Bad RequestMissing or invalid parameters
401UnauthorizedInvalid signature, missing headers, or expired timestamp
404Not FoundResource not found (e.g., user doesn't exist)
500Internal Server ErrorServer-side error

Timestamp Validity

Signatures are valid for 5 minutes from the timestamp. Requests with timestamps older than 5 minutes will be rejected with a 401 Unauthorized error.

Security Best Practices

  1. Keep CLIENT_SECRET Secure
    • Never expose the secret in client-side code
    • Store it in environment variables or secure vaults
    • Rotate secrets periodically
  2. Use HTTPS
    • Always use HTTPS in production
    • Never send signatures over unencrypted connections
  3. Timestamp Validation
    • Generate timestamps fresh for each request
    • Don't reuse old signatures
  4. Error Handling
    • Don't log the full signature in error messages
    • Implement proper retry logic with fresh timestamps

Quick Start Example

Here's a complete example of generating an auth token:

import axios from 'axios';
import crypto from 'crypto';

const API_BASE_URL = 'https://wdcf.xerve.online';
const CLIENT_SECRET = process.env.CLIENT_SECRET; // Keep this secure!

async function generateAuthToken() {
  const timestamp = Math.floor(Date.now() / 1000);
  const payload = {
    clientId: 'CLIENT_001',
    username: 'testuser001',
    displayName: 'Test User',
    ipAddress: '192.168.1.100',
    expiration: 5 // 5 minutes
  };

  // Generate signature
  const stringToSign = `POST/api/v1/generate-auth-token${timestamp}${JSON.stringify(payload)}`;
  const signature = crypto
    .createHmac('sha256', CLIENT_SECRET)
    .update(stringToSign)
    .digest('hex');

  // Make request
  const response = await axios.post(
    `${API_BASE_URL}/api/v1/generate-auth-token`,
    payload,
    {
      headers: {
        'Content-Type': 'application/json',
        'x-signature': signature,
        'x-timestamp': timestamp.toString()
      }
    }
  );

  console.log('Token:', response.data.data.token);
  console.log('Login Link:', response.data.data.loginLink);
  
  return response.data;
}

Support

For issues or questions regarding the V1 API, please contact the development team or refer to individual endpoint documentation for detailed usage examples.