> For the complete documentation index, see [llms.txt](https://docs.mmoweb.biz/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.mmoweb.biz/rest-api/master-akkaunt/balans/upravlenie-balansom.md).

# Управление балансом

### О транзакциях

Управление балансом мастер-аккаунта происходит через **транзакции**. Каждая транзакция — это одна операция по изменению баланса пользователя. Все транзакции логируются и сохраняются в системе для аудита.

При отправке нескольких транзакций в одном запросе каждая обрабатывается независимо:

* Если транзакция валидна и успешна — она выполняется и баланс изменяется
* Если транзакция имеет ошибку (пользователь не найден, недостаточно средств и т.д.) — она не выполняется
* Остальные транзакции в запросе продолжают обрабатываться независимо от ошибок в других

Это означает, что в одном запросе некоторые транзакции могут пройти успешно, а некоторые — не пройти. В этом случае возвращается код `PARTIAL_FAILURE`

**Типы операций:**

* `credit` — пополнение баланса
* `debit` — снятие с баланса

**Типы баланса:**

* `main` — основной баланс
* `bonus` — бонусный баланс (требуется плагин: бонусный баланс)

***

### Описание

Endpoint позволяет создавать транзакции для изменения баланса мастер-аккаунта. Можно обрабатывать до 50 транзакций в одном запросе.

Все операции логируются. Если хотя бы одна из них не прошла, возвращается статус `422` с кодом `PARTIAL_FAILURE`, но успешные транзакции остаются в системе.

***

### Endpoint

```
POST https://api.mmoweb.biz/v2/master-account/balance/transaction/create
```

**Content-Type:** `application/json`

***

### Структура запроса

Запрос содержит массив `transactions`, каждый элемент которого описывает одну операцию:

```json
{
  "transactions": [
    {
      "transaction_type": "credit",
      "balance_type": "main",
      "amount": "100.50",
      "user_id": 123,
      "server_id": 1
    }
  ]
}
```

***

### Параметры

#### Общие параметры

| Параметр       | Тип   | Описание                                 |
| -------------- | ----- | ---------------------------------------- |
| `transactions` | array | Массив транзакций. Максимум 50 элементов |

#### Параметры каждой транзакции

<table data-search="false"><thead><tr><th>Параметр</th><th>Тип</th><th>Обязателен</th><th>Описание</th></tr></thead><tbody><tr><td><code>transaction_type</code></td><td>string</td><td>Да</td><td><code>credit</code> (пополнение) или <code>debit</code> (снятие)</td></tr><tr><td><code>balance_type</code></td><td>string</td><td>Да</td><td><code>main</code> (основной) или <code>bonus</code> (бонусный)</td></tr><tr><td><code>amount</code></td><td>number</td><td>Да</td><td>Сумма операции. Должна быть > 0</td></tr><tr><td><code>user_id</code></td><td>integer</td><td>Да*</td><td>Идентификатор пользователя</td></tr><tr><td><code>email</code></td><td>string</td><td>Да*</td><td>Email пользователя</td></tr><tr><td><code>server_id</code></td><td>integer</td><td>Да</td><td>Идентификатор сервера или <code>0</code> для общего баланса</td></tr><tr><td><code>lifetime</code></td><td>integer</td><td>Нет</td><td>Время жизни бонусов в часах. Только для <code>balance_type=bonus</code></td></tr></tbody></table>

\*Необходимо передать либо `user_id`, либо `email`

> **На что влияет server\_id:**
>
> * `server_id=0` — операция с **общим балансом** мастер-аккаунта
> * `server_id > 0` — операция с **балансом на конкретном сервере**

***

### Примеры

#### Пополнить основной баланс

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST "https://api.mmoweb.biz/v2/master-account/balance/transaction/create" \
  -H "Authorization: Bearer APPLICATION_TOKEN_HERE" \
  -H "Content-Type: application/json" \
  -d '{
    "transactions": [
      {
        "transaction_type": "credit",
        "balance_type": "main",
        "amount": "500.00",
        "user_id": 123,
        "server_id": 0
      }
    ]
  }'
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
const token = 'APPLICATION_TOKEN_HERE';

const transactions = [
  {
    transaction_type: 'credit',
    balance_type: 'main',
    amount: '500.00',
    user_id: 123,
    server_id: 0
  }
];

fetch('https://api.mmoweb.biz/v2/master-account/balance/transaction/create', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ transactions })
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
```

{% endtab %}

{% tab title="PHP" %}

```php
<?php
$token = 'APPLICATION_TOKEN_HERE';
$url = 'https://api.mmoweb.biz/v2/master-account/balance/transaction/create';

$transactions = [
  [
    'transaction_type' => 'credit',
    'balance_type' => 'main',
    'amount' => '500.00',
    'user_id' => 123,
    'server_id' => 0
  ]
];

$payload = json_encode(['transactions' => $transactions]);

