Payment

iyzico & Stripe with 3-D Secure

The payment block adds checkout to your API without committing you to one processor. A provider abstraction sits in front of iyzico and Stripe, so the same routes, saved-card flows and webhook handling work whichever you choose.

It covers the full lifecycle: redirect-based checkout, 3-D Secure, saved payment methods, marketplace sub-merchant splitting, and a provider callback for asynchronous results. Provider credentials are referenced by env-var name and never inlined.

Provider & flow#

Select the processor and define where users land after a payment resolves. Redirect URLs drive the hosted-checkout return journey.

enabledbooleanOptional

Mount the payment routes and initialise the chosen provider.

Defaultfalse
provider'iyzico' | 'stripe'Optional

The active payment processor. Fill in the matching credentials block below.

basePathstringOptional

Route prefix for all payment endpoints.

Default"/payment"
defaultCurrency / defaultLocalestringOptional

Fallback currency (e.g. TRY, USD, EUR) and locale (e.g. tr, en) when a request omits them. Default to "TRY" and "tr" respectively when the config omits them.

Default"TRY" / "tr"
successRedirectUrl / failedRedirectUrl / errorRedirectUrlstringOptional

Where the browser is sent after a successful, failed or errored payment respectively. Default to the literal paths "/payment/success", "/payment/failed" and "/payment/error" — these are hardcoded literals, NOT derived from basePath, so customising basePath does not recompute them.

Default"/payment/success" / "/payment/failed" / "/payment/error"
callbackUrlstringOptional

URL the provider posts asynchronous results back to. Auto-generated from basePath if omitted.

Capabilities#

Saved methods and 3-D Secure are ON by default — you opt OUT of them; sub-merchant splitting is the one capability that is off by default and opt-in.

savedMethodsEnabledbooleanOptional

Let users store cards for faster repeat checkout (provider-tokenised; no PAN touches your DB). On by default — set false to disable.

Defaulttrue
threeDSecureEnabledbooleanOptional

Enable the 3-D Secure challenge flow. On by default — shifts liability and satisfies SCA requirements; set false to disable.

Defaulttrue
subMerchantsEnabledbooleanOptional

Enable marketplace sub-merchants so a payment can be split and commission retained. Off by default — opt in to unlock marketplace splitting.

Defaultfalse

iyzico#

Credentials for the iyzico processor. Each field accepts a literal value or — preferably — the name of an env var holding the secret.

iyzicoobjectOptional

iyzico provider credentials.

apiUrlstringOptional

iyzico API base URL (env-var name or literal). Use the sandbox URL in development.

apiKeystringOptional

iyzico API key (env-var name or literal). Sensitive.

secretKeystringOptional

iyzico secret key (env-var name or literal). Sensitive.

Stripe#

Credentials and client tuning for Stripe. Requires the optional stripe npm package. The webhook secret verifies that incoming events genuinely came from Stripe.

stripeobjectOptional

Stripe provider configuration.

secretKeystringOptional

Stripe secret key (sk_test_… / sk_live_…), as env-var name or literal. Sensitive.

webhookSecretstringOptional

Webhook signing secret (whsec_…) used to verify event authenticity. Sensitive.

apiVersionstringOptional

Pin a Stripe API version. Defaults to the library's latest.

maxNetworkRetriesnumberOptional

Automatic retry count for transient network failures.

Default2
timeoutnumberOptional

Per-request timeout in milliseconds.

Default30000

Under the hood — provider abstraction#

createPaymentService reads your config and returns a single PaymentProvider, so the routes never know which gateway they're talking to. It fails safe: a missing or half-configured provider returns null and the payment routes simply don't mount.

one interface, two providersPaymentProviderOptional

iyzico and stripe each implement the same PaymentProvider contract (createIyzicoProvider / createStripeProvider). Your code and the generated routes call the interface; swapping providers is a config change, not a code change.

env-resolved credentialsresolveEnvValueOptional

Every credential (apiKey, secretKey, webhookSecret, apiUrl) is run through resolveEnvValue — if the string matches an environment variable it uses that, otherwise the literal. So the same config travels across environments with secrets in env vars.

fail-safe initnull on misconfigOptional

If payment.enabled is false the service simply returns null (no warning — the guard runs before the logger is even created). If payment is enabled but the provider block is missing or required credentials don't resolve, it logs a warning and returns null. Either way the app still boots, just without payment routes, instead of crashing.

webhook secretStripeOptional

The Stripe webhook secret is threaded into the service so the webhook route can verify event signatures before trusting them; a missing secret is warned about loudly because it disables that verification.

Marketplace money layer#

config.payment.marketplace turns on the provider-neutral marketplace subsystem: an immutable double-entry ledger, per-sale split breakdown (gross → providerFee → platformFee → reserve → netPayable), risk reserves, delayed settlement, a payout-request workflow, and disputes. Writes to the sensitive money tables (payment_ledger_entries, payment_reserves, payment_splits, …) through the generic entity API are locked to godmin superusers (non-godmin POST/PUT/PATCH/DELETE get 403); all legitimate writes go through the dedicated /payment routes and marketplace services, which derive ownership server-side. Generic reads stay on the normal claim model.

enabledbooleanOptional

Turns on the marketplace money layer (ledger, splits, reserves, payouts, disputes).

defaultSettlementDelayDaysnumberOptional

Days a completed sale's net payable is held before it settles to the seller's available balance.

Default7
newSellerDelayDaysnumberOptional

Longer settlement delay applied to new/unseasoned sellers instead of the default delay.

Default14
reserveRatenumber (0–1)Optional

Fraction of each sale's after-fee amount held back as a risk reserve (clamped to 0–1). 0 = no reserve.

Default0
reserveReleaseDaysnumberOptional

Days a held reserve waits before it is eligible for release back to the seller.

Default0
minimumPayoutAmountnumberOptional

Smallest balance that may be requested as a payout (in minor units, e.g. cents — 500 = 5.00; marketplace ledger/split amounts are all integer minor units).

Default0
defaultCurrencystringOptional

Currency for marketplace ledger/splits when not otherwise specified; falls back to payment.defaultCurrency, then USD.

Defaultpayment.defaultCurrency ?? 'USD'
autoReleaseReservesbooleanOptional

When true, reserves past their reserveReleaseDays are released automatically; otherwise release is manual/operator-driven.

Defaultfalse

Related sections