Sabong API v1.0

Debit Balance API

Overview

The Debit Balance API deducts funds from a user's wallet. This endpoint creates a debit transaction and updates the wallet balance atomically. Use this endpoint to process withdrawals, deduct bet amounts, or charge fees to user accounts.

Endpoint

MethodEndpointAuthentication
POST/api/v1/debit-balanceSignature Required

Authentication

This endpoint requires Signature-based Authentication. You must include the following headers:

HeaderDescription
x-signatureHMAC-SHA256 signature of the request
x-timestampUnix timestamp (seconds) when the request was generated

Note: See Overview for detailed information on how signature authentication works and how to generate signatures.

Request Body

FieldTypeRequiredDefaultValidation
clientIdstringYes-Min 1 character
amountnumberYes-Min: 0.01
descriptionstringNo-Max 500 characters
referencestringNo-Max 255 characters, external reference ID

Request Example

{
  "clientId": "CLIENT_001",
  "amount": 50.00,
  "description": "Withdrawal request",
  "reference": "WITHDRAWAL_789"
}

Response

Success Response (200 OK)

{
  "status": "success",
  "message": "Balance debited successfully",
  "data": {
    "userId": 123,
    "clientId": "CLIENT_001",
    "amount": 50.00,
    "type": "debit",
    "transactionId": 457,
    "balance": 1550.50
  }
}

Response Fields

FieldTypeDescription
statusstringAlways "success" for successful requests
messagestringHuman-readable success message
data.userIdintegerInternal user ID
data.clientIdstringClient identifier
data.amountnumberAmount that was debited
data.typestringTransaction type: "debit"
data.transactionIdintegerUnique transaction ID for this debit operation
data.balancenumber | nullNew wallet balance after debit, or null if unavailable

Error Responses

Validation Error (400 Bad Request)

{
  "status": "failed",
  "message": "Validation failed",
  "data": {
    "errors": {
      "clientId": ["The clientId field is required."],
      "amount": ["The amount field is required.", "The amount must be at least 0.01."]
    }
  }
}

User Not Found (404 Not Found)

{
  "status": "failed",
  "message": "User not found",
  "data": null
}

Insufficient Balance (400 Bad Request)

{
  "status": "failed",
  "message": "Insufficient balance",
  "data": {
    "error": "Insufficient balance for debit operation"
  }
}

Authentication Error (401 Unauthorized)

{
  "status": "error",
  "message": "Invalid signature",
  "data": null
}

Server Error (500 Internal Server Error)

{
  "status": "failed",
  "message": "Failed to debit balance",
  "data": {
    "error": "Database connection failed"
  }
}

Usage Example

cURL

curl -X POST https://wdcf.xerve.online/api/v1/debit-balance \
  -H "Content-Type: application/json" \
  -H "x-signature: YOUR_SIGNATURE" \
  -H "x-timestamp: 1706802000" \
  -d '{
    "clientId": "CLIENT_001",
    "amount": 50.00,
    "description": "Withdrawal request",
    "reference": "WITHDRAWAL_789"
  }'

Note: To generate the signature, refer to the Overview documentation.

JavaScript/TypeScript (with Axios)

import axios from 'axios';
// Import your signature generation function (see Overview)
import { generateSignature } from './signature-utils';

const API_BASE_URL = 'https://wdcf.xerve.online';
const CLIENT_SECRET = 'your-secret-key';

interface DebitBalanceData {
  clientId: string;
  amount: number;
  description?: string;
  reference?: string;
}

