Back to blog

Payment infrastructure

Building payment infrastructure with Iyzico: Turkey realities

Iyzico may not feel as smooth as Stripe, but for many Turkey-focused products — from event ticketing to subscription SaaS — it is the practical starting point. The hard part is not wiring the SDK; it is what you show when payment fails, how you handle order state when webhooks lag, and how refunds fit your fulfillment flow.

8 min read

Quick answer

In Turkey, account setup, 3DS requirements, and merchant contracts differ from global providers. Model payment state in one table (pending, requires_action, paid, failed, refunded), verify webhooks with signatures and idempotency keys, and run a low-amount production test with a real card after sandbox — panel settings often behave differently in prod.

Why Iyzico comes first in Turkey

Global payment providers do not fit every local use case. In Turkey, company structure, merchant onboarding, mandatory 3DS, and cardholder behavior differ from a typical Stripe-first workflow. Teams used to Stripe may find Iyzico panels and flows less polished at first glance — but for TL billing, local compliance, and merchant account reality, it remains the default choice for many domestic products. The same provider can power event checkout, SaaS subscriptions, or marketplace payments; what changes is integration depth and operational discipline, not the logo on the checkout page.

Connecting the SDK is the easy part

Real complexity appears after checkout opens: what the user sees on decline, whether their order still exists after 3DS redirect, whether the UI claims success before the webhook arrives, and whether refunds update inventory, tickets, or subscription state automatically. Shipping without answers to these questions is why sandbox-green flows break on the first production Friday.

Where integrations usually break

Non-idempotent webhooks process the same payment twice — common under high-volume ticket sales because providers legitimately retry callbacks. Lost session-to-order mapping after 3DS return strands users in “I paid but have no order,” especially in mobile browsers and in-app webviews. Sandbox behavior diverges from production merchant settings: installments, BIN rules, callback URLs. Cookie and redirect issues between webviews and hosted payment pages silently drop sessions. Showing “payment complete” before webhook confirmation increases support load and dispute risk.

How to model payment state on the backend

Keep payment status in a single payment_intent or order_payment table: pending, requires_action, paid, failed, refunded. The UI reads this state; webhooks only update it — they should not re-run business logic. Webhook handlers in NestJS, Go, or similar stacks need signature verification and idempotency keys; duplicate event or payment IDs must no-op. Orders, tickets, or subscriptions reference payment state; fulfillment must not run until paid is confirmed. In high-traffic ticketing, this separation prevents double issuance and inventory drift.

Production testing and mobile vs. web

Sandbox success does not guarantee production merchant panel behavior. Before launch, run a low-amount live card test: 3DS return, webhook delay, and refund paths only prove out this way. On mobile, in-app digital goods fall under store rules; physical services, event tickets, or real-world fulfillment are different — clarify this before choosing payment architecture. Web checkout plus deep link return works on mobile but carries UX cost. Native IAP, external web payment, or hybrid models depend on product and distribution channel; there is no universal answer.

What to evaluate

Webhook idempotency
Duplicate notifications must not double-charge or double-fulfill. Protect event or idempotency keys with a unique database constraint.
Clear state machine
UI, webhooks, and fulfillment must read the same payment state table. “Callback received” alone is not proof of paid.
Production validation
Sandbox does not mirror prod merchant settings, 3DS return, or real-card behavior. Plan a small live test before marketing spend.

Frequently asked questions

What differs most between Iyzico sandbox and production?

Callback URL allowlists, installment and BIN settings, 3DS enforcement, and production-only limits in the merchant panel. Flows that pass in sandbox can fail when a prod-only option is disabled.

Order lost after 3DS return — what should we fix?

Persist order or payment id before 3DS via session, cookie, or deep link parameter. The return page should query current payment state instead of starting a new checkout; do not rely on webhook timing alone.

What should users see when webhooks are delayed?

Show an intermediate state such as “payment received, confirming your order.” Do not fulfill until paid is confirmed by webhook or provider query. Polling or SSE improves UX while state catches up.

How does Iyzico checkout work inside mobile apps?

Digital content and subscriptions may fall under store IAP rules. Event and service sales often use external web checkout with deep link return. If using webviews, test cookie and third-party storage restrictions early.

Related guides

Let’s clarify this for your own project

Share your project briefly and I’ll prepare a free technical review covering the possible scope, roadmap, and key risks to watch.

Request a technical review

© 2026 TetryLabs. All rights reserved.