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

@simpay/typescript

v1.0.2

Published

Official Simpay payment gateway SDK for TypeScript

Readme

SimPay TypeScript SDK

Oficjalne SDK SimPay dla TypeScript i Node.js.

Biblioteka udostępnia klienta SimPayClient oraz moduły dla:

  • płatności online (payments)
  • SMS Premium (sms)
  • Direct Billing (directBilling)
  • notyfikacji IPN (notifications)

SDK działa w środowisku Node.js i korzysta z natywnego fetch.


Wymagania

  • Node.js >= 18

Instalacja

npm install @simpay/typescript

Szybki start

import { SimPayClient } from "@simpay/typescript";

const simpay = new SimPayClient({
  api: {
    password: process.env.SIMPAY_API_PASSWORD!,
  },
  service: {
    id: process.env.SIMPAY_SERVICE_ID!,
  },
  ipn: {
    signatureKey: process.env.SIMPAY_IPN_SIGNATURE_KEY!,
    validateSourceIp: true,
  },
});

Konfiguracja klienta

import type { SimPayClientConfig } from "@simpay/typescript";

const config: SimPayClientConfig = {
  api: {
    password: "YOUR_API_PASSWORD",
    timeout: 10000,
  },
  service: {
    id: "YOUR_DEFAULT_SERVICE_ID",
  },
  ipn: {
    signatureKey: "YOUR_IPN_SIGNATURE_KEY",
    validateSourceIp: false,
  },
};

Pola konfiguracji

api.password

Hasło API SimPay używane do autoryzacji Bearer.

api.timeout

Timeout requestów HTTP w milisekundach. Jeśli nie podasz własnej wartości, SDK użyje 10000 ms.

service.id

Domyślne ID usługi. Nadal możesz przekazywać serviceId jawnie do metod modułów.

ipn.signatureKey

Klucz do weryfikacji podpisów IPN.

ipn.validateSourceIp

Czy weryfikować adres źródłowy IPN przez allowlistę SimPay.


Publiczne API

Runtime

  • SimPayClient

Błędy

  • SimPayError
  • SimPayApiError
  • SimPayValidationError
  • SimPaySignatureError
  • SimPayNetworkError
  • SimPayIpnError

Typy

SDK eksportuje publiczne typy dla:

  • payments
  • sms
  • directbilling
  • notifications
  • common

Przykład:

import type {
  CreateTransactionRequest,
  VerifyCodePayload,
  DirectBillingCreateTransactionRequest,
  PaymentIpnNotification,
} from "@simpay/typescript";

Moduły

Payments

Dostęp przez:

simpay.payments

Dostępne podmoduły

  • simpay.payments.services
  • simpay.payments.channels
  • simpay.payments.transactions
  • simpay.payments.refunds
  • simpay.payments.blikLevel0
  • simpay.payments.blikRecurrent

Payments → Services

Lista usług płatności

const services = await simpay.payments.services.list();

Szczegóły usługi

const service = await simpay.payments.services.get("service_id");

Payments → Channels

Lista kanałów płatności

const channels = await simpay.payments.channels.list("service_id");

Payments → Transactions

Utworzenie transakcji

const transaction = await simpay.payments.transactions.create("service_id", {
  amount: 12.5,
  currency: "PLN",
  description: "Order #123",
  control: "order_123",
  customer: {
    email: "[email protected]",
    name: "John Doe",
  },
  returns: {
    success: "https://twoja-strona.pl/payment/success",
    failure: "https://twoja-strona.pl/payment/failure",
  },
});

Przykładowa odpowiedź:

const response = {
  transactionId: "tx_123",
  redirectUrl: "https://...",
};

Lista transakcji

const transactions = await simpay.payments.transactions.list("service_id");

Szczegóły transakcji

const details = await simpay.payments.transactions.get(
  "service_id",
  "transaction_id",
);

Payments → Refunds

Lista refundów transakcji

const refunds = await simpay.payments.refunds.list(
  "service_id",
  "transaction_id",
);

Szczegóły refundu

const refund = await simpay.payments.refunds.get(
  "service_id",
  "transaction_id",
  "refund_id",
);

Utworzenie refundu

