Repository navigation
v0.12.0-beta.2
Pre-releaseAdded
-
Add
commissionRouter(subpathbetter-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
fraudRulesplugin 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 fromX-Forwarded-Forunless you name that header and your proxies. It ships as its ownbetter-payment/fraudentry point, sobetter-payment/pluginsstays 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 fromhashparamsand confirmed with the bank Thanks to @sizinajans (#195). -
Rename the
localizedErrorsplugin toi18nand 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 inlocales. HTTP handler responses pick their language with theheader(Accept-Language),cookieandcallbackstrategies, in the order you choose;payment.errors.detectLocale(request)runs the same detection.localizedErrors,errorMessages,LocalizedErrorsOptionsandErrorMessageDictionarystill work and are deprecated. -
Add Model Context Protocol (MCP) server plugin (
mcp) for AI agents and assistants. Thanks to @Enard52. -
Add the
better-payment/nestjsframework 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
openAPIplugin: 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 itsbasePath. The reference is off inmode: 'production'unlessdisabled: falseis set, andprivileged: trueputs it behind the handler'sauthorizehook. Plugin endpoint contexts now always havehtml(), and plugins get a read-onlyendpointslist. Thanks to @Enard52. -
Add
pendingResolverplugin 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
captchaplugin 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_MISSINGandCAPTCHA_INVALID - Exclude provider callback and 3DS completion operations Thanks to @Enard52.
- Add
-
Add
rateLimitplugin 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 withtrustProxy, otherwise an explicitkeyis required. Thanks to @Enard52. -
Plugin: redact card data and personal data from logs and events (PCI DSS & KVKK) Thanks to @Enard52.
-
Add the
refundApprovalplugin: 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(subpathbetter-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
telemetryplugin: one OpenTelemetry-compatible span per provider call with the provider, operation, result, normalized error code, HTTP status, retry count and duration, plus apayment.callscounter and apayment.durationhistogram. It has no dependencies — it accepts any structurally compatibletracerandmeter, so a real@opentelemetry/apitracer 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
threeDSTimeoutplugin tracking initiated 3D Secure payments across providers - Support configurable timeout duration (e.g.
'15m'), pluggableThreeDSFlowStore, andonExpirecallback - Query provider before expiring to protect against late successful callbacks
- Provide
payment.threeDS.expireStale()for serverless and cron schedulers Thanks to @Enard52.
- Add
-
Add the
webhookForwardingplugin: forwards payment events to external microservices as HMAC-SHA256 signed JSON webhooks with configurable event filtering, exponential backoff retries, sensitive card data sanitization, and theverifyForwardedWebhookhelper 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 defaultoncodes and are ignored even when listed; 503 still fails over.- Plugin endpoints refuse HTML form bodies on
POSTwith 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 newacceptForm: true. AnonRequesthook that throws now stops the request with 503 instead of letting it through, andrateLimitgetspassOnStoreErrorfor applications that prefer to stay open while their store is down. redact:fieldsandcustomnow add to the defaults instead of replacing them, so listing one extra field no longer unmasks the CVC or the TCKN pattern;cardHolderName,securityCodeand provider secrets (storeKey,hashKey,apiSecret,clientSecret,terminalProvPassword) are masked by default; and the result the call returns keepspaymentId,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 newgetActoroption 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 newcancelAmountoption puts them under the threshold, amounts are parsed strictly, and approving the same request twice refunds once.