$ch = curl_init($url);
curl_setopt_array($ch, [
  CURLOPT_POST => true,
  CURLOPT_POSTFIELDS => $payload,
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => [
    'Authorization: Bearer ' . $token,
    'Content-Type: application/json'
  ]
]);

$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

$data = json_decode($response, true);

echo "HTTP Status: " . $httpCode . "\n";
echo json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
?>
```

{% endtab %}
{% endtabs %}

#### Пополнить бонусный сервера (со сроком действия бонусов)

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST "https://api.mmoweb.biz/v2/master-account/balance/transaction/create" \
  -H "Authorization: Bearer APPLICATION_TOKEN_HERE" \
  -H "Content-Type: application/json" \
  -d '{
    "transactions": [
      {
        "transaction_type": "credit",
        "balance_type": "bonus",
        "amount": "100.00",
        "email": "user@example.com",
        "server_id": 2,
        "lifetime": 24
      }
    ]
  }'
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
const token = 'APPLICATION_TOKEN_HERE';

const transactions = [
  {
    transaction_type: 'credit',
    balance_type: 'bonus',
    amount: '100.00',
    email: 'user@example.com',
    server_id: 2,
    lifetime: 24
  }
];

fetch('https://api.mmoweb.biz/v2/master-account/balance/transaction/create', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ transactions })
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
```

{% endtab %}

{% tab title="PHP" %}

```php
<?php
$token = 'APPLICATION_TOKEN_HERE';
$url = 'https://api.mmoweb.biz/v2/master-account/balance/transaction/create';

$transactions = [
  [
    'transaction_type' => 'credit',
    'balance_type' => 'bonus',
    'amount' => '100.00',
    'email' => 'user@example.com',
    'server_id' => 2,
    'lifetime' => 24
  ]
];

$payload = json_encode(['transactions' => $transactions]);

$ch = curl_init($url);
curl_setopt_array($ch, [
  CURLOPT_POST => true,
  CURLOPT_POSTFIELDS => $payload,
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => [
    'Authorization: Bearer ' . $token,
    'Content-Type: application/json'
  ]
]);

$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

$data = json_decode($response, true);

echo "HTTP Status: " . $httpCode . "\n";
echo json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
?>
```

{% endtab %}
{% endtabs %}

#### Пакетная операция с несколькими пользователями

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST "https://api.mmoweb.biz/v2/master-account/balance/transaction/create" \
  -H "Authorization: Bearer APPLICATION_TOKEN_HERE" \
  -H "Content-Type: application/json" \
  -d '{
    "transactions": [
      {
        "transaction_type": "credit",
        "balance_type": "main",
        "amount": "100.00",
        "user_id": 123,
        "server_id": 1
      },
      {
        "transaction_type": "debit",
        "balance_type": "main",
        "amount": "50.00",
        "email": "player@example.com",
        "server_id": 1
      },
      {
        "transaction_type": "credit",
        "balance_type": "bonus",
        "amount": "250.00",
        "user_id": 456,
        "server_id": 0,
        "lifetime": 48
      }
    ]
  }'
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
const token = 'APPLICATION_TOKEN_HERE';

const transactions = [
  {
    transaction_type: 'credit',
    balance_type: 'main',
    amount: '100.00',
    user_id: 123,
    server_id: 1
  },
  {
    transaction_type: 'debit',
    balance_type: 'main',
    amount: '50.00',
    email: 'player@example.com',
    server_id: 1
  },
  {
    transaction_type: 'credit',
    balance_type: 'bonus',
    amount: '250.00',
    user_id: 456,
    server_id: 0,
    lifetime: 48
  }
];

fetch('https://api.mmoweb.biz/v2/master-account/balance/transaction/create', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ transactions })
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
```

{% endtab %}

{% tab title="PHP" %}

```php
<?php
$token = 'APPLICATION_TOKEN_HERE';
$url = 'https://api.mmoweb.biz/v2/master-account/balance/transaction/create';

$transactions = [
  [
    'transaction_type' => 'credit',
    'balance_type' => 'main',
    'amount' => '100.00',
    'user_id' => 123,
    'server_id' => 1
  ],
  [
    'transaction_type' => 'debit',
    'balance_type' => 'main',
    'amount' => '50.00',
    'email' => 'player@example.com',
    'server_id' => 1
  ],
  [
    'transaction_type' => 'credit',
    'balance_type' => 'bonus',
    'amount' => '250.00',
    'user_id' => 456,
    'server_id' => 0,
    'lifetime' => 48
  ]
];

$payload = json_encode(['transactions' => $transactions]);

$ch = curl_init($url);
curl_setopt_array($ch, [
  CURLOPT_POST => true,
  CURLOPT_POSTFIELDS => $payload,
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => [
    'Authorization: Bearer ' . $token,
    'Content-Type: application/json'
  ]
]);

$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

$data = json_decode($response, true);