const createdRefund = await simpay.payments.refunds.create(
  "service_id",
  "transaction_id",
  {
    amount: 10,
  },
);

Payments → BLIK Level 0

Wysłanie 6-cyfrowego kodu BLIK

const result = await simpay.payments.blikLevel0.submitCode(
  "service_id",
  "transaction_id",
  "123456",
);

Odpowiedź:

{ accepted: true }

Payments → BLIK Recurrent

Lista subskrypcji BLIK

const result = await simpay.payments.blikRecurrent.list("service_id", {
  filter: {
    status: "subscription_active",
    mode: "BLIK",
  },
  page: 1,
  perPage: 20,
  sort: "-created_at",
});

Utworzenie subskrypcji BLIK

const created = await simpay.payments.blikRecurrent.create("service_id", {
  transactionId: "tx_123",
  ticket: { T6: "123456" },
  alias: {
    value: "AABBCC",
    type: "PAYID",
    label: "Subskrypcja premium",
  },
  options: {},
});

Autopayment dla subskrypcji

const autopayment = await simpay.payments.blikRecurrent.autopayment(
  "service_id",
  "subscription_id",
  {
    transactionId: "tx_456",
  },
);

Lista aliasów BLIK

const aliases = await simpay.payments.blikRecurrent.listAliases("service_id", {
  filter: {
    status: "alias_active",
    type: "PAYID",
  },
  page: 1,
  perPage: 20,
  sort: "-created_at",
});

Wyrejestrowanie aliasu BLIK

await simpay.payments.blikRecurrent.deleteAlias(
  "service_id",
  "alias_id",
  {
    reason: "Rezygnacja użytkownika",
  },
);

SMS Premium

Dostęp przez:

simpay.sms

Dostępne podmoduły

  • simpay.sms.services
  • simpay.sms.transactions
  • simpay.sms.verification
  • simpay.sms.numbers

SMS → Services

Lista usług SMS

const services = await simpay.sms.services.list();

Szczegóły usługi SMS

const service = await simpay.sms.services.get("service_id");

SMS → Transactions

Lista transakcji SMS

const transactions = await simpay.sms.transactions.list("service_id");

Szczegóły transakcji SMS

const transaction = await simpay.sms.transactions.get("service_id", 123456);

SMS → Verification

Weryfikacja kodu SMS

const result = await simpay.sms.verification.verify("service_id", {
  code: "ABC123",
  number: 7055,
});

Przykładowa odpowiedź:

const response = {
  used: false,
  code: "ABC123",
  test: true,
  from: "48500100200",
  number: 7055,
  value: 5,
};

SMS → Numbers

Lista wszystkich numerów SMS

const numbers = await simpay.sms.numbers.list();

Szczegóły numeru

const number = await simpay.sms.numbers.get(7055);

Lista numerów dla usługi

const serviceNumbers = await simpay.sms.numbers.listByService("service_id");

Szczegóły numeru dla usługi

const serviceNumber = await simpay.sms.numbers.getByService("service_id", 7055);

Direct Billing

Dostęp przez:

simpay.directBilling

Dostępne podmoduły

  • simpay.directBilling.services
  • simpay.directBilling.calculation
  • simpay.directBilling.transactions

Direct Billing → Services

Lista usług Direct Billing

const services = await simpay.directBilling.services.list();

Szczegóły usługi Direct Billing

const service = await simpay.directBilling.services.get("service_id");

Direct Billing → Calculation

Kalkulacja prowizji

const calculation = await simpay.directBilling.calculation.calculate(
  "service_id",
  25,
);

Direct Billing → Transactions

Utworzenie transakcji Direct Billing

const transaction = await simpay.directBilling.transactions.create(
  "service_id",
  {
    amount: 19.99,
    amountType: "gross",
    description: "Subscription renewal",
    control: "order_123",
    phoneNumber: "500600700",
    returns: {
      success: "https://twoja-strona.pl/db/success",
      failure: "https://twoja-strona.pl/db/failure",
    },
  },
);

Lista transakcji Direct Billing

const transactions = await simpay.directBilling.transactions.list(
  "service_id",
  {
    filter: {
      status: "transaction_db_payed",
    },
  },
);

