# Stripe PaymentIntent in Svelte/SvelteKit

Svelte apps do not need a wrapper library. stripe-js works directly: a SvelteKit server route mints the PaymentIntent with the secret key, and the page component mounts a card element and confirms.

## Server route mints the secret

```
// src/routes/api/payment-intent/+server.ts
import Stripe from 'stripe';
import { STRIPE_API_KEY_VALUE } from '$env/static/private';
import { json } from '@sveltejs/kit';

const stripe = new Stripe(STRIPE_API_KEY_VALUE);

export async function POST({ request }) {
  const { amount, currency } = await request.json();
  const intent = await stripe.paymentIntents.create({
    amount,
    currency,
    automatic_payment_methods: { enabled: true },
  });
  return json({ 'clientSecret': intent.client_secret });
}
```

## Page confirms the card

```
[script]
  import { onMount } from 'svelte';
  import { loadStripe } from '@stripe/stripe-js';

  let cardEl;
  let stripe, card;

  onMount(async () => {
    stripe = await loadStripe('YOUR_PUBLISHABLE_KEY_VALUE');
    card = stripe.elements().create('card');
    card.mount(cardEl);
  });

  async function pay() {
    const { clientSecret } = await fetch('/api/payment-intent', {
      method: 'POST',
      body: JSON.stringify({ amount: 2000, currency: 'usd' }),
    }).then((r) => r.json());
    const { error, paymentIntent } = await stripe.confirmCardPayment(clientSecret, {
      payment_method: { card },
    });
    if (error) console.log(error.message);
    else if (paymentIntent.status === 'succeeded') console.log('paid');
  }
[/script]

[div bind:this={cardEl}][/div]
[button on:click={pay}]Pay[/button]
```

## Notes

- The secret key lives in `$env/static/private`, imported only by `+server.ts` files.
- `bind:this` gives stripe-js the DOM node; mount after `loadStripe` resolves.
- `confirmCardPayment` handles 3D Secure automatically.