echo "HTTP Status: " . $httpCode . "\n";
echo json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
?>
```

{% endtab %}
{% endtabs %}

***

### Ответы

#### Все транзакции успешны (200 OK)

```json
{
  "success": true,
  "transactions": [
    {
      "index": 0,
      "success": true,
      "balance_type": "main",
      "transaction_type": "credit",
      "amount": "100.50",
      "balance_before": "500.00",
      "balance_after": "600.50",
      "lifetime": null
    },
    {
      "index": 1,
      "success": true,
      "balance_type": "bonus",
      "transaction_type": "credit",
      "amount": "250.00",
      "balance_before": "1000.00",
      "balance_after": "1250.00",
      "lifetime": 24
    }
  ]
}
```

#### Часть транзакций не прошла (422 Unprocessable Entity)

```json
{
  "success": false,
  "code": "PARTIAL_FAILURE",
  "transactions": [
    {
      "index": 0,
      "success": true,
      "balance_type": "main",
      "transaction_type": "credit",
      "amount": "100.00",
      "balance_before": "500.00",
      "balance_after": "600.00",
      "lifetime": null
    },
    {
      "index": 1,
      "success": false,
      "code": "INSUFFICIENT_FUNDS",
      "balance_type": "main",
      "transaction_type": "debit",
      "balance_before": "250.00"
    },
    {
      "index": 2,
      "success": false,
      "code": "USER_NOT_FOUND",
      "balance_type": "bonus"
    }
  ]
}
```

#### Ошибка валидации (400 Bad Request)

```json
{
  "success": false,
  "code": "VALIDATION_ERROR",
  "message": {
    "transactions.0.amount": "Amount field must contain a number."
  }
}
```

#### Слишком много транзакций (400 Bad Request)

```json
{
  "success": false,
  "code": "BATCH_TOO_LARGE",
  "message": "Maximum 50 transactions per request"
}
```

***

### Коды ошибок

#### На уровне запроса (HTTP 400)

| Код                | Описание                                  | Решение                                                  |
| ------------------ | ----------------------------------------- | -------------------------------------------------------- |
| `VALIDATION_ERROR` | Ошибка в структуре или параметрах запроса | Проверьте формат JSON и обязательные поля                |
| `BATCH_TOO_LARGE`  | Передано более 50 транзакций              | Разделите запрос на несколько с максимум 50 транзакциями |

#### На уровне отдельной транзакции

| Код                      | HTTP Status | Описание                          | Когда встречается                                                                |
| ------------------------ | ----------- | --------------------------------- | -------------------------------------------------------------------------------- |
| `VALIDATION_ERROR`       | 422         | Проблемы с параметрами транзакции | `amount <= 0`, отсутствуют `user_id` и `email`                                   |
| `SERVER_NOT_FOUND`       | 422         | Сервер не найден                  | Передан `server_id > 0`, но такого сервера нет в системе                         |
| `USER_NOT_FOUND`         | 422         | Пользователь не найден            | Пользователь с указанным `user_id` или `email` не существует                     |
| `BONUS_BALANCE_DISABLED` | 422         | Бонусный баланс отключен          | Попытка операции с `balance_type=bonus`, но бонусный баланс отключен для проекта |
| `INSUFFICIENT_FUNDS`     | 422         | Недостаточно средств              | Попытка снять (`debit`) больше, чем есть на балансе                              |

#### Общий результат

| Код               | HTTP Status | Описание                                                            |
| ----------------- | ----------- | ------------------------------------------------------------------- |
| `success: true`   | 200         | Все транзакции выполнены успешно                                    |
| `PARTIAL_FAILURE` | 422         | Некоторые транзакции не прошли, результаты в массиве `transactions` |

***

### Особенности и рекомендации

#### Бонусный баланс (`bonus`)

* Может быть отключен/не приобретен модуль на уровне проекта — в этом случае любая операция вернет `BONUS_BALANCE_DISABLED`
* При `credit` (пополнении) можно указать `lifetime` в часах (автоматически истекут через указанное время)
* Если `lifetime` не указан, бонусы остаются неограниченными по времени

#### Обработка результатов

* **Каждая транзакция имеет свой `index`** — используйте его для маппинга результатов на исходные данные
* **Если `success: false` на уровне запроса**, проверьте код ошибки и структуру
* **Если `PARTIAL_FAILURE`**, обработайте каждый результат отдельно
* **Балансы в ответе — это строки** для сохранения точности при работе с дробными числами

#### Пакетная обработка

* Максимум 50 транзакций за раз
* Проверка серверов кэшируется в рамках одного запроса (если несколько транзакций на один `server_id`, проверка происходит один раз)
* Если в одном запросе разные `server_id`, каждый проверяется отдельно

***

### Примечания

* Все операции логируются на платформе с полной информацией (пользователь, сумма, тип операции, источник)
* `lifetime` применяется только к бонусному балансу и отсчитывается от момента получения
* Используйте `server_id=0` для работы с общим балансом, независимо от конкретного сервера
