# Платежи и счета

Source: <https://telegafirst.com/docs/payments>
Locale: ru
releaseGitSha: 0bb11ef116e17ec64c802d5476eaff442e53d252
sourceContentDigest: 11bacac64142b2958d80bec9829ef5a193dd7bd37b4968d579d64633c1c75731
Version: 2

В TelegaFirst покупатель получает предложение и счёт в ходе разговора с вашим бизнесом. Владелец управляет платёжной настройкой, а оператор работает в Telegram. Это руководство помогает проверить подключённые способы оплаты, согласовать отправку счёта и отдельно зафиксировать подтверждённый ручной расчёт.

Результаты этих действий различаются: сохранённые реквизиты означают настройку, `delivery:"queued"` — постановку отправки счёта в очередь, а запись платежа — факт расчёта. Проверка подключения провайдера не создаёт платёж и не подтверждает оплату заказа.

## Доступ и подготовка

Пройдите [авторизацию](https://telegafirst.com/docs/authorization) и убедитесь, что выбран нужный бизнес. В MCP проверьте `get_active_bot` и обновите `tools/list`; в REST сверяйте `X-Client-Slug` и `X-Bot-Username`. Все значения номеров и ответов ниже — учебные примеры, используйте объекты из собственного бизнеса.

Показанные REST-маршруты настройки, платежей и Sales принимают API credential через `X-Api-Key` либо `Authorization: Bearer tgf_*`. Произвольный JWT сессии покупателя не заменяет этот доступ. OAuth-подключение собственного агента через MCP использует свой действующий grant и согласованные права.

| Действие | Право |
| - | - |
| Прочитать, настроить, включить или отключить платёжного провайдера | `payments:config`, доступ владельца |
| Подготовить/исполнить отправку счёта, ручную продажу, отметить ручную оплату | `orders:write` |
| Прочитать платежи через REST | `pull:payments` |
| Прочитать заказ через REST | `pull:orders` |
| Настроить RU-профиль бизнеса через onboarding | `onboarding:write` |

Собственный агент клиента работает в пределах выданных прав. Внутренние Qualifier, Manager и Coach советуют и передают денежное действие человеку; они не подтверждают оплату и не изменяют денежные условия. `payments:config` не даёт агенту произвольного доступа к другим бизнесам. Реальный API key, OAuth grant или M2M credential сохраняет свою настоящую принадлежность; фиктивное приложение для OAuth не создаётся.

## Проверить настройки провайдеров

MCP: `get_payment_config` с `{}`. REST: `GET /api/v1/tools/payments`, право `payments:config`, успешный статус `200`. Ответ не содержит секретов: доступны только отметки настройки, валюты и время изменения. Полный учебный пример:

```json
{
  "updatedAt": "2026-09-30T12:34:56.000Z",
  "defaultCurrency": "EUR",
  "providers": [
    {
      "provider": "robokassa",
      "enabled": false,
      "hasCredentials": false,
      "currency": null
    },
    {
      "provider": "yookassa",
      "enabled": false,
      "hasCredentials": false,
      "currency": null
    },
    {
      "provider": "stars",
      "enabled": false,
      "hasCredentials": true,
      "currency": null
    },
    {
      "provider": "cryptobot",
      "enabled": false,
      "hasCredentials": false,
      "currency": null
    },
    {
      "provider": "stripe",
      "enabled": true,
      "hasCredentials": true,
      "currency": "USD"
    },
    {
      "provider": "paypal",
      "enabled": false,
      "hasCredentials": false,
      "currency": null
    },
    {
      "provider": "paddle",
      "enabled": false,
      "hasCredentials": false,
      "currency": null
    },
    {
      "provider": "tinkoff",
      "enabled": false,
      "hasCredentials": false,
      "currency": null
    },
    {
      "provider": "prodamus",
      "enabled": false,
      "hasCredentials": false,
      "currency": null
    }
  ]
}
```

`hasCredentials:true` сообщает о наличии необходимых реквизитов, а не об успешной оплате. `enabled:false` выключает способ оплаты. Доступность конкретного способа для покупки дополнительно зависит от цены, валюты, позиции и проверок провайдера. У Stars секретов нет, поэтому `hasCredentials:true` допустимо даже до включения.

## Сохранить реквизиты и включить способ оплаты

Согласуйте с владельцем провайдера, валюту и режим. Получайте секреты через защищённый ввод своего клиента, храните их вне публичных промптов, переписки и документации. Для одного провайдера используется строгая форма `credentials`, различаемая по `provider`. Для Stripe нужны `secret_key` и `webhook_secret`, для YooKassa — `shop_id` и `api_key`; точную схему остальных провайдеров берите из описания `configure_payment_credentials`.

REST: `POST /api/v1/tools/payments`, право `payments:config`, обязательный `Idempotency-Key`. Следующий JavaScript-фрагмент показывает полное тело учебного Stripe-запроса, получая значения секретов из защищённого ввода. Он не содержит реальных ключей и сам ничего не отправляет:

```javascript
const configureRequest = {
  credentials: {
    provider: "stripe",
    secret_key: stripeSecretKeyFromSecureInput,
    webhook_secret: stripeWebhookSecretFromSecureInput,
    currency: "EUR"
  },
  enabled: false,
  default_currency: "RUB"
};
```

`enabled:false` позволяет сохранить реквизиты без включения способа оплаты. Если `enabled` не передан, значение по умолчанию — `true`, и сервер выполняет проверку допуска к включению. Успешный REST-ответ `201` для показанного запроса:

```json
{
  "provider": "stripe",
  "enabled": false,
  "hasCredentials": true,
  "currency": "EUR"
}
```

В MCP `configure_payment_credentials` принимает ту же форму запроса, но результат — onboarding envelope с `tenant`, `active_slug`, `stage`, `status`, `next_action` и `body` проверки провайдера. REST-ответ настройки выше не является этим MCP envelope. Покажите владельцу фактический `next_action.say_to_user` и результат проверки.

Для включения уже настроенного провайдера используйте `enable_payment_provider` или `POST /api/v1/tools/payments/enable`. Для Stars это единственный путь подключения: реквизиты для него не передаются. После подтверждения владельца REST-запрос с `Idempotency-Key` содержит:

```json
{
  "provider": "stars"
}
```

Успех — `201`:

```json
{
  "provider": "stars",
  "enabled": true,
  "hasCredentials": true
}
```

Для отключения используйте `disable_payment_provider` или `POST /api/v1/tools/payments/disable`, также с `Idempotency-Key`. Учебный запрос и полный успешный ответ `201`:

```json
{
  "provider": "stripe"
}
```

```json
{
  "provider": "stripe",
  "disabled": true
}
```

Отключение сохраняет реквизиты. Повторное включение использует их; считайте способ готовым только после проверки фактического ответа и условий продажи. Секретные значения ни чтение настройки, ни ответы записи не возвращают.

## Проверить подключение и профиль бизнеса

Для проверки используйте `probe_payment_provider` с `{"provider":"yookassa"}` либо `POST /api/v1/tools/onboarding/payment-provider/probe` с тем же телом, правом `payments:config` и `Idempotency-Key`. REST возвращает `201` с полным onboarding envelope; его `body` содержит `provider`, `alive`, `test_mode`, `webhook_url`. При успешной проверке учебного YooKassa: `alive:true`, `test_mode:false`. При транспортном отказе: `alive:false`, `test_mode:null`; секреты и внутренняя ошибка провайдера не раскрываются. Это диагностический результат, а не HTTP-ошибка оплаты.

Для RU-профиля самозанятого используйте `set_tax_profile` либо `POST /api/v1/tools/onboarding/tax-profile`, право `onboarding:write`, `Idempotency-Key`, тело:

```json
{
  "jurisdiction": "ru",
  "business_type": "self_employed"
}
```

В полном onboarding envelope результат `body` равен `{"business_type":"self_employed","taxation_system":null}`. Самозанятость — вид бизнеса; не передавайте её как систему налогообложения. Для `ip` и `ooo` схема требует `taxation_system`; возьмите разрешённое значение из актуального описания инструмента.

Данные профиля и фискальные условия продавца проверяются перед включением соответствующих провайдеров. Ответственность продавца принадлежит вашему бизнесу. Обе зоны `.ru` и `.com` предусмотрены при запуске: они разделяют юрисдикцию и платёжные требования. Язык документа и выбор канала покупателя не определяют автоматически валюту или налоговый профиль.

Платёжные провайдеры отправляют уведомления через единый вход Gateway: сервер определяет провайдера по подписи и заголовкам, проверяет подлинность и приводит уведомление к единому платёжному событию. Это вход для провайдеров; справочник Hub описывает операции, которые вызывает ваш агент. Для настройки кабинета провайдера копируйте фактический `webhook_url` из диагностики своей среды; не отправляйте собственный «успешный webhook» для отметки заказа оплаченным.

## Отправить счёт после подтверждения <!-- tgf-anchor: invoice -->

Сначала прочитайте заказ своего бизнеса и проверьте покупателя, позиции, сумму, валюту и доступные способы оплаты. `order_seq_num` — публичный номер заказа внутри бизнеса. Номер берите из результата продажи или чтения заказа, а не из адреса таблицы базы данных.

1. Вызовите `prepare_send_invoice`. Подготовка не отправляет сообщения.
2. Прочитайте её `payload`, `preparation_id`, `payload_hash` и `expires_at`. Покажите человеку: кому будет отправлен счёт, по какому заказу и на каких условиях. Спросите: «Отправить этому покупателю счёт по этому заказу?»
3. После явного подтверждения вызовите `execute_send_invoice` с точными `preparation_id` и `payload_hash` из той же подготовки. Сервер заново проверяет возможность отправки перед исполнением.

MCP-подготовка учебного заказа:

```json
{
  "jsonrpc": "2.0",
  "id": 4,
  "method": "tools/call",
  "params": {
    "name": "prepare_send_invoice",
    "arguments": {
      "order_seq_num": 45
    }
  }
}
```

Execute принимает только значения из просмотренного фактического ответа:

```javascript
const executeInvoiceArguments = {
  preparation_id: reviewedInvoicePreparation.preparation_id,
  payload_hash: reviewedInvoicePreparation.payload_hash
};
```

Успешное тело результата `execute_send_invoice`:

```json
{
  "orderSeqNum": 45,
  "delivery": "queued",
  "replayed": false
}
```

`queued` означает сохранённый план отправки. Оно не обещает, что покупатель уже получил сообщение, перешёл по ссылке или оплатил. Следите за состоянием заказа и платежей отдельно. Подготовка действует 15 минут и привязана к бизнесу, операции и конкретному подключению. При истечении или переключении бизнеса заново подготовьте и согласуйте сценарий; не создавайте `payload_hash` самостоятельно.

REST-интеграция показывает тот же сценарий человеку до своей денежной команды: `POST /api/v1/sales/orders/45/invoice`, право `orders:write`, `Idempotency-Key: sales-invoice-001`, строгое тело:

```json
{}
```

Успех — `201` с `{"orderSeqNum":45,"delivery":"queued","replayed":false}`. REST не имеет отдельного выдуманного маршрута prepare. Заказ без реального покупателя отклоняется; подставить произвольного получателя в тело нельзя.

## Зафиксировать реальный ручной расчёт

`mark_paid` не является продолжением подготовки счёта. Используйте его только после проверки человеком, что деньги получены, и явного согласия перевести заказ на ручной расчёт. Допустимые значения `settlement_type`: `cash`, `bank_transfer`, `transfer`. `switch_to_manual` обязательно равно `true`; заметка необязательна, после удаления пробелов имеет длину от 1 до 500 символов.

После подтверждения MCP-запрос выглядит так:

```json
{
  "jsonrpc": "2.0",
  "id": 5,
  "method": "tools/call",
  "params": {
    "name": "mark_paid",
    "arguments": {
      "order_seq_num": 45,
      "settlement_type": "bank_transfer",
      "settlement_note": "Paid at desk",
      "switch_to_manual": true,
      "idempotency_key": "sales-settlement-001"
    }
  }
}
```

REST: `POST /api/v1/sales/orders/45/mark-paid`, право `orders:write`, `Idempotency-Key: sales-settlement-001`, тело:

```json
{
  "settlement_type": "bank_transfer",
  "settlement_note": "Paid at desk",
  "switch_to_manual": true
}
```

Полное успешное тело, в REST статус `201`:

```json
{
  "orderSeqNum": 45,
  "paymentSeqNum": 68,
  "replayed": false
}
```

`paymentSeqNum` — номер новой записи платежа; он может быть `null`, если результат расчёта не создал новую запись. Проверьте фактический ответ. Не выполняйте эту команду по одной лишь фразе покупателя, по статусу `queued` или из внутреннего AI-диалога без проверки человеком.

## Прочитать результат и безопасно повторить запрос

`GET /api/v1/payments/9` с правом `pull:payments` возвращает платёж по его номеру. Полный учебный ответ `200` без расширенных связей:

```json
{
  "seq_id": 9,
  "amount": "100.00",
  "currency": "RUB",
  "provider": "yookassa",
  "provider_payment_id": "provider-safe-9",
  "status": "succeeded",
  "created_at": "2026-09-30T10:00:00.000Z",
  "updated_at": "2026-09-30T10:00:00.000Z"
}
```

Для списка используйте `GET /api/v1/payments?limit=2&status=succeeded`. `limit` — 1–200, по умолчанию 50; `meta.next_cursor` непрозрачен, действует 15 минут и связан с бизнесом, ресурсом и фактическими фильтрами. Следующую страницу читайте с теми же фильтрами. `user_seq_num` и `order_seq_num` — номера связей в бизнесе; raw `user_id` и `order_id` не передаются. `include=user,order` добавляет разрешённые связанные представления; порядок списка остаётся по времени создания, параметр `sort` не обещает другого порядка. GET не требует idempotency key и не поддерживает здесь ETag/If-Match.

У REST-настройки провайдеров действует HTTP-квитанция на 24 часа: тот же ключ и тот же запрос возвращают сохранённый ответ; изменённый запрос под тем же ключом даёт `422 IDEMPOTENCY_KEY_MISMATCH`, одновременный повтор — `409 CONFLICT`. Денежные Sales-команды используют отдельную долговременную квитанцию на 30 дней: точный повтор возвращает тот же результат с `replayed:true`, изменение команды — `422 IDEMPOTENCY_KEY_MISMATCH`, ещё исполняемая квитанция — `409 IDEMPOTENCY_KEY_IN_FLIGHT`. Live права и принадлежность креденшла проверяются перед повтором.

Если ответ потерян, сохраните ключ, тело и контекст команды. Не отправляйте тот же расчёт с новым ключом, пока не выяснили исход. Для MCP execute используется полученная подготовка; после её потребления повтор может быть отклонён как недоступный. Не обходите отказ новой подготовкой без проверки уже созданного заказа или платежа. [Идемпотентность и версии](https://telegafirst.com/docs/etag-and-idempotency).

## Ошибки и следующий шаг

| Операция | HTTP / код | Действие |
| - | - | - |
| REST: нет действующего креденшла | `401 INVALID_API_KEY` | Повторить вход, проверить отзыв доступа. |
| REST: недостаточно прав | `403 INSUFFICIENT_SCOPE` | Проверить конкретные права в [описании доступа](https://telegafirst.com/docs/scopes-and-permissions). |
| RU-провайдер: профиль не заполнен | `422 PAYMENT_TAX_PROFILE_MISSING` | Заполнить профиль бизнеса и повторить согласованное включение. |
| Включение без нужных реквизитов | `422 VALIDATION_ERROR` | Сохранить реквизиты нужного провайдера; ответ не раскрывает секрет. |
| REST: строгая схема не принята | `400 VALIDATION_ERROR` | Исправить поля `validation_errors`. |
| REST: отсутствует обязательный ключ | `400 IDEMPOTENCY_KEY_REQUIRED` | Дать команде стабильный ключ. |
| Sales: заказ или покупатель отсутствует | `404 NOT_FOUND` | Проверить текущий бизнес и номера из своего списка. |
| Sales: не выполнены бизнес-условия | `422 INVALID_REQUEST` | Проверить получателя, платёжные условия и необходимость ручного расчёта. |
| Номер/фильтр платежа неверен | `400 INVALID_REQUEST`, `INVALID_FILTER` или `INVALID_CURSOR` | Исправить номер, фильтр или заново начать список. |
| Данные требуют доступного тарифа | `403 PLAN_UPGRADE_REQUIRED` | Проверить тариф, пробный период и оплаченное окно. |
| Ресурсный лимит | `413 PAYLOAD_TOO_LARGE` или `429 RATE_LIMIT_EXCEEDED` | Сократить запрос или ждать `Retry-After`. |

REST-ошибка — Problem Details с `code`, `status`, `instance`, `traceId` и при наличии `hint`. Полный пример отсутствующего права для чтения настройки:

```json
{
  "type": "https://telegafirst.ru/docs/errors#INSUFFICIENT_SCOPE",
  "title": "Forbidden",
  "status": 403,
  "instance": "/api/v1/tools/payments",
  "code": "INSUFFICIENT_SCOPE",
  "traceId": "0123456789abcdef0123456789abcdef",
  "detail": "Missing required scope(s): payments:config",
  "hint": {
    "reason": "The credential lacks a scope this operation requires.",
    "recovery": "Compare missing_scopes at GET /api/v1/me with this operation and use a key that includes them."
  }
}
```

Ключи и внутренний текст провайдера в публичный ответ не включаются. При MCP `isError:true` читайте текст ошибки инструмента. При `PREPARED_SCENARIO_TENANT_CHANGED` остановите исполнение и проверьте активный бизнес. Другие недоступные или несовпавшие подготовки могут дать безопасное сообщение внутренней ошибки с traceId; не ожидайте раскрытия внутренних причин. Сверьте уже выполненное действие, сценарий и подключение перед повтором. Дополнительная диагностика: [ошибки](https://telegafirst.com/docs/errors), [каталог и продажи](https://telegafirst.com/docs/catalog-and-sales).
