payfyio
Guides

Changelog

Release history for payfyio — every version from the v0.1 launch through the latest release.

Release history. Every published version is listed below, newest first. payfyio is an early public release (0.x): the API is stabilizing toward a v1.0 and minor versions may still introduce changes. Each entry below pins the features and breaking changes for that version, so you can match the docs to the version you have installed (npm ls @fyio/payfyio). Anything from pre-launch development cycles is archived at the bottom for historical reference only and does not apply to 0.x.

v0.7.0 — Garanti BBVA 3D Secure

Garanti.completeThreeDSPayment used to fail closed — it returned failure for every callback because no response-hash verification existed. It now verifies the bank's hash and confirms real payments. Verified end-to-end against the bank's sandbox.

⚠️ Breaking for Garanti users. The request signatures were the old v0.01 SHA-1 shapes and did not authenticate against GVP; they are now the documented API version 512 SHA-512 forms. No config change is needed — but if you had worked around the old hashes, remove the workaround.

New

  • Garanti 3D Secure works. 3DS runs at GVP's 3D_PAY security level: the bank authenticates the cardholder and provisions in one leg, then posts the final result to your callbackUrl. There is no second call to make.
  • Callback verification. completeThreeDSPayment recomputes SHA512(hashparams values + storeKey), compares constant-time, and requires the bank's signed field list to cover mdstatus + procreturncode — so a forged callback cannot sign a harmless subset and slip past. The hash is checked before any status field is read. The charged amount is bound at init inside secure3dhash, so the callback's unsigned txnamount echo is never trusted.
  • verifyGaranti3DHash(callbackData, storeKey) is exported for verifying the callback outside the provider (webhook routers, edge functions).
  • refundPassword — optional Garanti config for the PROVRFN provision user's own password; defaults to provisionPassword. Refund and void now run as PROVRFN.

Changed

  • Garanti request hashes are SHA-512 (API v512). HashData = SHA512(OrderID + TerminalID + CardNumber + Amount + CurrencyCode + SHA1(password + terminalId.padStart(9,'0'))) for /VPServlet, and secure3dhash = SHA512(TerminalID + OrderID + Amount + CurrencyCode + SuccessURL + ErrorURL + Type + InstallmentCnt + StoreKey + hashedPassword) for the 3D engine. Asserted against the golden vector in the bank's own docs.
  • Mode follows mode. Requests were hardcoded Mode=PROD, which GVP rejects on the test host; sandbox requests are now tagged Mode=TEST.
  • secure3DStoreKey is optional and defaults to storeKey. GVP issues one key, and requiring a second one made 3DS unusable out of the box.

Notes

Verified against sanalposprovtest.garantibbva.com.tr: non-3D sale, order inquiry, and a full 3D_PAY round trip (form → 3D engine → callback → completeThreeDSPayment). Void and refund authenticate correctly but are declined at the host by the shared public test terminal (RPC-05) — verify reversals on your own terminal.

İş Bankası, Ziraat and Yapı Kredi remain fail-closed until their own response-hash verification is implemented.

v0.6.0 — Marketplace / escrow library surface

Building blocks for custody-less escrow, payouts, and marketplace splits. Everything is additive — existing callers and the 11 untouched providers are unaffected (same optional-field / optional-base-method pattern as binCheck / installmentInfo).

⚠️ License & custody. payout and marketplace split (submerchants, PaymentRequest.split) move money to a third party. Enabling real money-out requires payment-institution licensing and a custody / sponsor-bank arrangement (in Türkiye: a TCMB Ödeme Kuruluşu license or a licensed partner). This release ships the library surface only — it does not, by itself, make you a licensed PSP.

⚠️ Sandbox verification. Endpoint paths and request fields for the money-movement features (capture/void, payout, submerchant, split) and the iyzico webhook are covered by unit tests with a mocked transport — they are not yet verified against live sandboxes. Run an integration pass with real sandbox credentials before relying on these in production.

New

  • Pre-auth / Capture / Void (delayed capture) — PaymentRequest.capture: false authorizes without capturing; complete later with payment.capturePayment({ paymentId, amountMinor? }) (partial supported) or release with payment.voidAuthorization({ paymentId }). Implemented for iyzico (/payment/preauth + /postauth + /cancel) and Stripe (capture_method: manual). Other providers throw Capture/Void not supported by this provider.
  • Minor-unit money helperstoMinor / fromMinor / formatMinor / minorUnitDigits, exported at the package root. Correct for zero-decimal (JPY/KRW) and three-decimal (KWD/BHD) currencies.
  • Idempotency keysidempotencyKey? on every mutating request. Stripe maps it to the native Idempotency-Key header; iyzico maps it to conversationId; other providers ignore it silently.
  • Payout / Transferpayment.payout({ to, amountMinor, currency, reference }) sends money out to a third party (PayoutDestination = { iban } | { accountId }).
  • Submerchant CRUD + marketplace splitpayment.submerchants.create / update / retrieve(...); PaymentRequest.split[] + platformCommissionMinor. Implemented for iyzico and Stripe Connect (single-destination).
  • Unified webhooksverifyWebhook(provider, rawBody, headers, secret) returns a normalized PayfyioEvent discriminated union and throws WebhookSignatureError on an invalid signature. (iyzico webhook normalization lands in a follow-up.)

