> ## Documentation Index
> Fetch the complete documentation index at: https://docs.bafanglaicai88.com/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> Describe only the public 123hub merchant API documented on this site. The primary endpoint is POST /public/api/multihub/v1.
> Preserve API method names, field names, header names, and error codes exactly as documented. Do not invent endpoints or parameters.
> Treat every amount as an integer in minor units unless a page explicitly states otherwise.
> Never expose, request, or fabricate a merchant secret key. The SDK pages contain reference implementations, not official SDK packages.

# Balance Guide

> Track your merchant balances across currencies

# Balance API

The Balance API lets you check your merchant account balances across all supported currencies. Use it to monitor available funds, track frozen amounts from pending payouts, and verify sufficient funds before initiating withdrawals.

<Info>
  Balances are returned per currency within a single `balance` object. Each currency tracks **value** (available) and **value\_freezing** (frozen). The `value_blocking` and `enabled` fields are currently constant compatibility fields in the runtime response.
</Info>

## Retrieve Balances

Use the `balance.get` method to retrieve your current balances for all currencies.

**Endpoint:** `POST https://api.bafanglaicai88.com/public/api/multihub/v1`

### Request

<CodeGroup>
  ```bash cURL theme={null}
  BODY='{"method":"balance.get","params":{}}'
  HASH=$(printf '%s%s' "$BODY" "YOUR_SECRET_KEY" | sha512sum | awk '{print $1}')
  TIMESTAMP=$(date +%s)
  NONCE=$(uuidgen | tr '[:upper:]' '[:lower:]')

  curl -X POST "https://api.bafanglaicai88.com/public/api/multihub/v1" \
    -H "Content-Type: application/json" \
    -H "X-Data-Application-Id: 42" \
    -H "X-Data-Hash: ${HASH}" \
    -H "X-Data-Timestamp: ${TIMESTAMP}" \
    -H "X-Data-Nonce: ${NONCE}" \
    --data-binary "${BODY}"
  ```

  ```python Python theme={null}
  import hashlib
  import requests
  import json
  import time
  import uuid

  SECRET_KEY = "your_secret_key"
  APPLICATION_ID = "42"

  body = {
      "method": "balance.get",
      "params": {}
  }

  body_json = json.dumps(body, separators=(",", ":"))
  data_hash = hashlib.sha512((body_json + SECRET_KEY).encode()).hexdigest()

  response = requests.post(
      "https://api.bafanglaicai88.com/public/api/multihub/v1",
      headers={
          "Content-Type": "application/json",
          "X-Data-Application-Id": APPLICATION_ID,
          "X-Data-Hash": data_hash,
          "X-Data-Timestamp": str(int(time.time())),
          "X-Data-Nonce": str(uuid.uuid4()),
      },
      data=body_json,
      timeout=(3.05, 30),
  )

  data = response.json()
  print(data)
  ```

  ```javascript Node.js theme={null}
  const crypto = require('crypto');
  const fetch = require('node-fetch');

  const SECRET_KEY = 'your_secret_key';
  const APPLICATION_ID = '42';

  const body = {
    method: 'balance.get',
    params: {},
  };

  const bodyJson = JSON.stringify(body);
  const dataHash = crypto.createHash('sha512')
    .update(bodyJson + SECRET_KEY)
    .digest('hex');
  const timestamp = Math.floor(Date.now() / 1000).toString();
  const nonce = crypto.randomUUID();

  const response = await fetch('https://api.bafanglaicai88.com/public/api/multihub/v1', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-Data-Application-Id': APPLICATION_ID,
      'X-Data-Hash': dataHash,
      'X-Data-Timestamp': timestamp,
      'X-Data-Nonce': nonce,
    },
    body: bodyJson,
    signal: AbortSignal.timeout(30000),
  });

  const data = await response.json();
  console.log(data);
  ```
</CodeGroup>

### Response

Successful responses return **HTTP 200**. Error responses return **HTTP 400**. Always check the `success` field to determine if the request was processed correctly.

