Ketmus
Esc

Начало работы

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

Первый счёт и обработка оплаты за 10 минут.

В этом руководстве вы создадите счёт через API, отправите клиента на платёжную страницу и обработаете уведомление об оплате.

1. Сохраните API-ключ

Получите ключ в личном кабинете (как это сделать) и сохраните его в переменных окружения сервера. Никогда не передавайте ключ в браузер или в код мобильного приложения.

KETMUS_API_KEY=XXXXXX-XXXXXX-XXXXXX-XXXXXX
KETMUS_WEBHOOK_SECRET=whsec_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

2. Создайте счёт

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-бота.