Skip to content

v0.12.0-beta.2

Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 22 Oct 04:12
faa0501

Added

  • Add commissionRouter (subpath better-payment/commission-router), which routes each payment to the cheapest eligible provider from merchant-defined commission rate tables, with quotes that explain every choice, tie/share-cap/override policies, safe fallbacks and same-provider refunds Thanks to @Enard52.

  • Plugin: currency conversion with TCMB exchange rates, markup, and refund protection Thanks to @Enard52.

  • Plugin: provider failover with circuit breaker and zero double-charge guarantee Thanks to @Enard52 (#247).

  • Add the fraudRules plugin for card-testing protection: velocity counters per IP, card, BIN, email or buyer (with consecutive-decline and distinct-value rules), blocked BIN ranges, an amount limit, your own rule functions and an optional challenge hook, all checked before the provider is called. Every counter key is a salted HMAC digest, so a card number never reaches the store, the log or a message, and nothing is read from X-Forwarded-For unless you name that header and your proxies. It ships as its own better-payment/fraud entry point, so better-payment/plugins stays the same size. Closes #105 Thanks to @Enard52.

  • Add the Garanti BBVA provider (GVP, XML API 512): non-3D and 3D Secure payments (3D, 3D_PAY), GarantiPay (securityLevel: 'GARANTI_PAY'), refund, void and order inquiry. 3D callbacks are verified from hashparams and confirmed with the bank Thanks to @sizinajans (#195).

  • Rename the localizedErrors plugin to i18n and make it work like the i18n plugin of Better Auth: i18n({ translations, defaultLocale, detection, localeCookie, getLocale }). English is built in, and the built-in Turkish, German, Russian and Arabic translations come in locales. HTTP handler responses pick their language with the header (Accept-Language), cookie and callback strategies, in the order you choose; payment.errors.detectLocale(request) runs the same detection. localizedErrors, errorMessages, LocalizedErrorsOptions and ErrorMessageDictionary still work and are deprecated.

  • Add Model Context Protocol (MCP) server plugin (mcp) for AI agents and assistants. Thanks to @Enard52.

  • Add the better-payment/nestjs framework adapter: toNestHandler(payment) returns a single request handler for a NestJS controller that works on both the Express and the Fastify platform. It has no @nestjs/* dependency and reads the request and response objects injected by @Req() and @Res() Thanks to @Enard52 (#270).

  • Add examples/next-shop, a complete Next.js App Router and Prisma shop: server-side cart totals, 3D Secure through the handler, orders updated by payment events and a privileged refund route, with a Playwright happy-path test and a MockProvider that needs no credentials Thanks to @Enard52 (#287).

  • Add the openAPI plugin: generates an OpenAPI 3.1.0 document and serves an interactive Scalar API reference page for all HTTP handler routes, configured providers, and registered plugin endpoints. The document lists only the routes the handler serves, under its basePath. The reference is off in mode: 'production' unless disabled: false is set, and privileged: true puts it behind the handler's authorize hook. Plugin endpoint contexts now always have html(), and plugins get a read-only endpoints list. Thanks to @Enard52.

  • Add pendingResolver plugin to query and resolve timed out payments (NETWORK_ERROR) on a schedule, preventing double charging and emitting final outcome events. Thanks to @Enard52.

  • feat(plugins): add captcha plugin supporting Turnstile, reCAPTCHA, and hCaptcha (#173)

    • Add captcha plugin to verify tokens before payment execution
    • Support Cloudflare Turnstile, Google reCAPTCHA v3 (with minScore), and hCaptcha
    • Read token from HTTP headers or request body candidates
    • Normalize failure error codes to CAPTCHA_MISSING and CAPTCHA_INVALID
    • Exclude provider callback and 3DS completion operations Thanks to @Enard52.
  • Add rateLimit plugin for HTTP handler endpoints with per-route throttling, a customizable key extractor, sliding window store, and callback exclusion. The client identity defaults to a safe source: proxy headers are only read with trustProxy, otherwise an explicit key is required. Thanks to @Enard52.

  • Plugin: redact card data and personal data from logs and events (PCI DSS & KVKK) Thanks to @Enard52.

  • Add the refundApproval plugin: requires manager approval before processing refunds and cancellations above a specified threshold, with in-memory or custom store, approval/rejection methods, self-approval prevention, Slack/webhook notify callback, and handler endpoints (/refunds/pending, /refunds/approve, /refunds/reject). Thanks to @Enard52.

  • Add routing (subpath better-payment/routing): rule-based provider routing with BIN, bank, card family, card type, card origin, amount, currency, installment, 3D Secure, operation and custom predicate conditions; ordered and deterministic weighted targets; injected health, BIN and key-value store hooks; explainable decisions and audit listeners; follow-up operations that stay on the provider that handled the payment; and no re-routing after a possible charge. Thanks to @Enard52.

  • Add the telemetry plugin: one OpenTelemetry-compatible span per provider call with the provider, operation, result, normalized error code, HTTP status, retry count and duration, plus a payment.calls counter and a payment.duration histogram. It has no dependencies — it accepts any structurally compatible tracer and meter, so a real @opentelemetry/api tracer works and applications without OpenTelemetry can pass nothing at all. Attributes are low-cardinality and never contain card data, and a throwing tracer is reported through the logger without changing the payment. Thanks to @Enard52.

  • feat(plugins): add threeDSTimeout plugin to expire abandoned 3D Secure payments (#180)

    • Add threeDSTimeout plugin tracking initiated 3D Secure payments across providers
    • Support configurable timeout duration (e.g. '15m'), pluggable ThreeDSFlowStore, and onExpire callback
    • Query provider before expiring to protect against late successful callbacks
    • Provide payment.threeDS.expireStale() for serverless and cron schedulers Thanks to @Enard52.
  • Add the webhookForwarding plugin: forwards payment events to external microservices as HMAC-SHA256 signed JSON webhooks with configurable event filtering, exponential backoff retries, sensitive card data sanitization, and the verifyForwardedWebhook helper for receivers. Thanks to @Enard52.

Fixed

  • failover: a payment that failed with an HTTP 500, 502 or 504 answer no longer moves to a backup provider, because the provider may have charged the card before the error. These statuses are out of the default on codes and are ignored even when listed; 503 still fails over.
  • Plugin endpoints refuse HTML form bodies on POST with 415, like the built-in actions, so another site cannot post to them with the visitor's cookies (CSRF); an endpoint a third party posts a form to sets the new acceptForm: true. An onRequest hook that throws now stops the request with 503 instead of letting it through, and rateLimit gets passOnStoreError for applications that prefer to stay open while their store is down.
  • redact: fields and custom now add to the defaults instead of replacing them, so listing one extra field no longer unmasks the CVC or the TCKN pattern; cardHolderName, securityCode and provider secrets (storeKey, hashKey, apiSecret, clientSecret, terminalProvPassword) are masked by default; and the result the call returns keeps paymentId, conversationId, the 3D Secure and checkout form pages and the stored card tokens as the provider sent them.
  • refundApproval: the approve and reject endpoints take the approver from the new getActor option instead of the request body (and answer 403 without it), a request body can no longer mark a refund as already approved, cancellations wait for approval unless the new cancelAmount option puts them under the threshold, amounts are parsed strictly, and approving the same request twice refunds once.