```json theme={null}
{
  "success": true,
  "result": {
    "balance": {
      "id": 0,
      "amounts": [
        {
          "value": 150000,
          "value_freezing": 25000,
          "value_blocking": 0,
          "currency": "INR",
          "enabled": true
        },
        {
          "value": 50000,
          "value_freezing": 0,
          "value_blocking": 0,
          "currency": "MXN",
          "enabled": true
        },
        {
          "value": 75000,
          "value_freezing": 0,
          "value_blocking": 0,
          "currency": "TRY",
          "enabled": true
        }
      ],
      "enabled": true
    }
  },
  "request_id": "req_abc123def456",
  "processing_time": 15
}
```

### Error Response

If the request fails (e.g., invalid authentication), the response will contain an `error` field with HTTP 400:

```json theme={null}
{
  "success": false,
  "error": {
    "code": 3000,
    "message": "Authentication error",
    "details": null,
    "context": null
  },
  "request_id": "req_xyz789",
  "processing_time": 2
}
```

## Response Fields

### Envelope Fields

| Field             | Type           | Description                                              |
| ----------------- | -------------- | -------------------------------------------------------- |
| `success`         | boolean        | Whether the request was processed successfully           |
| `result`          | object \| null | Response data (present when `success` is `true`)         |
| `error`           | object \| null | Error details (present when `success` is `false`)        |
| `request_id`      | string         | Unique identifier for this request, useful for debugging |
| `processing_time` | integer        | Server-side processing time in milliseconds              |

### Balance Object

| Field             | Type    | Description                                                                            |
| ----------------- | ------- | -------------------------------------------------------------------------------------- |
| `balance.id`      | integer | Balance identifier. Returns the `service_id` if included in the request, otherwise `0` |
| `balance.enabled` | boolean | Currently always `true` in the runtime response                                        |
| `balance.amounts` | array   | Array of per-currency balance entries                                                  |

### Amount Entry Fields

| Field            | Type    | Description                                               |
| ---------------- | ------- | --------------------------------------------------------- |
| `value`          | integer | Funds available for new withdrawals, in **minor units**   |
| `value_freezing` | integer | Funds reserved by pending withdrawals, in **minor units** |
| `value_blocking` | integer | Currently always `0`, in **minor units**                  |
| `currency`       | string  | ISO 4217 currency code (e.g., `INR`, `MXN`)               |
| `enabled`        | boolean | Currently always `true` in the runtime response           |

<Warning>
  All monetary values are returned as **integers in minor units** (e.g., paise for INR, centavos for MXN). For example, `150000` INR = 1,500.00 INR. Use integer or decimal arithmetic to avoid floating-point precision issues.
</Warning>

<Info>
  **Balance values:**

  * **`value`** -- funds you can use right now for new withdrawals or payouts
  * **`value_freezing`** -- funds reserved by pending withdrawals that have not yet completed. These are temporarily locked and cannot be used for new operations
  * **`value_blocking`** -- currently a constant compatibility field with value `0`

  When a withdrawal completes, frozen funds are released and debited. If a withdrawal fails, frozen funds return to `value`.
</Info>

## Multi-Currency Support

The `balance.get` method returns balances for **all currencies** associated with your merchant account in a single `balance.amounts` array. There is no need to query each currency separately.

If your merchant account is configured for multiple currencies (e.g., INR, MXN, TRY, ARS, AUD, LKR, UYU), you will see an entry for each one in the `amounts` array. Currencies with no activity will not appear in the response.

## Usage Example: Check Balance Before Withdrawal

