diff --git a/clients/apps/web/src/app/(main)/docs/developers/guides/nextjs/page.mdx b/clients/apps/web/src/app/(main)/docs/developers/guides/nextjs/page.mdx
index 3e33d471eb..be20c960da 100644
--- a/clients/apps/web/src/app/(main)/docs/developers/guides/nextjs/page.mdx
+++ b/clients/apps/web/src/app/(main)/docs/developers/guides/nextjs/page.mdx
@@ -30,10 +30,10 @@ npx polar-init
## Install the Polar JavaScript SDK
-To get started, you need to install the Polar JavaScript SDK. You can do this by running the following command:
+To get started, you need to install the Polar JavaScript SDK and the Polar Nextjs helper package. You can do this by running the following command:
```bash
-pnpm install @polar-sh/sdk
+pnpm install @polar-sh/sdk @polar-sh/nextjs
```
## Setting up environment variables
@@ -130,7 +130,7 @@ export const ProductCard = ({ product }: ProductCardProps) => {
- Buy
+ Buy
{price}
@@ -138,7 +138,7 @@ export const ProductCard = ({ product }: ProductCardProps) => {
}
```
-Notice that we create a link to `/checkout` with a query parameter `priceId`. This is the ID of the price that the user will be charged for when they click the "Buy" button. We will configure this route in the next section.
+Notice that we create a link to `/checkout` with a query parameter `productId`. We will configure this route in the next section.
### Displaying Products
@@ -177,30 +177,16 @@ Go ahead and create a new GET route in Next.js.
```typescript
// src/app/checkout/route.ts
-import { api } from '@/polar'
-import { type NextRequest, NextResponse } from 'next/server'
-
-export async function GET(req: NextRequest) {
- const url = new URL(req.url)
- const productPriceId = url.searchParams.get('priceId') ?? ''
- // Polar will replace {CHECKOUT_ID} with the actual checkout ID upon a confirmed checkout
- const confirmationUrl = `${req.nextUrl.protocol}//${req.nextUrl.host}/confirmation?checkout_id={CHECKOUT_ID}`
-
- try {
- const result = await api.checkouts.custom.create({
- productPriceId,
- successUrl: confirmationUrl,
- })
-
- return NextResponse.redirect(result.url)
- } catch (error) {
- console.error(error)
- return NextResponse.error()
- }
-}
+import { Checkout } from '@polar-sh/nextjs'
+
+export const GET = Checkout({
+ accessToken: process.env.POLAR_ACCESS_TOKEN!,
+ successUrl: '/confirmation',
+ server: 'sandbox', // Use this option if you're using the sandbox environment - else use 'production' or omit the parameter
+});
```
-We can now easily create a checkout session & redirect there by creating a link to `/checkout?priceId={priceId}`. Just like we did in the `ProductCard` component.
+We can now easily create a checkout session & redirect there by creating a link to `/checkout?productId={productId}`. Just like we did in the `ProductCard` component.
### Handling the Confirmation Page
@@ -209,10 +195,10 @@ Create a new page in Next.js to handle the confirmation page. This is where the
```tsx
// src/app/confirmation/page.tsx
export default function Page({
- searchParams: { checkout_id },
+ searchParams: { checkoutId },
}: {
searchParams: {
- checkout_id: string
+ checkoutId: string
}
}) {
return
Thank you! Your checkout is now being processed.
@@ -257,41 +243,17 @@ POLAR_WEBHOOK_SECRET="..."
### Setting up the Webhook handler
-#### Verifying the signature
-
-It's important to verify that the requests are truly coming from Polar. Our SDK comes with a builtin utility function that validates and parses the webhook payload:
-
```typescript
// src/app/api/webhook/polar/route.ts
-import { validateEvent, WebhookVerificationError } from '@polar-sh/sdk/webhooks'
-
-export async function POST(request: NextRequest) {
- const requestBody = await request.text()
- const webhookHeaders = {
- 'webhook-id': request.headers.get('webhook-id') ?? '',
- 'webhook-timestamp': request.headers.get('webhook-timestamp') ?? '',
- 'webhook-signature': request.headers.get('webhook-signature') ?? '',
- }
-
- let webhookPayload: ReturnType
- try {
- webhookPayload = validateEvent(
- requestBody,
- webhookHeaders,
- env.POLAR_WEBHOOK_SECRET,
- )
- } catch (error) {
- if (error instanceof WebhookVerificationError) {
- return new NextResponse('', { status: 403 })
- }
- throw error
- }
+import { Webhooks } from "@polar-sh/nextjs";
- // webhookPayload is now verified and holds the event data
-}
+export const POST = Webhooks({
+ webhookSecret: process.env.POLAR_WEBHOOK_SECRET,
+ onPayload: async (payload) => // Handle payload...
+});
```
-The webhook event is now verified and you can proceed to handle the event data.
+The webhook event is now verified and you can proceed to handle the payload data.
#### Handling Webhook Events
@@ -299,41 +261,42 @@ Depending on which events you've subscribed to, you'll receive different payload
```typescript
// src/app/api/webhook/polar/route.ts
-export async function POST(request: NextRequest) {
- // ...
-
- switch (webhookPayload.type) {
- case 'checkout.created':
- // Handle the checkout created event
- // supabase.from('checkouts').insert(webhookPayload.data)
- break
- case 'checkout.updated':
- // Handle the checkout updated event
- // supabase.from('checkouts').update(webhookPayload.data).match({ id: webhookPayload.data.id })
- break
- case 'subscription.created':
- // Handle the subscription created event
- break
- case 'subscription.updated':
- // Handle the subscription updated event
- break
- case 'subscription.active':
- // Handle the subscription active event
- break
- case 'subscription.revoked':
- // Handle the subscription revoked event
- break
- case 'subscription.canceled':
- // Handle the subscription canceled event
- break
- default:
- // Handle unknown event
- console.log('Unknown event', webhookPayload.type)
- break
+import { Webhooks } from "@polar-sh/nextjs";
+
+export const POST = Webhooks({
+ webhookSecret: process.env.POLAR_WEBHOOK_SECRET,
+ onPayload: async (payload) => {
+ switch (payload.type) {
+ case 'checkout.created':
+ // Handle the checkout created event
+ // supabase.from('checkouts').insert(webhookPayload.data)
+ break
+ case 'checkout.updated':
+ // Handle the checkout updated event
+ // supabase.from('checkouts').update(webhookPayload.data).match({ id: webhookPayload.data.id })
+ break
+ case 'subscription.created':
+ // Handle the subscription created event
+ break
+ case 'subscription.updated':
+ // Handle the subscription updated event
+ break
+ case 'subscription.active':
+ // Handle the subscription active event
+ break
+ case 'subscription.revoked':
+ // Handle the subscription revoked event
+ break
+ case 'subscription.canceled':
+ // Handle the subscription canceled event
+ break
+ default:
+ // Handle unknown event
+ console.log('Unknown event', webhookPayload.type)
+ break
+ }
}
-
- return NextResponse.json({ received: true })
-}
+});
```
If you're keeping track of active and inactive subscriptions in your database, make sure to handle the `subscription.active` and `subscription.revoked` events accordingly.