--- title: "Быстрый старт" url: "https://docs.x-hub.online/start/quickstart/" description: "Первый платёж за пять шагов: ключи, создание платежа, QR, вебхук." relatedDocuments: - "https://docs.x-hub.online/start/auth/" - "https://docs.x-hub.online/start/sandbox/" - "https://docs.x-hub.online/money/withdrawals/" - "https://docs.x-hub.online/webhooks/" - "https://docs.x-hub.online/payments/" --- # Быстрый старт Создадим первый платёж и получим webhook за 5 минут. ## Что нужно - `api_key` — публичный идентификатор. Строка вида `xh_live_...` (продакшн) или `xh_test_...` (sandbox) - `api_secret` — секрет, хранится на твоём бэкенде - `webhook_secret` — для верификации webhook'ов - Публичный URL для webhook'ов (HTTPS, работающий 24/7) ## Как получить ключи { #kak-poluchit-klyuchi } 1. **Свяжись с командой X-Hub** через контакты, которые передал тебе менеджер. Обсудим тариф, настроим нужные опции (приём RUB / обмен USDT→RUB / KYC) и создадим твой аккаунт. 2. **На твой email прилетит magic-link** от X-Hub. Кликаешь → попадаешь в свой кабинет на `https://app.x-hub.online`. 3. **Генерируешь свои ключи сам.** В кабинете раздел «API ключи» → большая кнопка «Сгенерировать API-ключи». Нажимаешь и получаешь **один раз** все три секрета: - `api_key` (префикс `xh_test_` для sandbox или `xh_live_` для production) - `api_secret` - `webhook_secret` 4. **Сразу сохраняешь в менеджер паролей** (1Password, Bitwarden и т.п.). `api_key` потом можно посмотреть в любой момент в кабинете, но `api_secret` и `webhook_secret` больше показаны не будут. !!! tip "Как хранятся секреты" Ключи и секреты генерируются на сервере X-Hub и показываются **один раз** — в момент генерации. `api_secret` хранится у нас только в виде хэша — восстановить его нельзя, только перевыпустить. `webhook_secret` хранится на нашей стороне: он нужен серверу X-Hub, чтобы подписывать каждый webhook. !!! note "Ключи у тебя раздельные для теста и боя, а `webhook_secret` — общий" `api_key` + `api_secret` живут в двух независимых слотах: тестовом и боевом. Когда ты генерируешь ключи второго слота, `webhook_secret` **не** выдаётся повторно — он один на оба режима, не меняется, и в открытом виде показывается ровно один раз, при самой первой генерации. Если ты его потерял — перевыпусти его отдельно (см. ниже); повторно «подсмотреть» существующий нельзя. Так сделано намеренно: этим секретом подписываются уведомления об оплате, и любой, у кого есть доступ к твоему кабинету, иначе мог бы получить его, просто нажав «сгенерировать ключи» в тестовом режиме. ### Ротация - **`api_secret`** — ротируешь сам в том же разделе «API ключи» кнопкой «Перевыпустить». Старый секрет сразу перестаёт работать. Ротируется секрет того слота, в котором ты сейчас работаешь; при подозрении на утечку боевого ключа можно (и нужно) сначала перевести аккаунт в тестовый режим — приём боевых платежей остановится, — а потом сменить именно боевой секрет. - **`webhook_secret`** — перевыпускается отдельной кнопкой в блоке Webhook. Старый секрет сразу перестаёт работать, поэтому меняй его синхронно со своим бэкендом (лучше в окно низкого трафика). - **`api_key`** — стабильный публичный идентификатор. Ротация не предусмотрена (для смены нужен новый merchant-аккаунт). - **Emergency reset** — если потерял доступ к кабинету, попроси X-Hub через поддержку перевыпустить `api_secret` — тебе передадут его разово через защищённый канал. Уточни, какой слот меняем: тестовый или боевой. !!! warning "Храни `api_secret` и `webhook_secret` только на бэкенде" Никогда не отдавай клиенту/браузеру. При компрометации — перевыпусти через кабинет. ### Настройка Webhook URL После генерации ключей укажи URL твоего сервера, куда X-Hub будет присылать события платежей: 1. В том же разделе «API ключи» кабинета найди блок **Webhook URL** 2. Нажми «Изменить» → вставь URL своего endpoint'а (только HTTPS публичный) 3. Сохрани **Важно:** - Пока `webhook_url` не указан (или не сгенерирован `webhook_secret`), webhook'и **копятся в PENDING** и не отправляются. Как только конфигурация становится полной (URL + секрет), накопленные события **отпускаются сразу** — в ближайшем цикле доставки, а не через отложенную паузу. Новые события после этого доставляются в течение ~5 секунд. - Если webhook так и не настроен, накопленные события живут **30 суток**, после чего помечаются `FAILED` и не доставляются уже никогда. - URL можно **менять в любой момент** — изменение не требует реcтарта интеграции. - Подробнее про формат webhook payload — в разделе [Webhook](../money/withdrawals.md#webhook) ниже, про проверку подписи — в [Verify signature](../webhooks/index.md#verify-signature). ### Переход sandbox → production У тебя **один аккаунт** и **два слота ключей**: тестовые `xh_test_...` и боевые `xh_live_...`: - В sandbox тестируешь интеграцию под ключами `xh_test_...` (без реальных денег). - Когда готов к боевому запуску — сам переключаешь режим в кабинете кнопкой «Активировать боевой режим», генерируешь `xh_live_...` ключи и подставляешь их в код вместо test-ключей. - Запрос с ключом **не-активного** режима вернёт `401` с кодом `MODE_MISMATCH` и понятным сообщением, какой режим сейчас активен. Подробнее — в разделе [Sandbox](./sandbox.md#sandbox) ниже. ## Сетевые требования ### Входящие webhook'и (X-Hub → твой сервер) X-Hub отправляет webhook'и с фиксированного IP **`72.56.237.132`**. Если твой webhook-endpoint закрыт файрволом — добавь этот IP в whitelist. ### Исходящие запросы (твой сервер → X-Hub) Если X-Hub выдал тебе **IP-whitelist** (не всем мерчантам — по запросу), то запросы с других IP получат `403 IP_NOT_WHITELISTED`. По умолчанию whitelist не активен. Production endpoint: `https://api.x-hub.online` | Sandbox: тот же URL, разный префикс ключа. ## 1. Создать платёж ```bash curl -X POST https://api.x-hub.online/api/v1/payments \ -H "X-Api-Key: xh_test_abc123..." \ -H "X-Api-Secret: YOUR_API_SECRET" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "amount_rub": "500.00", "external_id": "order-12345", "payment_method": "sbp", "description": "VPN подписка 1 месяц", "success_url": "https://shop.example.com/orders/12345/done" }' ``` Ответ: ```json { "id": "pay_550e8400-e29b-41d4-a716-446655440000", "status": "pending", "amount_rub": "500.00", "payment_url": "https://qr.nspk.ru/BD10100NR0811JNT8FAQG039UTUIDSOM", "expires_at": "2026-04-14T13:15:00Z" } ``` **Что дальше:** два пути на выбор. 1. **Редирект.** Отправить клиента на `payment_url` — он оплатит по ссылке. 2. **Свой чекаут (host-to-host).** В `payment_url` приходит ссылка НСПК, и её содержимое — это и есть полезная нагрузка QR-кода СБП. Закодируй её в QR любой библиотекой и покажи у себя: на своей странице, в приложении или картинкой в боте. Клиент никуда не уходит. !!! tip "Нужна оплата картой?" Этот пример — про `payment_method: "sbp"`. Для `"card"` тело запроса то же самое, а вот `payment_url` в ответе работает по-другому: только редирект, host-to-host-путь недоступен. Разница и что делать, если карты не подключены — в [оплате картой](../payments/index.md#card-payment). ## 2. Клиент оплачивает Клиент видит QR-код СБП, оплачивает через приложение банка. X-Hub получает подтверждение, меняет статус на `paid`. ## 3. Получить webhook X-Hub делает POST на твой `webhook_url` с payload: ```json { "event": "payment.status_changed", "payment_id": "pay_550e8400-...", "external_id": "order-12345", "status": "paid", "previous_status": "processing", "amount_rub": "500.00", "actual_amount_rub": null, "amount_usdt": null, "payment_method": "sbp", "timestamp": "2026-04-14T13:05:12Z", "metadata": {"user_id": "usr_abc"} } ``` В payload `payment.status_changed` есть поле `refund_pending` (`true`, пока по платежу идёт незавершённый возврат). В уведомлениях `settled`, `expired` и части `paid` / `amount_mismatch` / `failed` его пока нет — отсутствие поля читай как `false`, а не как ошибку формата. У неуспешного списания в payload приходит `failure_reason` — **почему** не прошло. От причины зависит, что делать: не хватило денег → повторить через день-два и подписку не отменять; согласие на автосписание отозвано → просить привязать заново. Поле приходит только у `status: "failed"`; у остальных статусов его в payload нет. [Коды и действия →](../payments/index.md#failure-reason) У рекуррентного списания в payload дополнительно приходят два поля: `"subscription_id": "sub_..."` — подписка (и её пользователь), и `"period_ref": "2026-08"` — период, который это списание занимает. По ним событие сопоставляется с подпиской и периодом без обращения к API. Оба поля приходят **при любом** изменении статуса списания: оплата, отказ, истечение, расчёт — и в песочнице тоже. У обычных (не подписочных) платежей этих полей в payload нет. В заголовках `X-Webhook-Signature` и `X-Webhook-Timestamp` — HMAC-SHA256 от `timestamp + "." + body`, ключ = твой `webhook_secret`. [Как проверить подпись →](../webhooks/index.md#verify-signature) ## 4. Проверить статус вручную ```bash curl https://api.x-hub.online/api/v1/payments/pay_550e8400-... \ -H "X-Api-Key: xh_test_abc123..." \ -H "X-Api-Secret: YOUR_API_SECRET" ``` ---