<CodeGroup>
  ```python Python theme={null}
  import hashlib
  import requests
  import json
  import time
  import uuid

  SECRET_KEY = "your_secret_key"
  APPLICATION_ID = "42"

  body = {
      "method": "balance.get",
      "params": {}
  }

  body_json = json.dumps(body, separators=(",", ":"))
  data_hash = hashlib.sha512((body_json + SECRET_KEY).encode()).hexdigest()

  response = requests.post(
      "https://api.bafanglaicai88.com/public/api/multihub/v1",
      headers={
          "Content-Type": "application/json",
          "X-Data-Application-Id": APPLICATION_ID,
          "X-Data-Hash": data_hash,
          "X-Data-Timestamp": str(int(time.time())),
          "X-Data-Nonce": str(uuid.uuid4()),
      },
      data=body_json,
      timeout=(3.05, 30),
  )

  data = response.json()

  if data["success"]:
      for amount in data["result"]["balance"]["amounts"]:
          if amount["currency"] == "INR":
              available = amount["value"]
              payout_amount = 50000  # 500.00 INR

              if available < payout_amount:
                  print(f"Insufficient balance: {available} < {payout_amount}")
              else:
                  print(f"Sufficient balance ({available}). Proceeding with withdrawal.")
                  # Proceed with withdrawal
  else:
      print(f"Error: {data['error']}")
  ```

  ```javascript Node.js theme={null}
  const crypto = require('crypto');
  const fetch = require('node-fetch');

  const SECRET_KEY = 'your_secret_key';
  const APPLICATION_ID = '42';

  const body = {
    method: 'balance.get',
    params: {},
  };

  const bodyJson = JSON.stringify(body);
  const dataHash = crypto.createHash('sha512')
    .update(bodyJson + SECRET_KEY)
    .digest('hex');
  const timestamp = Math.floor(Date.now() / 1000).toString();
  const nonce = crypto.randomUUID();

  const response = await fetch('https://api.bafanglaicai88.com/public/api/multihub/v1', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-Data-Application-Id': APPLICATION_ID,
      'X-Data-Hash': dataHash,
      'X-Data-Timestamp': timestamp,
      'X-Data-Nonce': nonce,
    },
    body: bodyJson,
    signal: AbortSignal.timeout(30000),
  });

  const data = await response.json();

  if (data.success) {
    const inrAmount = data.result.balance.amounts.find(a => a.currency === 'INR');
    if (inrAmount) {
      const payoutAmount = 50000; // 500.00 INR
      if (inrAmount.value < payoutAmount) {
        console.error(`Insufficient balance: ${inrAmount.value} < ${payoutAmount}`);
      } else {
        console.log(`Sufficient balance (${inrAmount.value}). Proceeding with withdrawal.`);
        // Proceed with withdrawal
      }
    }
  } else {
    console.error('Error:', data.error);
  }
  ```
</CodeGroup>

## How Balance Changes

Your balance updates automatically in response to payment lifecycle events:

| Event                | Effect on Balance                                                      |
| -------------------- | ---------------------------------------------------------------------- |
| Deposit completed    | `value` increases by net amount (deposit amount minus fee)             |
| Withdrawal created   | `value_freezing` increases, `value` decreases by the withdrawal amount |
| Withdrawal completed | `value_freezing` decreases (funds sent to recipient)                   |
| Withdrawal failed    | `value_freezing` decreases, `value` increases (funds unfrozen)         |
| Refund processed     | `value` decreases by refund amount                                     |

<Note>
  Balance changes are reflected immediately after each event. You can poll `balance.get` to track updates in real time, or use [webhooks](/guides/webhooks) to receive notifications when payment events occur.
</Note>

## Authentication

All API requests use the same authentication mechanism:

| Header                  | Description                                                        |
| ----------------------- | ------------------------------------------------------------------ |
| `X-Data-Application-Id` | Your application ID (integer)                                      |
| `X-Data-Hash`           | SHA-512 hash of the request body concatenated with your secret key |
| `X-Data-Timestamp`      | Current Unix timestamp in seconds                                  |
| `X-Data-Nonce`          | Unique nonce for this request                                      |

The hash is computed as:

```
SHA512(requestBody + secretKey)
```

Where `requestBody` is the JSON string of the request body exactly as sent, and `secretKey` is your merchant secret key.
