# Партнёрская API-песочница Uniqore

Адрес: `https://api-sandbox.uniqore.ai`. Доступность подтверждает команда Uniqore.
Контракт: [OpenAPI 3.1](/openapi.json).

Здесь можно создать заявку и получить настоящие подписанные HTTP-уведомления
о синтетической регистрации и первой оплате. Деньги, платёжный провайдер и
реальные контакты не нужны. Это отдельная среда; production-ключи здесь не действуют.
Партнёрского кабинета в этой версии нет. Все действия выполняет ваш сервер.

## Доступ

Используйте предоставленные sandbox API-ключ и отдельный секрет подписи webhook.
Production-реквизиты в этой среде не действуют. Процент в sandbox служит
только проверке интеграции. Храните реквизиты на сервере.

В примерах переменная `PARTNER_API_KEY` берётся из вашего хранилища секретов.
Не вставляйте настоящий ключ в документацию, URL, браузер или общие журналы.
`REFERRAL_ID` заменяется ID из ответа на создание заявки.

## 1. Проверить ключ и получателя

```sh
curl -sS https://api-sandbox.uniqore.ai/v1/partner/test \
  -H "Authorization: Bearer $PARTNER_API_KEY"

curl -sS https://api-sandbox.uniqore.ai/v1/partner/test-webhook \
  -H "Authorization: Bearer $PARTNER_API_KEY" \
  -H 'Content-Type: application/json' -d '{}'
```

Первый ответ должен содержать `status: "ok"`, `referrals_enabled: true`.
Второй отправляет `integration.test` на настроенный адрес, возвращает
`event_id`, `delivered`, `http_status` и `error`. `delivered: true` подтверждает
успешный ответ вашего сервера; проверку подписи выполняет ваш обработчик.
Проверочное уведомление не влияет на регистрации, оплаты и партнёрскую статистику.

## 2. Создать заявку

```sh
curl -sS https://api-sandbox.uniqore.ai/v1/partner/referrals \
  -H "Authorization: Bearer $PARTNER_API_KEY" \
  -H 'Idempotency-Key: sandbox-example-001' \
  -H 'Content-Type: application/json' \
  -d '{"external_user_id":"sandbox-user-001","locale":"ru"}'
```

Новая заявка возвращает `201`, `referral_id`, `landing_url` и `expires_at`.
Повтор с тем же ключом и телом возвращает `200` с тем же результатом.
Другое тело с тем же ключом даёт `409 partner_idempotency_conflict`.
Для новой проверки используйте новый ключ и новый проверочный идентификатор.
Не передавайте реальные контакты в `external_user_id`.

Ссылка ведёт на информационную страницу песочницы. Открывать её для запуска
сценариев не требуется. Скачивание приложения и browser handoff здесь не включены.

## 3. Запустить регистрацию

```sh
curl -sS "https://api-sandbox.uniqore.ai/v1/partner/sandbox/referrals/$REFERRAL_ID/events" \
  -H "Authorization: Bearer $PARTNER_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"type":"registration.completed"}'
```

Создаётся синтетическая регистрация и событие `registration.completed`.
Ответ `202` означает, что событие принято и ожидает доставки:

```json
{
  "referral_id": "92d3d9c1-9b04-4b35-9843-9e82c23a6ed3",
  "event_id": "1fb099b9-1ef2-45b2-abfc-dc51b14fe651",
  "type": "registration.completed",
  "delivery_status": "pending",
  "replayed": false
}
```

Идентификаторы в примере условные. Повтор возвращает `200`, прежний `event_id`,
`replayed: true` и текущее состояние доставки. Новый аккаунт и событие не создаются.

## 4. Запустить первую оплату

```sh
curl -sS "https://api-sandbox.uniqore.ai/v1/partner/sandbox/referrals/$REFERRAL_ID/events" \
  -H "Authorization: Bearer $PARTNER_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"type":"payment.first_succeeded","plan":{"id":"founder","name":"Основатель"}}'
```

Создаётся синтетическая первая оплата и событие `payment.first_succeeded`.
Ответ имеет тот же формат, `type` соответствует оплате. Дата задаётся сервером,
тариф берётся из запроса, процент из текущей настройки партнёра. В webhook
передаются дата, тариф и точный процент без суммы, валюты, контактов и ID аккаунта.

Повтор с тем же тарифом возвращает прежнее событие. Изменение процента после
первого вызова не меняет снимок. Другой тариф возвращает
`409 partner_sandbox_plan_conflict`. Оплата до регистрации возвращает
`409 partner_sandbox_registration_required`.

## 5. Сверить статус и оба webhook

```sh
curl -sS "https://api-sandbox.uniqore.ai/v1/partner/referrals/$REFERRAL_ID" \
  -H "Authorization: Bearer $PARTNER_API_KEY"
```

После регистрации статус `linked`, `registered_at` заполнен,
`account_was_new: true`. После оплаты статус `first_paid`, заполнены
`first_paid_at` и `first_payment`. Данные совпадают с уведомлениями.

Оба события отправляются на ваш настроенный HTTPS-адрес в формате контракта.
В бизнес-событиях нет дополнительного `test`: среда определяется адресом и
отдельными секретами. В `integration.test` поле `test: true` сохраняется.

Подпись `X-Uniqore-Signature` равна `v1=` и hex HMAC-SHA256 от
`X-Uniqore-Timestamp + "." + raw_body`. Ключ HMAC это вся строка `uqw_…`.
Проверяйте исходные байты до разбора JSON, timestamp, затем тип и `event_id`.
Подписывайте строку секрета целиком, включая префикс `uqw_`. Сравнивайте
подпись за постоянное время, допускайте не более пяти минут расхождения часов.

После надёжного сохранения события верните короткий `2xx`. Временно ответьте
`500`, затем восстановите `2xx`: Uniqore повторит доставку. Сохраняются
`event_id` и байты тела, timestamp и подпись обновляются. Повторный `event_id`
не должен повторно запускать ваше бизнес-действие.

`delivery_status` бывает `unconfigured`, `pending`, `delivering`, `delivered`,
`failed`. Повтор симуляции показывает текущее состояние, но не перезапускает
доставку. При `unconfigured` согласуйте настройку получателя; после исчерпания
повторов обратитесь в команду Uniqore.

## Границы среды

- Заявка действует 30 дней; истечение до регистрации отклоняет сценарий с `422`.
  После привязки срок заявки не отменяет привязку и не мешает первой оплате.
- Чужая и отсутствующая заявки возвращают одинаковый `404`. API показывает
  только данные партнёра из его ключа.
- Неизвестные поля, пустой тариф и неподходящая заявка отклоняются без частичных
  аккаунтов, платежей или событий. Тело ограничено 8192 байтами.
- Общий лимит составляет 300 запросов за 60 секунд на партнёра,
  диагностические отправки дополнительно ограничены пятью попытками за 60 секунд.
- Заявки и события сохраняются между проверками. Для нового сценария
  создайте новую заявку.
- Sandbox проверяет API и уведомления. Установка приложения и переход
  от партнёрской ссылки к входу в Windows/macOS проверяются отдельно.

После проверки согласуйте рабочее подключение с Uniqore. Для production используются
отдельные реквизиты и коммерческий процент; тестовая настройка его не определяет.

