npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@onreza/cloudpayments-sdk

v0.3.1

Published

Типизированный TypeScript SDK для API CloudPayments

Readme

@onreza/cloudpayments-sdk

Типизированный TypeScript SDK для API CloudPayments и CloudKassir. Требует Node.js 24+; package artifact проверяется на минимальном и актуальном Node 24, unit-контракты — в Bun. Транспорт использует стандартные fetch и WebCrypto API. Публикуется один ESM artifact; require() поддержан встроенным в Node 24 механизмом require(esm).

  • ✅ 1:1 с распознанными API-адресами официальной документации — 48 методов и 8 типов webhook-уведомлений
  • ✅ Строгая типизация запросов и ответов: Transaction, Subscription, Order, TokenRecord, ThreeDsChallenge
  • ✅ Union-типы из справочников: Currency, ReasonCode, TransactionStatus, CultureName, …
  • ✅ Кроссрантайм WebCrypto для HMAC верификации webhook'ов
  • ✅ Безопасный retry: read-only операции и mutation с X-Request-ID
  • ✅ Идемпотентность через X-Request-ID
  • ✅ Автоматическое распознавание 3-D Secure challenge → CloudPayments3DsRequiredError

Установка

npm install @onreza/cloudpayments-sdk
# или
bun add @onreza/cloudpayments-sdk

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

1. Инициализация клиента

import { CloudPaymentsClient } from "@onreza/cloudpayments-sdk";

const cp = new CloudPaymentsClient({
  publicId: process.env.CP_PUBLIC_ID!,
  apiSecret: process.env.CP_API_SECRET!,
});

2. Оплата по криптограмме

import {
  CloudPaymentsClient,
  CloudPayments3DsRequiredError,
  CloudPaymentsBusinessError,
} from "@onreza/cloudpayments-sdk";

try {
  const tx = await cp.payments.chargeCryptogram(
    {
      Amount: 100,
      Currency: "RUB",
      IpAddress: req.ip,
      CardCryptogramPacket: req.body.cryptogram, // от Checkout.js на фронте
      AccountId: "user_123",
      Description: "Заказ #42",
    },
    { idempotencyKey: "payment-order-42" },
  );
  // tx.Status === "Completed", tx.TransactionId, tx.Token, …
} catch (err) {
  if (err instanceof CloudPayments3DsRequiredError) {
    // Редирект плательщика на err.acsUrl с передачей MD=transactionId, PaReq=err.paReq
    res.render("3ds-redirect", { acsUrl: err.acsUrl, md: err.transactionId, paReq: err.paReq });
  } else if (err instanceof CloudPaymentsBusinessError) {
    // err.reasonCode — числовой код из справочника ReasonCode (5051, 5206, …)
    // err.model — Transaction с деталями отказа
    console.error("Отказ:", err.apiMessage, "code:", err.reasonCode);
  }
}

3. Завершение 3-D Secure

После того как плательщик вернулся с TermUrl с PaRes:

const tx = await cp.payments.post3ds(
  {
    TransactionId: Number(req.body.MD),
    PaRes: req.body.PaRes,
  },
  { idempotencyKey: `post3ds-${req.body.MD}` },
);

4. Webhook handler

CloudPayments и CloudKassir шлют уведомления разных типов (Check/Pay/Fail/Confirm/Refund/Recurrent/Cancel/Receipt) на разные URL. Заголовок подписи — Content-HMAC (или X-Content-HMAC).

import { verifyCheckWebhook, WebhookVerificationError } from "@onreza/cloudpayments-sdk/webhooks";

app.post("/cp-webhook/check", async (req, res) => {
  const contentHmac = req.get("content-hmac");
  const signature = contentHmac ?? req.get("x-content-hmac");

  try {
    const payload = await verifyCheckWebhook({
      rawBody: req.rawBody, // сырое тело — НЕ parsed JSON
      signature,
      signatureKind: contentHmac ? "content-hmac" : "x-content-hmac",
      apiSecret: process.env.CP_API_SECRET!,
      contentType: req.get("content-type"),
    });
    // payload типизирован как CheckNotificationPayload
    res.json({ code: 0 }); // одобряем платёж
  } catch (e) {
    if (e instanceof WebhookVerificationError) {
      console.warn("Reject webhook:", e.reason);
      // Authenticated parse failure можно retry; поддельную подпись — нельзя.
      res.status(e.signatureVerified ? 500 : 401).end();
    } else {
      throw e;
    }
  }
});

5. Рекуррентные подписки

// 1. Сначала сделать charge с SaveCard=true, получить Token
const initial = await cp.payments.chargeCryptogram(
  {
    Amount: 100,
    Currency: "RUB",
    IpAddress: req.ip,
    CardCryptogramPacket: req.body.cryptogram,
    AccountId: "user_123",
    SaveCard: true,
  },
  { idempotencyKey: "initial-user-123" },
);

// 2. Создать подписку
const sub = await cp.subscriptions.create(
  {
    Token: initial.Token!,
    AccountId: "user_123",
    Description: "Месячная подписка Pro",
    Email: "[email protected]",
    Amount: 499,
    Currency: "RUB",
    RequireConfirmation: false,
    StartDate: new Date().toISOString(),
    Interval: "Month",
    Period: 1,
  },
  { idempotencyKey: "subscription-user-123" },
);

