Stripe — payment gateway integration profile
Also known as: Stripe Checkout
Stripe Payments
Category: global-card
Regions: Global
Countries: US
GB
EU
ZA
global
Currencies: USD
EUR
GBP
ZAR
and 135+ presentment currencies
Payment methods: card
apple_pay
google_pay
link
bank_debit
bnpl

Authentication:
model: bearer-secret-key
key_types: sk_test_
sk_live_
pk_test_
pk_live_
rk_
whsec_
sandbox_instant: yes
kyc_required_for_live: yes


Payment initiation:
flow: redirect
endpoint: POST https://api.stripe.com/v1/checkout/sessions
http_method: POST
required_params: mode
line_items
success_url
returns: id
url
payment_status
status
amount_unit: minor-subunit


Status handling:
mechanisms: webhook
poll
webhook_verification: Header 'Stripe-Signature: t=..,v1=..'; HMAC-SHA256 over '{t}.'+rawBody vs whsec_; 300s tolerance; RAW body required
raw_status_values: paid
unpaid
no_payment_required
succeeded
processing
requires_action
requires_confirmation
requires_capture
requires_payment_method
canceled
status_map: paid: paid
succeeded: paid
no_payment_required: paid
unpaid: pending
processing: pending
requires_action: pending
requires_confirmation: pending
requires_capture: pending
requires_payment_method: failed
canceled: failed
charge.dispute.created: disputed
charge.refunded: refunded

Capabilities:
redirect: yes
poll: yes
webhook: yes
mobile_push: no
refund: yes
recurring: yes

Credentials required:
key: secretKey
label: Secret Key (sk_)
secret: yes
note: server-side auth for all calls
key: webhookSecret
label: Webhook Signing Secret (whsec_)
secret: yes
note: needed to verify inbound events

Sandbox:
test_credentials: note: test keys instant from dashboard.stripe.com/test/apikeys, no KYC
test_cards: success
generic_decline
insufficient_funds
3ds_required
notes: any future expiry, any CVC. Zero-decimal currencies (JPY,KRW,VND,+~13) use whole units.

Known pain points and mitigations:
problem: Webhook signature verification fails
cause: JSON body-parser mutates the raw body before HMAC
mitigation: Verify against the raw request bytes, before any JSON parser; dedicate a raw-body route
severity: critical
problem: Duplicate order processing
cause: Stripe delivers events at-least-once (duplicates)
mitigation: Dedupe on event id; make side-effects idempotent
severity: high
problem: Out-of-order events / webhook beats redirect
cause: Events not guaranteed chronological
mitigation: Monotonic state machine keyed on your txn id; re-fetch object; never gate fulfillment on redirect
severity: high
problem: 100x over/undercharge
cause: cents vs zero-decimal currency confusion
mitigation: Single amount format in your API; convert to minor unit internally via a zero-decimal table
severity: high
problem: SCA/3DS payments silently stall
cause: Treating a created PaymentIntent as paid, missing requires_action
mitigation: Map requires_action -> pending; use hosted Checkout so Stripe handles 3DS
severity: medium

SDKs:
node: stripe
php: stripe/stripe-php
rest_direct_ok: yes

Notes: Zimbabwe is NOT a supported Stripe merchant country for live payouts — a ZW merchant needs an entity in a supported country. Sandbox testing works fine.

Fields not yet cross-checked against official docs: exact supported-country count