Files
novi-lessons/Les17-Externe-APIs/Les17-Lesopdracht.md
2026-06-03 16:58:25 +02:00

205 lines
4.5 KiB
Markdown

# Les 17 — Lesopdracht
## Stripe Checkout setup + eerste test-betaling
**Duur:** 30 min in-class
---
## Doel
Werkende Stripe Checkout in een Next.js app — pricing page, checkout session, en een succesvolle test-betaling.
---
## Stap 1 — Stripe account
1. Maak gratis account op https://stripe.com (skip business questions met "test mode")
2. Dashboard → Test mode (toggle rechtsboven)
3. Developers → API keys → kopieer:
- `Publishable key` (`pk_test_...`)
- `Secret key` (`sk_test_...`)
---
## Stap 2 — Product + Price aanmaken
In Stripe Dashboard:
1. Products → Add product
2. Naam: "Premium plan"
3. Price: € 9.99 / maand, recurring (subscription)
4. Save → kopieer `price_xxxxx` van de price die je net maakte
---
## Stap 3 — Next.js project
```bash
pnpm create next-app@latest stripe-demo \
--typescript --tailwind --app --no-src-dir --import-alias "@/*"
cd stripe-demo
pnpm add stripe
```
`.env.local`:
```
STRIPE_SECRET_KEY=sk_test_...
NEXT_PUBLIC_STRIPE_PRICE_ID=price_...
APP_URL=http://localhost:3000
```
---
## Stap 4 — Pricing page
`app/page.tsx`:
```tsx
"use client";
export default function Pricing() {
async function subscribe() {
const res = await fetch("/api/checkout", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
priceId: process.env.NEXT_PUBLIC_STRIPE_PRICE_ID,
email: "test@example.com",
}),
});
const { url } = await res.json();
window.location.href = url;
}
return (
<main className="max-w-md mx-auto p-12 text-center">
<h1 className="text-4xl font-bold mb-4">Premium Plan</h1>
<p className="text-2xl mb-2"> 9.99 / maand</p>
<ul className="text-left my-6 space-y-2">
<li> Onbeperkte projecten</li>
<li> Priority support</li>
<li> Advanced analytics</li>
</ul>
<button
onClick={subscribe}
className="bg-blue-600 text-white px-6 py-3 rounded-lg font-semibold"
>
Subscribe nu
</button>
</main>
);
}
```
---
## Stap 5 — Checkout endpoint
`app/api/checkout/route.ts`:
```typescript
import Stripe from "stripe";
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
export async function POST(req: Request) {
const { priceId, email } = await req.json();
const session = await stripe.checkout.sessions.create({
mode: "subscription",
line_items: [{ price: priceId, quantity: 1 }],
customer_email: email,
success_url: `${process.env.APP_URL}/success?session_id={CHECKOUT_SESSION_ID}`,
cancel_url: `${process.env.APP_URL}/`,
});
return Response.json({ url: session.url });
}
```
---
## Stap 6 — Success page
`app/success/page.tsx`:
```tsx
export default function Success() {
return (
<main className="max-w-md mx-auto p-12 text-center">
<h1 className="text-4xl font-bold mb-4 text-green-600"> Betaling geslaagd!</h1>
<p>Bedankt voor je aanmelding. Je krijgt zo een welkomstmail.</p>
</main>
);
}
```
---
## Stap 7 — Test
```bash
pnpm dev
```
Open http://localhost:3000:
1. Klik "Subscribe nu"
2. Stripe Checkout opent
3. Vul test-card in:
- Card: `4242 4242 4242 4242`
- Expiry: `12/34`
- CVC: `123`
- Postcode: willekeurig
4. Klik Subscribe
5. Redirect naar `/success` — werkt!
6. Check Stripe Dashboard → Payments — sessie zichtbaar
---
## Eisen
- [ ] Stripe account in test mode
- [ ] Product + price aangemaakt
- [ ] Pricing page werkt
- [ ] Checkout endpoint werkt
- [ ] Test-betaling slaagt met 4242 card
- [ ] Success page laadt na betaling
- [ ] In Stripe Dashboard zie je de transactie
---
## Tijdsindeling (30 min)
| Stap | Tijd |
|------|------|
| 1-2 — Stripe setup | 8 min |
| 3 — Project setup | 3 min |
| 4-5 — Pages + endpoint | 10 min |
| 6 — Success page | 2 min |
| 7 — Test | 7 min |
---
## Veelvoorkomende problemen
| Symptoom | Oplossing |
|----------|-----------|
| `Stripe is not defined` | `pnpm add stripe` opnieuw |
| `Invalid API key` | Check `sk_test_` (niet pk) in `.env.local` |
| `priceId required` | Check NEXT_PUBLIC_ prefix correct |
| 4242 card geweigerd | Check je staat in test mode (rechtsboven dashboard) |
| Success URL 404 | App URL klopt? `http://localhost:3000` (geen trailing slash) |
---
## Klaar? Verder met huiswerk
Het huiswerk voegt toe:
- Webhook handler met signature verify
- Resend welkomstmail bij betaling
- Retry logic voor externe calls
- `APIS.md` met je eindopdracht-toepassing
Zie `Les17-Huiswerk.md`.