async function debitBalance(data: DebitBalanceData) {
  const timestamp = Math.floor(Date.now() / 1000);

  // Generate signature (see Overview for implementation)
  const signature = generateSignature({
    method: 'POST',
    path: '/api/v1/debit-balance',
    payload: data,
    secret: CLIENT_SECRET,
    timestamp
  });

  try {
    const response = await axios.post(
      `${API_BASE_URL}/api/v1/debit-balance`,
      data,
      {
        headers: {
          'Content-Type': 'application/json',
          'x-signature': signature,
          'x-timestamp': timestamp.toString()
        }
      }
    );

    console.log('Debited amount:', response.data.data.amount);
    console.log('New balance:', response.data.data.balance);
    console.log('Transaction ID:', response.data.data.transactionId);
    return response.data;
  } catch (error: any) {
    console.error('Error:', error.response?.data || error.message);
    throw error;
  }
}

// Usage
debitBalance({
  clientId: 'CLIENT_001',
  amount: 50.00,
  description: 'Withdrawal request',
  reference: 'WITHDRAWAL_789'
});

Python

import requests
# Import your signature generation function (see Overview)
from signature_utils import generate_signature
import time

API_BASE_URL = 'https://wdcf.xerve.online'
CLIENT_SECRET = 'your-secret-key'

def debit_balance(client_id: str, amount: float, description: str = None, reference: str = None):
    timestamp = int(time.time())
    payload = {
        "clientId": client_id,
        "amount": amount
    }
    
    if description:
        payload["description"] = description
    if reference:
        payload["reference"] = reference

    # Generate signature (see Overview for implementation)
    signature = generate_signature(
        method="POST",
        path="/api/v1/debit-balance",
        payload=payload,
        secret=CLIENT_SECRET,
        timestamp=timestamp
    )

    headers = {
        "Content-Type": "application/json",
        "x-signature": signature,
        "x-timestamp": str(timestamp)
    }

    response = requests.post(
        f"{API_BASE_URL}/api/v1/debit-balance",
        json=payload,
        headers=headers
    )

    response.raise_for_status()
    data = response.json()
    print(f"Debited amount: {data['data']['amount']}")
    print(f"New balance: {data['data']['balance']}")
    print(f"Transaction ID: {data['data']['transactionId']}")
    return data

# Usage
if __name__ == "__main__":
    debit_balance(
        client_id="CLIENT_001",
        amount=50.00,
        description="Withdrawal request",
        reference="WITHDRAWAL_789"
    )

Important Notes

  1. Atomic Operation: The debit operation is atomic - either both the transaction record and balance update succeed, or both fail. This ensures data consistency.
  2. Insufficient Balance: The system will reject debit requests if the user doesn't have sufficient balance. Always check the balance first using the Get Balance API if you need to verify available funds.
  3. Minimum Amount: The minimum debit amount is 0.01. Requests with smaller amounts will be rejected.
  4. Currency: All amounts are in the default currency (USD). Currency conversion is not handled by this endpoint.
  5. Transaction Record: Each debit operation creates a transaction record that can be retrieved using the Get Transactions API.
  6. Positive Amounts Only: Send only positive amounts. The system will handle the subtraction internally. Do not send negative amounts.

Common Use Cases

  • Withdrawal Processing: Deduct funds when processing withdrawal requests
  • Bet Placement: Debit user wallet when placing bets
  • Fee Deduction: Charge service fees or commissions
  • Purchase Payments: Deduct amounts for in-app purchases or services

Error Handling

Error CodePossible CausesResolution
400Missing/invalid fields, amount < 0.01, insufficient balanceCheck validation errors, verify user has sufficient balance
401Invalid signature or expired timestampVerify signature generation and ensure timestamp is current
404User not foundVerify clientId exists; may need to create user first
500Database or transaction service failureCheck server logs and retry; transaction may have failed

Pre-Debit Balance Check

It's recommended to check the user's balance before attempting a debit, especially for large amounts:

async function safeDebit(clientId: string, amount: number) {
  // First, check current balance
  const balanceResponse = await getBalance(clientId);
  const currentBalance = balanceResponse.data.balance;
  
  if (currentBalance < amount) {
    throw new Error(`Insufficient balance. Available: ${currentBalance}, Required: ${amount}`);
  }
  
  // Proceed with debit
  return await debitBalance({ clientId, amount });
}