6. Разовое списание по сохранённому токену

const tx = await cp.payments.chargeToken(
  {
    Amount: 499,
    Currency: "RUB",
    AccountId: "user_123",
    Token: savedToken,
    TrInitiatorCode: 0, // 0 — инициирован ТСП, 1 — пользователем
    PaymentScheduled: 0, // 0 — без расписания
  },
  { idempotencyKey: "renewal-subscription-42-period-7" },
);

7. Онлайн-чек CloudKassir

const submitted = await cp.kkt.submitReceipt(
  {
    Inn: "7700000000",
    Type: "Income",
    InvoiceId: "order-42",
    CustomerReceipt: {
      Items: [
        { label: "Подписка Pro", price: 499, quantity: 1, amount: 499, vat: 20 },
      ],
      taxationSystem: 0,
      amounts: { electronic: 499 },
    },
  },
  { idempotencyKey: "receipt-order-42" },
);

const status = await cp.kkt.getReceiptStatus({ Id: submitted.Id });
// status.Status: "Processed" | "Error" | "Queued" | "NotFound"
// status.Warnings содержит эксплуатационные предупреждения кассы.

Модули клиента

  • cp.payments — оплата, выплаты, 3DS, просмотр/выгрузка транзакций
  • cp.subscriptions — create / get / findByAccount / update / cancel
  • cp.orders — счета с оплатой по email-ссылке
  • cp.settings — настройки уведомлений в ЛК
  • cp.escrow — сведения о безопасных сделках
  • cp.tPay, cp.sbp, cp.sberPay — ссылки и QR для альтернативных способов оплаты
  • cp.kkt — чеки, чеки коррекции, маркировка и состояние касс CloudKassir

Обработка ошибок

Иерархия (все наследуются от CloudPaymentsError):

| Класс | Когда | |---|---| | CloudPaymentsNetworkError | DNS, connection или timeout для read/idempotent запроса | | CloudPaymentsUnknownOutcomeError | Mutation без idempotency key получила неоднозначный network/5xx/response outcome; перед повтором нужна сверка | | CloudPaymentsHttpError | HTTP non-2xx (до разбора тела) | | CloudPaymentsAuthError | 401 — неверный publicId/apiSecret | | CloudPaymentsRateLimitError | 429 — превышен лимит CP (5/30 concurrent) | | CloudPaymentsBusinessError | {Success:false} от CP с Message и/или Model.ReasonCode | | CloudPayments3DsRequiredError | Требуется 3-D Secure; содержит acsUrl + paReq + transactionId | | CloudPaymentsSdkError | Внутренние инварианты SDK |

Справочники и типы

Все перечисления CP доступны как union-типы и label-maps:

import {
  type TransactionStatus,    // "AwaitingAuthentication" | "Authorized" | "Completed" | "Cancelled" | "Declined"
  type ReasonCode,           // 5001 | 5051 | ... 61 значение
  type Currency,             // "RUB" | "USD" | ... 28 валют
  type CultureName,          // "ru-RU" | "en-US" | "kk-KZ"
  transactionStatusLabels,   // { Authorized: "Авторизована", ... }
  reasonCodeLabels,          // { 5051: "Insufficient Funds", ... }
  currencyLabels,
} from "@onreza/cloudpayments-sdk";

Расширенные опции

Идемпотентность

await cp.payments.chargeCryptogram(body, {
  idempotencyKey: `order-${orderId}`, // X-Request-ID, результат кэшируется CP 1 час
});

Retry override

const cp = new CloudPaymentsClient({
  publicId, apiSecret,
  retry: { maxAttempts: 5, baseDelayMs: 500 },
  timeoutMs: 30_000,
});

// Отключить retry для конкретного запроса
await cp.payments.get(body, { retry: false });

Mutation без idempotencyKey никогда не повторяется автоматически. При сетевом обрыве, transient 5xx или повреждённом успешном ответе SDK возвращает CloudPaymentsUnknownOutcomeError: сначала сверяйте транзакцию через payments.get/реестр, затем принимайте решение о новой операции.

Региональный API

import { CloudPaymentsClient, CP_BASE_URL_KZ } from "@onreza/cloudpayments-sdk";

const cp = new CloudPaymentsClient({
  publicId,
  apiSecret,
  baseUrl: CP_BASE_URL_KZ,
});

Абсолютный URL другого origin отклоняется, чтобы Basic credentials нельзя было случайно отправить внешнему сервису. HTTP redirects также отклоняются.

Telemetry

Hooks получают URL, attempt, status и безопасные заголовки. Authorization и request body не передаются. Ошибка hook не влияет на платёж; её можно получить через onHookError.

Кастомный fetch

const cp = new CloudPaymentsClient({
  publicId, apiSecret,
  fetch: customFetch,
});

Отмена запроса

const ctrl = new AbortController();
const promise = cp.payments.listByDay({ Date: "2026-04-22" }, { signal: ctrl.signal });
setTimeout(() => ctrl.abort(), 5000);

Причина пользовательского abort пробрасывается без подмены на SDK-ошибку.

Документация

  • Полная документация CloudPayments: https://developers.cloudpayments.ru
  • Полная документация CloudKassir: https://developers.cloudkassir.ru
  • Архитектура SDK и внутреннее устройство: см. CLAUDE.md
  • Примеры: examples/

Лицензия

MIT © ONREZA