> ## Documentation Index
> Fetch the complete documentation index at: https://docs.anotherwrapper.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Stripe

> Step-by-step guide to setting up Stripe checkout links and webhooks

Stripe is a great default if you want the most familiar developer payment workflow with full control over products, prices, and metadata. Let's get you set up.

## What you're setting up

Four things, that's it:

1. A product or payment link in Stripe
2. A checkout URL saved in your env vars
3. A webhook endpoint in Stripe
4. A way for the repo to understand what was purchased

## Env vars

<CodeGroup>
  ```env Required theme={null}
  NEXT_PUBLIC_PAYMENT_PROVIDER=stripe
  NEXT_PUBLIC_CHECKOUT_URL_TEMPLATE=https://...
  STRIPE_SECRET_KEY=...
  STRIPE_WEBHOOK_SECRET=...
  ```

  ```env Optional checkout URLs theme={null}
  NEXT_PUBLIC_CHECKOUT_URL_PLAN_SMALL=https://...
  NEXT_PUBLIC_CHECKOUT_URL_PLAN_MEDIUM=https://...
  NEXT_PUBLIC_CHECKOUT_URL_PLAN_LARGE=https://...
  NEXT_PUBLIC_CHECKOUT_URL_CREDITS_SMALL=https://...
  NEXT_PUBLIC_CHECKOUT_URL_CREDITS_LARGE=https://...
  ```

  ```env Optional product map theme={null}
  STRIPE_PRODUCT_MAP='{"prod_123":"plan-medium"}'
  ```
</CodeGroup>

## Setup

<Steps>
  <Step title="Create your Stripe products">
    Head to your [Stripe Dashboard](https://dashboard.stripe.com/) and open **Product catalog**.

    1. Create a product for each thing you want to sell
    2. Add a price for each product
    3. Create a payment link or checkout flow

    For your first setup, keep it simple -- just create:

    * One **Medium plan** product
    * One **Small credits** product
  </Step>

  <Step title="Decide how Stripe describes the purchase">
    You have two options here. Pick whichever feels more natural to you.

    <Tabs>
      <Tab title="Option A: Metadata (recommended)">
        Add a `type` field to your product or checkout session metadata. This is the easiest to reason about because the purchase explains itself.

        Examples:

        * `type=plan-medium`
        * `type=credits-small`

        The repo will look for:

        1. `session.metadata.type` first
        2. `product.metadata.type` as fallback
      </Tab>

      <Tab title="Option B: Product map in env">
        Keep the mapping in your env vars instead:

        ```env theme={null}
        STRIPE_PRODUCT_MAP='{"prod_123":"plan-medium","prod_456":"credits-small"}'
        ```

        This is handy if you don't want to rely on Stripe metadata.
      </Tab>
    </Tabs>
  </Step>

  <Step title="Add your checkout URLs">
    Paste the Stripe payment link into the matching env var in `.env.local`:

    ```env theme={null}
    NEXT_PUBLIC_CHECKOUT_URL_PLAN_MEDIUM=https://buy.stripe.com/...
    NEXT_PUBLIC_CHECKOUT_URL_CREDITS_SMALL=https://buy.stripe.com/...
    ```

    These are the URLs your app buttons will send users to.
  </Step>

  <Step title="Add the webhook in Stripe">
    Back in Stripe:

    1. Go to **Developers -> Webhooks**
    2. Click **Add endpoint**
    3. Set the URL to:

    ```text theme={null}
    https://yourdomain.com/api/payments/stripe
    ```

    4. Enable at least these events:
       * `checkout.session.completed`
       * `checkout.session.async_payment_succeeded`
    5. Copy the **signing secret** into your env:

    ```env theme={null}
    STRIPE_WEBHOOK_SECRET=whsec_...
    ```
  </Step>

  <Step title="Add your secret key">
    Grab your Stripe secret key and add it too:

    ```env theme={null}
    STRIPE_SECRET_KEY=sk_...
    ```

    The repo needs this to verify the webhook and inspect the checkout session.
  </Step>
</Steps>

## How it works under the hood

Once Stripe sends a successful webhook, here's what happens:

1. The repo verifies the signature
2. It loads the checkout session
3. It resolves the purchase type from metadata or `STRIPE_PRODUCT_MAP`
4. It stores the purchase in the database
5. It updates the user's credits or plan state

## Verify your setup

<Check>
  **Your Stripe setup is working if all of these are true:**

  * The app opens the Stripe checkout page when you click a payment button
  * Stripe shows a successful webhook delivery in the dashboard
  * A row appears in your `purchases` table
  * A credits purchase increases the user's credits
  * A plan purchase updates the user's purchase state
</Check>

<AccordionGroup>
  <Accordion title="Using the publishable key instead of the secret key">
    `STRIPE_SECRET_KEY` needs your **secret** key (starts with `sk_`), not the publishable one (starts with `pk_`). The publishable key is for client-side Stripe.js only.
  </Accordion>

  <Accordion title="Checkout works but nothing happens after payment">
    You probably added the checkout URL but forgot the webhook. Without a webhook, Stripe can't tell your app the payment succeeded.
  </Accordion>

  <Accordion title="Webhook receives events but purchase type is unknown">
    You haven't set metadata on your product/session **and** you haven't set `STRIPE_PRODUCT_MAP`. The repo needs at least one of these to know what was purchased.
  </Accordion>

  <Accordion title="Webhook URL returns errors in production">
    Make sure you're using the correct production domain in the webhook URL, not `localhost`.
  </Accordion>
</AccordionGroup>

<Card title="Payments Overview" icon="money-bill" href="/payments">
  Go back to the shared payment architecture and basics.
</Card>
