Начало работы
Быстрый старт
Первый счёт и обработка оплаты за 10 минут.
В этом руководстве вы создадите счёт через API, отправите клиента на платёжную страницу и обработаете уведомление об оплате.
1. Сохраните API-ключ
Получите ключ в личном кабинете (как это сделать) и сохраните его в переменных окружения сервера. Никогда не передавайте ключ в браузер или в код мобильного приложения.
KETMUS_API_KEY=XXXXXX-XXXXXX-XXXXXX-XXXXXX
KETMUS_WEBHOOK_SECRET=whsec_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx2. Создайте счёт
curl -X POST "https://app.ketmus.com/api/merchant/v1/invoices" \
-H "Authorization: Bearer $KETMUS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"amount": 25,
"currency": "USD",
"order_id": "ORDER-1042",
"description": "Подписка Pro на 1 месяц",
"callback_url": "https://shop.example.com/webhooks/ketmus",
"success_url": "https://shop.example.com/orders/1042?paid=1"
}'3. Перенаправьте клиента
В ответе придёт объект invoice. Отправьте клиента на invoice.pay_url — там он выберет монету, увидит адрес, QR-код и таймер. После оплаты клиент вернётся на success_url.
const { invoice } = data
// Сохраните invoice.id рядом с заказом, чтобы потом сверять вебхуки
await db.orders.update({ id: 'ORDER-1042' }, { ketmusInvoiceId: invoice.id })
res.redirect(303, invoice.pay_url)4. Обработайте вебхук
Когда счёт будет оплачен, Ketmus отправит POST-запрос на callback_url. Проверьте подпись и выдайте товар:
import crypto from 'node:crypto'
import express from 'express'
const app = express()
app.post('/webhooks/ketmus', express.raw({ type: 'application/json' }), async (req, res) => {
const header = req.get('x-ketmus-signature') ?? ''
const { t, v1 } = Object.fromEntries(header.split(',').map((part) => part.split('=')))
const expected = crypto
.createHmac('sha512', process.env.KETMUS_WEBHOOK_SECRET)
.update(`${t}.${req.body}`)
.digest('hex')
const valid = v1 && expected.length === v1.length && crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(v1))
if (!valid) return res.status(400).send('bad signature')
const event = JSON.parse(req.body)
if (event.event === 'invoice.paid' || event.event === 'invoice.paid_over') {
await fulfillOrder(event.order_id, event.delivery_id)
}
res.sendStatus(200)
})Готово
Это вся базовая интеграция. Дальше изучите статусы счёта, все события вебхуков и сценарии для сайта и Telegram-бота.