v0.5.0 — Polar.sh + Lemon Squeezy

  • Polar.sh provider — hosted checkout for digital products and subscriptions. initThreeDSPayment / getPayment / refund / cancel + verifyWebhookSignature (Standard-Webhooks HMAC-SHA256, constant-time compare, key-rotation aware). Direct card (createPayment) is intentionally unsupported — Polar is hosted-only.
  • Lemon Squeezy provider — hosted checkout with merchant-of-record tax handling (LS collects and remits VAT/sales tax). initThreeDSPayment / getPayment / refund + verifyWebhookSignature (X-Signature, HMAC-SHA256 hex). Direct card and cancel are intentionally unsupported — unpaid checkouts expire.

v0.4.0 — Package renamed to @fyio/payfyio

  • payfyio@fyio/payfyio. All future releases ship under the new scoped name. The API, types, classes, and behaviour are 100% identical — only the install name changes.

    npm uninstall payfyio
    npm install @fyio/payfyio
    - import { Payfyio } from 'payfyio';
    + import { Payfyio } from '@fyio/payfyio';

    The unscoped payfyio package is deprecated; existing installs keep working but show a deprecation notice. No further versions ship under the old name.

v0.3.0 — Coinbase Commerce + security-event hook

  • Coinbase Commerce provider — crypto checkout (BTC, ETH, USDC, …). initThreeDSPayment / getPayment / cancel + verifyWebhookSignature (X-CC-Webhook-Signature, HMAC-SHA256, constant-time compare). Direct card and programmatic refund are intentionally unsupported — Commerce is a hosted crypto flow.
  • Security-event hook — observe abuse/probing on your own infrastructure via onSecurityEvent + securityNotifiers on PayfyioConfig. New event types (callback_verification_failed, provider_http_error, config_invalid, retry_suppressed, custom), built-in consoleNotifier() / webhookNotifier(), and a throttle() de-duper. Events never contain card data, CVV, expiry, or secret keys. Fully backward compatible.

v0.2.1 — Docs

  • English versions of CONTRIBUTING, BETA_RELEASE, RELEASE_WORKFLOW and the tests README. No runtime / API changes.

v0.2.0 — Security hardening (callbacks & HTTP signing)

Breaking changes — see below. These close real callback-forgery and double-charge risks; review before upgrading.

  • Parampos: fixed a 3DS callback-forgery — the verification hash now uses the server-side configured GUID instead of one echoed back in the callback.

  • PayTR (breaking): callback verification and all request tokens now use merchant_key as the HMAC-SHA256 key per PayTR's spec. The provider now requires apiKey (your merchant_key).

  • Garanti, İş Bankası, Ziraat, Yapı Kredi (breaking): completeThreeDSPayment now fails closed (returns failure) until proper per-bank response hash/MAC verification is implemented — previously it trusted mdStatus alone, so a forged callback could mark an unpaid order paid.

  • Callback hash comparisons are now constant-time (timingSafeEqual).

  • Automatic retries are restricted to idempotent HTTP methods — a charge/refund POST is never silently re-sent on a timeout (double-charge guard).

  • PayTR errors no longer return the raw axios error object (which carries the Authorization header) to callers.

    Stripe, PayPal and iyzico were reviewed and are unaffected — they confirm 3DS by re-querying the provider server-side rather than trusting the callback.

v0.1.0 — Initial public release

The first public release. One contract, every provider — evolving toward a stable v1.0.

Providers

  • 5 gateways — İyzico, PayTR, Parampos, Stripe, PayPal
  • 5 Turkish bank Virtual POS integrations — Akbank, Garanti BBVA, İş Bankası, Yapı Kredi, Ziraat Bankası

Core API

  • Single Payfyio class — defaultProvider + providers map
  • Runtime provider switching via payment.use("provider")
  • Typed getters per provider (payment.iyzico, payment.akbank, …)
  • getEnabledProviders() and isProviderEnabled() helpers

Payment surface

  • createPayment — direct card charge (2D)
  • initThreeDSPayment / completeThreeDSPayment — 3D Secure flow
  • initCheckoutForm — hosted checkout / iframe
  • refund (full / partial), cancel, getPayment
  • Provider extras: binCheck, installmentInfo, subscription billing (İyzico)

Transport & engineering

  • PayfyioHandler — drop-in REST handler for Next.js / Express
  • PayfyioClient + createPayfyioClient — typed browser client
  • Unified error shape across every provider; normalized currency codes and amounts
  • 100% TypeScript, one peer dependency (axios), HMAC-SHA256 / SHA-512 signature validation built in, MIT licensed

Pre-1.0 (archived)

Earlier iterations of this library shipped under different class names and adapter layouts before the v0.1 launch (the old payfyio/adapters/* layout, a different provider scope, etc.). They are listed here for historical context only — do not target them in new code.

On this page