Skip to content

Интеграция на Node.js ​

Готовый, протестированный набор для серверной интеграции (Node.js 18.13+, без зависимостей). Он ведёт себя так же, как набор Python: оба прогоняются по одним и тем же сценариям жизненного цикла, а тест чётности требует одинаковых результатов.

Скачать набор: eleven-pay-merchant-kit.zip (каталоги node/, python/, test-vectors/, curl/).

Пилотный режим

Реального приёма платежей через счета Cashier пока нет. Тесты и демонстрации набора работают на имитациях. Базовый адрес API вам выдают при подключении.

Состав набора ​

ФайлНазначение
elevenpay-client.mjsHTTP-клиент (fetch): создание/чтение счёта, опрос; перенаправления запрещены
order-store.mjsзаказы, ключи, события, очередь выдачи; exportState()/fromState() для переноса состояния
checkout-service.mjsадаптер сайта: AdapterSettings и CheckoutService
webhook-verify.mjs, webhook-receiver.mjsпроверка подписи и приём вебхука
offline-demo.mjsдемонстрация на имитациях
test/*.test.mjsтесты (node --test)

order-store.mjs хранит данные в памяти и показывает логику: в продакшене это таблицы вашей базы.

Настройка ​

Те же переменные, что и в Python: ELEVENPAY_BASE_URL (обязательна, значения по умолчанию нет), ELEVENPAY_API_KEY, ELEVENPAY_WEBHOOK_SECRET, а также необязательные ELEVENPAY_ORDER_TTL_SECONDS (1800), ELEVENPAY_POLL_DEADLINE_SECONDS (600), ELEVENPAY_LATE_PAYMENT_POLICY (review | fulfil). Секреты в объекте настроек не перечисляются и не попадают в JSON.stringify.

Использование ​

javascript
import { OrderNotPayable, StartUncertain, buildService } from "./checkout-service.mjs";
import { ApiError } from "./elevenpay-client.mjs";
import { OrderStore } from "./order-store.mjs";

const service = buildService(process.env, { store: new OrderStore() });

// 1. Заказ создаёт ВАШ сайт: сумма из вашего каталога, срок — ваш.
service.placeOrder("order_1001", 1500);

// 2. Попросить Eleven Pay отправить счёт плательщику.
try {
  const started = await service.startPayment("order_1001", "+7 700 123 45 67");
  console.log(started.reference, started.payerStep, started.replayed);
} catch (error) {
  if (error instanceof StartUncertain) {
    // Ответа нет: счёт мог быть создан. Повторите ПОЗЖЕ тем же вызовом (тот же ключ).
  } else if (error instanceof OrderNotPayable) {
    console.log(error.reason); // unknown_order | paid | expired
  } else if (error instanceof ApiError) {
    console.log(error.status, error.code); // см. таблицу ошибок
  } else {
    throw error;
  }
}

// 3. Прогресс страницы (опционально).
const progress = await service.refreshPayment("order_1001"); // { outcome, payerStep }
const waited = await service.awaitPayment("order_1001"); // "awaiting" по истечении предела = ещё не оплачено

// 4. Ваш срок: истёкшие неоплаченные заказы (ничего не отменяет в Eleven Pay).
const expired = service.expireStaleOrders();

payerStep: sending_request, approve_in_kaspi, paid, not_sent, unconfirmed.

Приём вебхука ​

Передайте сырые байты и заголовки. С Express используйте express.raw({ type: "*/*" }), неexpress.json(): подпись покрывает точные байты.

javascript
import express from "express";

const app = express();
app.post("/webhooks/eleven-pay", express.raw({ type: "*/*" }), (request, response) => {
  const { status, outcome } = service.handleWebhook(request.headers, request.body); // Buffer
  response.status(status).json({ outcome });
});

Исходы: fulfilled, duplicate, already_paid, late_payment, needs_review, ignored_event_type. Выдачу выполняет отдельный процесс по очереди выдачи; запись в неё делается в той же транзакции, что и смена статуса заказа.

Что проверять перед запуском ​

  • node --test — зелёный; node offline-demo.mjs — проходит.
  • Тесты на ваших данных: двойной клик, дубликат вебхука, поддельная подпись, просроченный заказ, поздний платёж (Чек-лист, Локальное тестирование).
  • Состояние хранится в вашей базе (а не в памяти), ключ идемпотентности — вместе с заказом.