# @prood/payment-stripe (https://prood.com/docs/packages/payments/stripe)

`@prood/payment-stripe` implements the `PaymentProvider` interface for Stripe, using the Checkout Sessions API with the embedded Payment Element.

## Installation [#installation]

Workspace package. Available from the source repo for now.

## Usage [#usage]

```ts
import { StripePaymentProvider } from '@prood/payment-stripe'

const provider = new StripePaymentProvider({
  secretKey: config.secretKey,
  webhookSecret: config.webhookSecret,
  publishableKey: config.publishableKey,
})
```

Via commerce factory (preferred in apps):

```ts
import { getTenantPaymentProvider } from '@prood/commerce'
const { provider } = await getTenantPaymentProvider(orgId, 'stripe')
```

## Configuration [#configuration]

| Field | Required | Description |
| --- | --- | --- |
| `secretKey` | Yes | Server-side secret key |
| `webhookSecret` | Webhooks | Signing secret |
| `publishableKey` | Client UI | Publishable key for Payment Element |

Each store enters these under Integrations in the dashboard. There is no environment fallback.

## Payment flow [#payment-flow]

1. `createSession()` → creates a Checkout Session
2. Client renders the Payment Element with its `clientSecret`
3. Customer submits → Stripe handles 3DS if required
4. `confirmSession()` → reads the Checkout Session's status
5. Webhook `checkout.session.completed` → the source of truth

## Webhook events [#webhook-events]

| Event | Action |
| --- | --- |
| `checkout.session.completed` | `payment.captured` when paid, otherwise `payment.authorized` |
| `checkout.session.async_payment_succeeded` | `payment.captured` |
| `checkout.session.async_payment_failed` | `payment.failed` |
| `checkout.session.expired` | `payment.cancelled` |
| `charge.refunded` | Record a refund, including one made in the Stripe dashboard. Stripe's refunded totals decide between `refunded` and `partially_refunded` |

Webhook URL: `https://prood.com/pay/api/webhooks/stripe/{orgId}`

## Refunds [#refunds]

```ts
await provider.refund({
  sessionId: 'cs_xxx', // the Checkout Session on the order
  amount: 50, // partial refund in major units
  reason: 'requested_by_customer',
})
```

`refund()` resolves when Stripe accepts the refund and reads nothing back. Stripe honours `idempotencyKey`, so a retry can't send the money twice.

## Test mode [#test-mode]

Use Stripe test keys (`sk_test_...`, `pk_test_...`):

| Card | Result |
| --- | --- |
| `4242 4242 4242 4242` | Success |
| `4000 0000 0000 3220` | 3DS required |
| `4000 0000 0000 9995` | Declined |

## Related pages [#related-pages]

<Cards>
  <Card title="Payment integration" href="/docs/guides/payment-integration" description="Setup guide." />
  <Card title="Checkout payments" href="/docs/apps/checkout/payments" description="Payment Element UI." />
</Cards>