Szczegóły transakcji Direct Billing

const details = await simpay.directBilling.transactions.get(
  "service_id",
  "transaction_id",
);

Notifications / IPN

Dostęp przez:

simpay.notifications

Dostępne podmoduły

  • simpay.notifications.payment
  • simpay.notifications.directbilling

Payment IPN

Weryfikacja IPN płatności

const result = await simpay.notifications.payment.verify({
  payload: req.body,
  sourceIp: req.ip,
});

Po poprawnej walidacji metoda zwraca:

"OK"

Dodatkowe metody

const isValid = simpay.notifications.payment.verifySignature(payload);
const isAllowedIp = await simpay.notifications.payment.validateSourceIp(ip);

Przykład z Express.js

Poniższy przykład pokazuje pełny handler webhooka płatności:

  • odbiór req.body
  • weryfikację podpisu i adresu IP
  • zawężanie typu notyfikacji przez switch (payload.type)
  • zwrócenie wymaganej odpowiedzi OK
import express from "express";
import {
  SimPayClient,
  SimPayIpnError,
  type PaymentIpnNotification,
} from "@simpay/typescript";

const app = express();
app.use(express.json());

const simpay = new SimPayClient({
  api: {
    password: process.env.SIMPAY_API_PASSWORD!,
  },
  service: {
    id: process.env.SIMPAY_SERVICE_ID!,
  },
  ipn: {
    signatureKey: process.env.SIMPAY_IPN_SIGNATURE_KEY!,
    validateSourceIp: true,
  },
});

app.post("/webhooks/simpay/payment", async (req, res) => {
  try {
    await simpay.notifications.payment.verify({
      payload: req.body,
      sourceIp: req.ip,
    });

    const payload = req.body as PaymentIpnNotification;

    switch (payload.type) {
      case "transaction:status_changed": {
        const transactionId = payload.data.id;
        const status = payload.data.status;
        const payerTransactionId = payload.data.payer_transaction_id;

        console.log("payment transaction status changed", {
          transactionId,
          payerTransactionId,
          status,
        });
        break;
      }

      case "transaction_refund:status_changed": {
        const refundId = payload.data.id;
        const refundStatus = payload.data.status;
        const transactionId = payload.data.transaction.id;

        console.log("refund status changed", {
          refundId,
          transactionId,
          refundStatus,
        });
        break;
      }

      case "transaction_blik_level0:code_status_changed": {
        const ticketStatus = payload.data.ticket_status;
        const transactionId = payload.data.transaction.id;
        const transactionStatus = payload.data.transaction.status;

        console.log("blik level0 status changed", {
          transactionId,
          ticketStatus,
          transactionStatus,
        });
        break;
      }

      case "blik:alias_status_changed": {
        const aliasId = payload.data.id;
        const aliasStatus = payload.data.status;
        const aliasValue = payload.data.value;

        console.log("blik alias status changed", {
          aliasId,
          aliasStatus,
          aliasValue,
        });
        break;
      }

      case "subscription:status_changed": {
        const subscriptionId = payload.data.id;
        const subscriptionStatus = payload.data.status;
        const mode = payload.data.mode;

        console.log("subscription status changed", {
          subscriptionId,
          subscriptionStatus,
          mode,
        });
        break;
      }

      case "ipn:test": {
        console.log("received payment ipn test", {
          serviceId: payload.data.service_id,
          nonce: payload.data.nonce,
        });
        break;
      }

      default: {
        const neverPayload: never = payload;
        throw new Error(`Unhandled payment notification: ${String(neverPayload)}`);
      }
    }

    res.status(200).send("OK");
  } catch (error) {
    if (error instanceof SimPayIpnError) {
      res.status(400).send(error.code);
      return;
    }

    res.status(500).send("ERROR");
  }
});

Dlaczego switch działa dobrze z typami?

Typ PaymentIpnNotification jest unią typów rozróżnianą po polu type. To znaczy, że po wejściu do konkretnego case TypeScript zawęża payload.data do właściwego kształtu.

Przykład:

