# Переводы

> Мгновенные переводы с баланса приложения пользователям PS Wallet по Telegram ID: методы transfer и getTransfers.

Метод `transfer` переводит деньги с баланса приложения пользователю PS Wallet по его Telegram ID. Перевод мгновенный и без комиссии: деньги приходят на счёт пользователя в той же монете и сети. Так удобно выплачивать выигрыши, кешбэк, возвраты и вознаграждения.

## Перед началом

1. Включите метод в кабинете приложения: «Безопасность» → «Переводы пользователям через API» (понадобится PIN-код). По умолчанию метод выключен, и запрос вернёт ошибку `403 METHOD_DISABLED`.
2. Пополните баланс приложения: оплаченные счета зачисляются на него автоматически, а пополнить его со своего счёта можно в кабинете — без комиссии.

> [!WARNING]
> Любой, у кого есть токен приложения, сможет выводить деньги с баланса через `transfer`. Включайте метод, только если он действительно нужен, и держите на балансе только необходимую сумму. Подробнее — в разделе [Безопасность](https://help.pswallet.org/ru/pay-api/security).

## transfer

Перевести деньги с баланса приложения пользователю PS Wallet. Только `POST`. Возвращает [Transfer](https://help.pswallet.org/ru/pay-api/types#transfer).

| Параметр | Тип | Описание |
|---|---|---|
| `user_id` | Number | Обязательно. Telegram ID получателя. Он должен хотя бы раз открыть PS Wallet. |
| `asset` | String | Обязательно. Монета: `USDT`, `USDT-TRC20`, `USDT-BEP20`, `USDT-ERC20`, `USDT-TON`, `XAUT`, `TRX`, `BNB`, `ETH`, `GRAM`. Рубли другим пользователям сейчас передать нельзя. |
| `amount` | String | Обязательно. Сумма. |
| `spend_id` | String | Обязательно. Уникальный идентификатор перевода, до 64 символов. Защищает от двойной отправки: перевод с уже использованным `spend_id` не выполнится (ошибка `SPEND_ID_USED`). |
| `comment` | String | Необязательно. Комментарий, который получатель увидит в уведомлении и истории, если сумма не ниже порога (по умолчанию $1). Ссылки и @упоминания вырезаются. До 1024 символов. |
| `disable_send_notification` | Boolean | Необязательно. `true` — не присылать получателю уведомление в бот. По умолчанию `false`. |

Если указать `asset=USDT`, деньги спишутся с первой сети, где на балансе приложения хватает суммы: TRC20 → BEP20 → TON → ERC20. Сеть перевода вернётся в поле `asset` ответа.

### Пример запроса

```bash title="cURL"
curl https://pay.pswallet.org/api/transfer \
  -H "PSWallet-Pay-API-Token: $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "user_id": 123456789,
    "asset": "USDT-TRC20",
    "amount": "5",
    "spend_id": "prize-2026-11-09-123456789",
    "comment": "Выигрыш в розыгрыше"
  }'
```

```js title="Node.js"
// Node.js 18+ (встроенный fetch)
// spend_id генерируйте один раз и сохраняйте до отправки запроса
const spendId = `prize-${drawId}-${userId}`;

const response = await fetch("https://pay.pswallet.org/api/transfer", {
  method: "POST",
  headers: {
    "PSWallet-Pay-API-Token": process.env.PSWALLET_PAY_TOKEN,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    user_id: userId,
    asset: "USDT-TRC20",
    amount: "5",
    spend_id: spendId,
    comment: "Выигрыш в розыгрыше",
  }),
});
const data = await response.json();
if (!data.ok) throw new Error(data.error.name);
console.log(data.result.transfer_id);
```

```python title="Python"
import os
import requests

# spend_id генерируйте один раз и сохраняйте до отправки запроса
spend_id = f"prize-{draw_id}-{user_id}"

response = requests.post(
    "https://pay.pswallet.org/api/transfer",
    headers={"PSWallet-Pay-API-Token": os.environ["PSWALLET_PAY_TOKEN"]},
    json={
        "user_id": user_id,
        "asset": "USDT-TRC20",
        "amount": "5",
        "spend_id": spend_id,
        "comment": "Выигрыш в розыгрыше",
    },
    timeout=15,
)
data = response.json()
if not data["ok"]:
    raise RuntimeError(data["error"]["name"])
print(data["result"]["transfer_id"])
```

Ответ:

```json
{
  "ok": true,
  "result": {
    "transfer_id": 311,
    "spend_id": "prize-2026-11-09-123456789",
    "user_id": "123456789",
    "asset": "USDT-TRC20",
    "amount": "5",
    "status": "completed",
    "completed_at": "2026-11-09T12:00:00.000+00:00",
    "comment": "Выигрыш в розыгрыше"
  }
}
```

### Двойная отправка и таймауты

`spend_id` — ваш ключ перевода. Генерируйте его один раз для каждой выплаты (например, из номера заказа или выплаты) и сохраняйте до отправки запроса. Повторный запрос с тем же `spend_id` не переведёт деньги второй раз, а вернёт ошибку `SPEND_ID_USED`.

> [!WARNING]
> Если запрос оборвался по таймауту и вы не знаете, прошёл ли перевод, проверьте его через `getTransfers` с тем же `spend_id`, а не отправляйте заново с новым. То же — при ошибке `500 INTERNAL_ERROR`.

### Комментарий и уведомление

- Получатель получает уведомление в бот PS Wallet, если не передан `disable_send_notification=true`.
- Комментарий получатель увидит в уведомлении и истории, только если сумма перевода не ниже порога (по умолчанию $1). Ниже порога перевод проходит без вашего текста.
- Ссылки и @упоминания в комментарии, который видит получатель, заменяются на `[…]`. В ответе API и в `getTransfers` комментарий возвращается так, как вы его передали.

### Ошибки transfer

Код ответа — 400, если не указан другой.

- `403 METHOD_DISABLED` — метод не включён в разделе «Безопасность».
- `403 TRANSFERS_DISABLED` — переводы для владельца приложения ограничены.
- `403 APP_FROZEN` — приложение заморожено.
- `PARAM_USER_ID_REQUIRED`, `PARAM_USER_ID_INVALID` — нет или неверный Telegram ID.
- `PARAM_SPEND_ID_REQUIRED`, `PARAM_SPEND_ID_INVALID` — нет `spend_id` или он длиннее 64 символов.
- `PARAM_COMMENT_INVALID` — комментарий длиннее 1024 символов.
- `PARAM_ASSET_REQUIRED`, `PARAM_ASSET_INVALID` — не передана, неизвестна или сейчас недоступна монета.
- `PARAM_AMOUNT_REQUIRED`, `PARAM_AMOUNT_INVALID` — нет суммы, она не больше нуля или в ней больше знаков, чем у монеты.
- `403 TEMPORARILY_UNAVAILABLE` — перевод в этой монете сейчас недоступен (например, рубли).
- `404 USER_NOT_FOUND` — получатель не найден: он ни разу не открывал PS Wallet.
- `SPEND_ID_USED` — перевод с таким `spend_id` уже был.
- `INSUFFICIENT_FUNDS` — на балансе приложения не хватает денег.

## getTransfers

Список переводов приложения, сначала новые. Возвращает `{ "items": [Transfer, …] }`.

| Параметр | Тип | Описание |
|---|---|---|
| `asset` | String | Необязательно. Только переводы в этой монете (`USDT` — во всех сетях). |
| `transfer_ids` | String | Необязательно. ID переводов через запятую (учитываются первые 1000). |
| `spend_id` | String | Необязательно. Перевод с этим `spend_id`. |
| `offset` | Number | Необязательно. Сколько переводов пропустить. По умолчанию 0. |
| `count` | Number | Необязательно. Сколько вернуть, от 1 до 1000. По умолчанию 100. |

```bash title="cURL"
curl "https://pay.pswallet.org/api/getTransfers?spend_id=prize-2026-11-09-123456789" \
  -H "PSWallet-Pay-API-Token: $TOKEN"
```

Ответ:

```json
{
  "ok": true,
  "result": {
    "items": [
      {
        "transfer_id": 311,
        "spend_id": "prize-2026-11-09-123456789",
        "user_id": "123456789",
        "asset": "USDT-TRC20",
        "amount": "5",
        "status": "completed",
        "completed_at": "2026-11-09T12:00:00.000+00:00",
        "comment": "Выигрыш в розыгрыше"
      }
    ]
  }
}
```

Пустой `items` при поиске по `spend_id` значит, что перевода не было — его можно отправить снова с тем же `spend_id`.

Ошибки (код 400): `PARAM_ASSET_INVALID`, `PARAM_TRANSFER_IDS_INVALID`, `PARAM_OFFSET_INVALID`, `PARAM_COUNT_INVALID`.

---
Источник: https://help.pswallet.org/ru/pay-api/transfers
