Stripe
Setup guide for the stripe payments provider. The shared API (initiate_payment,
verify_payment, refund_payment, webhooks, hooks, saved methods) is documented in
Payments.
1. Get credentials. In the Stripe Dashboard,
under Developers -> API keys, copy the Secret key (sk_test_... in test
mode, sk_live_... in production).
2. Set environment variables:
KIRAK_PAYMENT_STRIPE_SECRET_KEY=sk_test_...KIRAK_PAYMENT_STRIPE_WEBHOOK_SECRET=whsec_... # from step 33. Configure the webhook. Under Developers -> Webhooks -> Add endpoint,
point it at https://your-domain.com/payments/webhook/stripe and select at
minimum: checkout.session.completed, checkout.session.async_payment_succeeded,
checkout.session.async_payment_failed, invoice.payment_succeeded,
invoice.payment_failed, customer.subscription.updated,
customer.subscription.deleted, charge.refunded. The two async_payment
events report payments made with a delayed method such as a bank debit; without
them those payments stay PENDING. Copy the endpoint’s
Signing secret into KIRAK_PAYMENT_STRIPE_WEBHOOK_SECRET; without it every
webhook fails with WEBHOOK_SECRET_NOT_CONFIGURED (500). For saved methods,
also send payment_method.detached, payment_method.updated,
payment_method.automatically_updated and customer.updated to the webhook
endpoint. For off-session charges, also send payment_intent.succeeded and
payment_intent.payment_failed.
One Stripe account, several Kirak databases (two apps, or staging and
production, often in test mode): Stripe sends every event to every endpoint,
so each app also receives the others’ events. A checkout completes only the
row that stored its session id when the session was created (so if that id
cannot be stored, initiate_payment fails and no checkout url is returned),
an off-session charge only the row whose random reference (kirak_ref in
payment_meta, sent in the PaymentIntent’s metadata) it carries (one made
before references carries none and matches only a row without one), and a setup
session saves a card only for the user whose Stripe customer this instance
created; everything else is acknowledged and left alone. Several Stripe
instances in one app record processed events per instance.
4. Use it:
# One-time paymentresult = await kirak.payments.initiate_payment({ "provider": "stripe", "user_id": "42", "amount": 2999, "currency": "USD", "name": "Pro Plan", "type": "one_time",})
# Subscription -- subscription_plan_id is a Stripe Price IDresult = await kirak.payments.initiate_payment({ "provider": "stripe", "user_id": "42", "amount": 2999, "currency": "USD", "name": "Pro Plan", "type": "subscription", "subscription_plan_id": "price_abc123", "interval": "month", "interval_count": 1, # optional, default monthly})Webhook events
Section titled “Webhook events”after_webhook receives these provider-neutral event names (see
Webhook Hooks):
data["event"] |
Gateway events |
|---|---|
payment_completed |
checkout.session.completed (only when paid), checkout.session.async_payment_succeeded, payment_intent.succeeded (off-session charges only) |
payment_failed |
invoice.payment_failed, checkout.session.async_payment_failed, payment_intent.payment_failed (off-session, declined) |
subscription_renewed |
invoice.payment_succeeded |
subscription_updated |
customer.subscription.updated (other statuses) |
subscription_past_due |
customer.subscription.updated with status past_due or unpaid |
subscription_cancelled |
customer.subscription.deleted |
refund_completed |
charge.refunded |
refund_pending |
– (reserved) |
dispute_created |
charge.dispute.created |
dispute_updated |
charge.dispute.closed |
payment_method_saved |
checkout.session.completed of a setup session |
payment_method_removed |
payment_method.detached |
payment_action_required |
payment_intent.payment_failed with authentication_required (off-session) |
A Stripe checkout session paid by a delayed method (a bank debit) is reported as checkout.session.completed with the payment still unpaid. Kirak records it as PENDING and reports no event; payment_completed is reported when checkout.session.async_payment_succeeded arrives, and payment_failed on checkout.session.async_payment_failed.