function handlePaymentNotification(payload: PaymentIpnNotification): void {
  switch (payload.type) {
    case "transaction:status_changed":
      payload.data.id;
      payload.data.status;
      payload.data.payer_transaction_id;
      break;

    case "transaction_refund:status_changed":
      payload.data.transaction.id;
      payload.data.amount.value;
      break;
  }
}

To daje bardzo wygodny i bezpieczny model obsługi webhooków bez ręcznego rzutowania każdej gałęzi.


Direct Billing IPN

Weryfikacja IPN Direct Billing

const result = await simpay.notifications.directbilling.verify({
  payload: req.body,
  sourceIp: req.ip,
});

Po poprawnej walidacji metoda zwraca:

"OK"

Dodatkowe metody

const isValid = simpay.notifications.directbilling.verifySignature(payload);
const isAllowedIp = await simpay.notifications.directbilling.validateSourceIp(ip);

Przykład z Express.js

import express from "express";
import {
  SimPayClient,
  SimPayIpnError,
  type DirectBillingTransactionNotification,
} from "@simpay/typescript";

const app = express();
app.use(express.json());

const simpay = new SimPayClient({
  api: {
    password: process.env.SIMPAY_API_PASSWORD!,
  },
  service: {
    id: process.env.SIMPAY_SERVICE_ID!,
  },
  ipn: {
    signatureKey: process.env.SIMPAY_IPN_SIGNATURE_KEY!,
    validateSourceIp: true,
  },
});

app.post("/webhooks/simpay/directbilling", async (req, res) => {
  try {
    await simpay.notifications.directbilling.verify({
      payload: req.body,
      sourceIp: req.ip,
    });

    const payload = req.body as DirectBillingTransactionNotification;

    switch (payload.status) {
      case "transaction_db_new":
      case "transaction_db_confirmed":
      case "transaction_db_payed":
      case "transaction_db_rejected": {
        console.log("direct billing notification", {
          id: payload.id,
          serviceId: payload.serviceId,
          status: payload.status,
          numberFrom: payload.number_from,
          provider: payload.provider,
          net: payload.values.net,
          gross: payload.values.gross,
          partner: payload.values.partner,
          control: payload.control ?? null,
        });
        break;
      }

      default: {
        const neverStatus: never = payload.status;
        throw new Error(`Unhandled direct billing status: ${neverStatus}`);
      }
    }

    res.status(200).send("OK");
  } catch (error) {
    if (error instanceof SimPayIpnError) {
      res.status(400).send(error.code);
      return;
    }

    res.status(500).send("ERROR");
  }
});

Kiedy używać verify(), a kiedy verifySignature()?

verify()

Używaj w normalnym webhook handlerze HTTP. Metoda sprawdza:

  • adres IP źródła (jeśli validateSourceIp: true)
  • obecność klucza podpisu
  • kształt payloadu
  • podpis notyfikacji

verifySignature()

Używaj, gdy:

  • chcesz sprawdzić tylko podpis,
  • payload został już wcześniej zwalidowany inną warstwą,
  • testujesz lub debugujesz webhooki poza pełnym requestem HTTP.

Obsługa błędów

SDK rozróżnia kilka klas błędów:

  • SimPayError – baza
  • SimPayApiError – API zwróciło błąd
  • SimPayValidationError – niepoprawne dane wejściowe
  • SimPayNetworkError – błąd sieci / timeout
  • SimPaySignatureError – błędy podpisu
  • SimPayIpnError – błędy IPN / webhooków

Przykład:

import {
  SimPayApiError,
  SimPayNetworkError,
  SimPayValidationError,
} from "@simpay/typescript";

try {
  const result = await simpay.payments.transactions.create("service_id", {
    amount: 10,
    customer: {
      email: "[email protected]",
    },
  });
} catch (error) {
  if (error instanceof SimPayValidationError) {
    console.error("Validation:", error.message);
  } else if (error instanceof SimPayApiError) {
    console.error("API:", error.statusCode, error.errorCode);
  } else if (error instanceof SimPayNetworkError) {
    console.error("Network:", error.message);
  } else {
    console.error("Unknown error:", error);
  }
}

Development

Uruchamianie testów

npm test

Typecheck

npm run typecheck

Lint

npm run lint

Format

npm run format

Pełna walidacja

npm run verify