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.