# API Sandbox

Sandbox API нужен для тестовой интеграции партнеров. Через него можно пройти полный путь займа: рассчитать условия, получить тестовый BTC-адрес для залога, подтвердить зачисление, завершить выдачу, принять USDT-погашение и вернуть залог. Реальных переводов в блокчейне в Sandbox нет: адреса тестовые, а зачисления подтверждаются действиями API `confirm_btc` и `confirm_usdt`.

Базовый адрес: `https://partner.fundora.capital`. Авторизация: `Authorization: Bearer sk_sandbox_YOUR_KEY`. Все POST-запросы требуют `Idempotency-Key`. Лимит: 120 запросов за 60 секунд на один Sandbox API-ключ.

### Содержание

* [Как работает Sandbox](https://docs.fundora.capital/api-sandbox#kak-rabotaet-sandbox)
* [Быстрый старт](https://docs.fundora.capital/api-sandbox#bystryi-start)
* [Окружение и правила](https://docs.fundora.capital/api-sandbox#okruzhenie-i-pravila)
* [Тестовые кошельки](https://docs.fundora.capital/api-sandbox#testovye-koshelki)
* [Сценарий займа от заявки до выдачи](https://docs.fundora.capital/api-sandbox#scenarii-zaima-ot-zayavki-do-vydachi)
* [Сценарий погашения и возврата залога](https://docs.fundora.capital/api-sandbox#scenarii-pogasheniya-i-vozvrata-zaloga)
* [Webhooks](https://docs.fundora.capital/api-sandbox#webhooks)
* [Ошибки](https://docs.fundora.capital/api-sandbox#oshibki)
* [Повторные запросы и request\_id](https://docs.fundora.capital/api-sandbox#povtornye-zaprosy-i-request_id)
* [Где смотреть поля](https://docs.fundora.capital/api-sandbox#gde-smotret-polya)

### Как работает Sandbox

Sandbox повторяет основной путь клиентского кабинета Fundora, но без реальных переводов. Партнер вызывает API по шагам и получает такое состояние, которое можно показать в своем интерфейсе.

1. Сначала партнер получает настройки: ставки, курсы, лимиты, комиссии и параметры риска.
2. Затем создает тестовую заявку на займ и получает адреса, которые нужны для сценария.
3. Вместо реального ожидания блокчейна партнер отправляет подтверждающее действие API.
4. После выдачи партнер может проверить состояние займа и запустить погашение.
5. При полном погашении API показывает шаг возврата залога.

Главное правило: шаги нельзя выполнять в произвольном порядке. Если отправить действие раньше времени, API вернет `409 FLOW_CONFLICT`. В этом случае нужно вызвать [GET State](https://docs.fundora.capital/api-sandbox/get-state), посмотреть текущий шаг и продолжить с него.

### Быстрый старт

1. Получите Sandbox API-ключ в [партнерском кабинете Fundora](https://partner.fundora.capital).
2. Вызовите [GET Config](https://docs.fundora.capital/api-sandbox/get-config), чтобы получить ставки, курсы, комиссии и лимиты для калькулятора.
3. Вызовите [GET State](https://docs.fundora.capital/api-sandbox/get-state), чтобы понять, есть ли уже активная заявка или займ по этому ключу.
4. Создайте заявку через [POST Loans](https://docs.fundora.capital/api-sandbox/post-loans) с `action=start_collateral_transfer`.
5. Проходите следующие шаги тем же методом [POST Loans](https://docs.fundora.capital/api-sandbox/post-loans), меняя `action` на следующий допустимый.
6. После выдачи проверьте займ через [GET Loans](https://docs.fundora.capital/api-sandbox/get-loans) или [GET State](https://docs.fundora.capital/api-sandbox/get-state).
7. Запустите погашение через [POST Repayments](https://docs.fundora.capital/api-sandbox/post-repayments).
8. Настройте [Webhooks](https://docs.fundora.capital/api-sandbox/get-webhooks), если партнерскому backend нужны push-события вместо polling.

```bash
curl https://partner.fundora.capital/api/sandbox/config \
  -H "Authorization: Bearer sk_sandbox_YOUR_KEY"
```

### Окружение и правила

| Параметр         | Значение                                                                    |
| ---------------- | --------------------------------------------------------------------------- |
| Базовый адрес    | `https://partner.fundora.capital`                                           |
| Кабинет партнера | [partner.fundora.capital](https://partner.fundora.capital)                  |
| Контур           | Sandbox, без реальных переводов в блокчейне                                 |
| Версия описания  | `0.3.0`, фиксируется в `info.version` OpenAPI                               |
| Авторизация      | `Authorization: Bearer sk_sandbox_YOUR_KEY`                                 |
| POST-запросы     | Всегда передавайте `Idempotency-Key`                                        |
| Лимит            | 120 запросов за 60 секунд на один Sandbox API-ключ                          |
| Журнал запросов  | `request_id`, `error_code` и `Idempotency-Key` видны в партнерском кабинете |

Несовместимые изменения будут выходить как новая версия OpenAPI и отдельно анонсироваться партнерам. На этапе тестирования URL остается `/api/sandbox/*`.

### Тестовые кошельки

API передает данные по кошелькам в поле `sandboxFlow`. Это не реальные кастодиальные кошельки: у них `isRealWallet=false`, сеть `sandbox`, а подтверждение выполняется через API.

Для заявки на займ кошельки находятся здесь: `sandboxFlow.loanApplications[].wallets`.

| Поле                | Актив | Для чего нужно                                                       |
| ------------------- | ----- | -------------------------------------------------------------------- |
| `collateralDeposit` | BTC   | Адрес, который нужно показать клиенту для тестового перевода залога. |
| `loanPayout`        | USDT  | Тестовый кошелек сценария выдачи займа в USDT.                       |
| `collateralReturn`  | BTC   | Адрес, который используется в сценарии будущего возврата залога.     |

Для погашения кошельки находятся здесь: `sandboxFlow.repaymentOperations[].wallets`.

| Поле               | Актив | Для чего нужно                                                                                         |
| ------------------ | ----- | ------------------------------------------------------------------------------------------------------ |
| `repayment`        | USDT  | Адрес для тестового платежа по процентам, частичному или полному погашению.                            |
| `collateralReturn` | BTC   | Адрес возврата залога после полного погашения. Для процентов и частичного погашения может быть `null`. |

Каждый кошелек содержит `asset`, `chainCode`, `address`, `requiredConfirmations`, `isRealWallet` и `confirmationMode`.

### Сценарий займа от заявки до выдачи

| Шаг | Что вызвать                                                                                                                         | Что происходит                                                                                                                                    |
| --- | ----------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| 1   | [GET Config](https://docs.fundora.capital/api-sandbox/get-config)                                                                   | Получаете ставки, LTV, порог ликвидации, комиссии и курсы для калькулятора.                                                                       |
| 2   | [GET State](https://docs.fundora.capital/api-sandbox/get-state)                                                                     | Проверяете, есть ли уже активная заявка или займ по текущему API-ключу.                                                                           |
| 3   | [POST Loans](https://docs.fundora.capital/api-sandbox/post-loans) с `action=start_collateral_transfer`                              | Создается черновик заявки, рассчитываются параметры займа, возвращаются тестовые кошельки `collateralDeposit`, `loanPayout` и `collateralReturn`. |
| 4   | [POST Loans](https://docs.fundora.capital/api-sandbox/post-loans) с `action=confirm_btc`                                            | Имитируется зачисление BTC-залога. В рабочем контуре это будет проверка блокчейна, в Sandbox это отдельное действие API.                          |
| 5   | [POST Loans](https://docs.fundora.capital/api-sandbox/post-loans) с `action=run_kyt`                                                | Имитируется проверка залога по правилам KYT.                                                                                                      |
| 6   | [POST Loans](https://docs.fundora.capital/api-sandbox/post-loans) с `action=complete_payout`                                        | Заявка завершается и превращается в активный займ.                                                                                                |
| 7   | [GET State](https://docs.fundora.capital/api-sandbox/get-state) или [GET Loans](https://docs.fundora.capital/api-sandbox/get-loans) | Получаете ID займа, статус, долг, залог, LTV и историю.                                                                                           |

### Сценарий погашения и возврата залога

| Шаг | Что вызвать                                                                                                                         | Что происходит                                                                                                                                            |
| --- | ----------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 1   | [GET Loans](https://docs.fundora.capital/api-sandbox/get-loans) или [GET State](https://docs.fundora.capital/api-sandbox/get-state) | Выбираете активный займ и проверяете сумму долга.                                                                                                         |
| 2   | [POST Repayments](https://docs.fundora.capital/api-sandbox/post-repayments) с `action=start_payment`                                | Создается операция погашения. API возвращает `operation_id` и тестовый USDT-кошелек `repayment`. Для полного погашения также вернется `collateralReturn`. |
| 3   | [POST Repayments](https://docs.fundora.capital/api-sandbox/post-repayments) с `action=confirm_usdt`                                 | Имитируется зачисление USDT-платежа. На этом и следующих шагах передавайте `operation_id`.                                                                |
| 4   | [POST Repayments](https://docs.fundora.capital/api-sandbox/post-repayments) с `action=run_kyt`                                      | Имитируется проверка платежа по правилам KYT.                                                                                                             |
| 5   | [POST Repayments](https://docs.fundora.capital/api-sandbox/post-repayments) с `action=complete_settlement`                          | Проценты или основной долг списываются в тестовом состоянии займа.                                                                                        |
| 6   | [POST Repayments](https://docs.fundora.capital/api-sandbox/post-repayments) с `action=complete_collateral_return`                   | При полном погашении завершается возврат BTC-залога.                                                                                                      |
| 7   | [GET State](https://docs.fundora.capital/api-sandbox/get-state)                                                                     | Проверяете, что займ закрыт, операция погашения завершена, а возврат залога отражен в истории.                                                            |

Если погашение только процентное или частичное, шаг возврата залога не нужен.

### Webhooks

Sandbox webhooks отправляют push-события на HTTPS endpoint партнера при изменении loan flow, repayment flow и sandbox-партнера. Механика та же, которую планируется использовать для LIVE API: endpoint настраивается API-ключом, delivery подписывается HMAC SHA-256, попытки доставки пишутся в журнал и могут быть повторены.

Настройка endpoint выполняется через [POST Webhooks](https://docs.fundora.capital/api-sandbox/post-webhooks). Первый ответ и ответ при `rotate_secret=true` возвращают `signingSecret`; сохраните его на своей стороне, позже API показывает только `secretPreview`. Для проверки вызовите [POST Webhook Test](https://docs.fundora.capital/api-sandbox/post-webhook-test).

Webhook request приходит как `POST` с JSON body и заголовками:

| Заголовок                     | Значение                                                                      |
| ----------------------------- | ----------------------------------------------------------------------------- |
| `x-fundora-webhook-id`        | Event ID.                                                                     |
| `x-fundora-webhook-event`     | Тип события, например `sandbox.loan.issued`.                                  |
| `x-fundora-webhook-timestamp` | Unix timestamp в секундах.                                                    |
| `x-fundora-webhook-signature` | `v1=` + HMAC SHA-256 от строки `${timestamp}.${rawBody}` на `signing_secret`. |

Endpoint должен отвечать любым 2xx статусом. Не-2xx, timeout или сетевая ошибка переводят delivery в retry/failed; повторить можно через [POST Webhook Retry](https://docs.fundora.capital/api-sandbox/post-webhook-retry).

События Sandbox:

| Event                              | Когда отправляется                                       |
| ---------------------------------- | -------------------------------------------------------- |
| `sandbox.loan_application.updated` | Создана заявка, подтвержден BTC-залог или пройден KYT.   |
| `sandbox.loan.issued`              | Sandbox-заявка завершена и стала активным займом.        |
| `sandbox.loan.updated`             | Прямое изменение активного займа через action endpoint.  |
| `sandbox.repayment.updated`        | Создана или продвинута операция погашения до settlement. |
| `sandbox.repayment.settled`        | Проценты или основной долг списаны в sandbox-состоянии.  |
| `sandbox.collateral.returned`      | Залог возвращен или снят через sandbox action.           |
| `sandbox.partner.updated`          | Sandbox-профиль партнера создан или обновлен.            |
| `sandbox.webhook.test`             | Тестовый event из API.                                   |

### Ошибки

Все ошибки возвращаются в едином формате: `request_id`, `error_code`, `error`. Для логики интеграции используйте `error_code`, а текст `error` показывайте человеку.

| HTTP | Код ошибки                          | Когда возникает                                                          | Что делать                                                                                                                                                    |
| ---- | ----------------------------------- | ------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 401  | `SANDBOX_API_KEY_REQUIRED`          | Не передан заголовок авторизации.                                        | Передайте `Authorization: Bearer sk_sandbox_...`.                                                                                                             |
| 401  | `SANDBOX_API_KEY_INVALID`           | Ключ неверный, отозван или истек.                                        | Проверьте или создайте новый Sandbox API-ключ.                                                                                                                |
| 500  | `SANDBOX_API_KEY_DATABASE_REQUIRED` | Sandbox API не настроен на стороне окружения.                            | Передайте `request_id` в поддержку Fundora.                                                                                                                   |
| 401  | `SANDBOX_SESSION_REQUIRED`          | Не удалось определить sandbox-сессию.                                    | Повторите запрос с валидным ключом или передайте `request_id` в поддержку.                                                                                    |
| 429  | `SANDBOX_RATE_LIMIT_EXCEEDED`       | Превышен лимит 120 запросов за 60 секунд.                                | Подождите следующее окно и повторите запрос.                                                                                                                  |
| 400  | `INVALID_JSON`                      | Тело запроса не является валидным JSON.                                  | Проверьте `Content-Type: application/json` и тело запроса.                                                                                                    |
| 400  | `INVALID_ACTION`                    | Действие неизвестно или не подходит для метода API.                      | Сверьте `action` с описанием метода.                                                                                                                          |
| 400  | `INVALID_AMOUNT`                    | Сумма, залог или параметры погашения невалидны.                          | Проверьте лимиты из [GET Config](https://docs.fundora.capital/api-sandbox/get-config).                                                                        |
| 404  | `LOAN_NOT_FOUND`                    | Займ не найден для текущего API-ключа.                                   | Обновите состояние через [GET State](https://docs.fundora.capital/api-sandbox/get-state) или [GET Loans](https://docs.fundora.capital/api-sandbox/get-loans). |
| 409  | `FLOW_CONFLICT`                     | Шаг вызван раньше времени или из неправильного статуса.                  | Вызовите [GET State](https://docs.fundora.capital/api-sandbox/get-state) и продолжите с текущего шага.                                                        |
| 400  | `IDEMPOTENCY_KEY_REQUIRED`          | POST отправлен без `Idempotency-Key`.                                    | Передайте новый UUID в `Idempotency-Key`.                                                                                                                     |
| 409  | `IDEMPOTENCY_KEY_CONFLICT`          | Этот ключ уже использован с другим телом запроса или другим методом API. | Для новой операции используйте новый UUID; для повтора отправьте тот же запрос.                                                                               |
| 409  | `IDEMPOTENCY_KEY_IN_PROGRESS`       | Такой ключ уже обрабатывается.                                           | Повторите позже с тем же ключом и тем же телом запроса.                                                                                                       |
| 400  | `WEBHOOK_URL_REQUIRED`              | Webhook endpoint не передан.                                             | Передайте публичный HTTPS URL.                                                                                                                                |
| 400  | `WEBHOOK_URL_INVALID`               | Endpoint не HTTPS или указывает на local/private host.                   | Используйте публичный HTTPS URL без credentials.                                                                                                              |
| 400  | `WEBHOOK_EVENTS_INVALID`            | Список событий пустой или содержит неизвестный event.                    | Передайте поддерживаемые события из Webhooks section.                                                                                                         |
| 409  | `WEBHOOK_ENDPOINT_REQUIRED`         | Тестовый event отправлен до настройки webhook.                           | Сначала вызовите POST Webhooks.                                                                                                                               |
| 404  | `WEBHOOK_DELIVERY_NOT_FOUND`        | Delivery не найден или уже доставлен.                                    | Проверьте список deliveries через GET Webhooks.                                                                                                               |

### Повторные запросы и request\_id

* Все POST-запросы требуют `Idempotency-Key`, обычно UUID.
* Для новой операции используйте новый ключ.
* Для повтора после сетевой ошибки используйте тот же ключ, тот же метод API и то же тело запроса.
* Если отправить тот же ключ с другим телом запроса, API вернет `IDEMPOTENCY_KEY_CONFLICT`.
* Каждый ответ содержит `request_id`. Он виден в журнале запросов партнерского кабинета и помогает быстро разбирать обращения в поддержку.

### Где смотреть поля

Ниже на этой странице находятся методы API и схемы запросов/ответов. Основные места:

* [GET Config](https://docs.fundora.capital/api-sandbox/get-config) - ставки, курсы, комиссии, сроки и риск-параметры.
* [GET State](https://docs.fundora.capital/api-sandbox/get-state) - полный снимок: займы, текущие сценарии, кошельки, история и партнерский блок.
* [POST Loans](https://docs.fundora.capital/api-sandbox/post-loans) - шаги создания и выдачи займа.
* [POST Repayments](https://docs.fundora.capital/api-sandbox/post-repayments) - шаги погашения и возврата залога.
* [GET Partner](https://docs.fundora.capital/api-sandbox/get-partner) - данные партнера, ссылки, уровни и вознаграждения.
* [GET Webhooks](https://docs.fundora.capital/api-sandbox/get-webhooks) - webhook endpoint, signing secret preview и последние delivery attempts.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.fundora.capital/api-sandbox.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
