---
name: payment-integration
description: Integrate a payment gateway (Stripe / Omise / 2c2p) with webhooks + idempotency. Use for billing/checkout.
---

# Skill: Payment Integration

## When to use

Checkout, subscriptions, invoicing. (Not enabled by default — portal-platform has no payment preset.)

## Steps

1. Server-side only — never expose secret keys to the client; the client uses publishable keys + tokens.
2. Create the intent/charge server-side; return the client a token/secret to confirm.
3. Handle webhooks for the source of truth (payment succeeded/failed) — never trust the client's "success".
4. Make webhook handlers **idempotent** (dedupe by provider event id).
5. Record every state transition in an append-only ledger + audit log.

## Gotchas

- Webhooks arrive more than once and out of order — dedupe + handle any order.
- Verify webhook signatures; reject unsigned.
- Money is integer minor units (satang/cents) — never float.
- PCI scope: never store card numbers; let the gateway tokenize.
- Reconcile daily against the provider; don't trust local state alone.

## Validation

Test-mode charge succeeds; webhook is idempotent; signature verified; amounts integer; ledger balances.
