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

# Fulfill Orders

> Learn how to fulfill orders after a customer pays via checkout or payment links.

After you integrate with Flex Checkout or create a Payment Link to take your customers to a
payment form, you need a notification to fulfill their order after a successful payment.

In this guide, you'll learn how to use webhooks to fulfill orders after a payment.

## Fulfillment guide

<Steps titleSize="h3">
  <Step title="Select webhook events">
    Choose the webhook events that are relevant to your checkout session.

    * **customer.created** — When a customer record is created in Flex.
    * **payment\_intent.created** — As soon as the customer begins entering payment info.
    * **payment\_intent.succeeded** — After a successful payment (fires twice on split carts).
    * **customer.subscription.created** — For subscription sessions, when a subscription is first created. Includes the subscription's initial `status` (e.g., `trialing`, `active`, or `incomplete`).
    * **customer.subscription.updated** — Sent when an *existing* subscription changes (plan changes, payment failure, cancellation, etc.). **Not sent at subscription creation**, and not reliably sent on `trialing` → `active` transitions. Don't depend on this event for detecting new subscriptions.
    * **invoice.payment\_succeeded** — Sent when a subscription invoice is paid. The most reliable signal that a customer has paid — recommended for provisioning or extending membership / entitlements.
    * **checkout\_session.completed** — Sent after a checkout session has fully completed.

    <Info>
      **Recommended pattern for subscription fulfillment**

      To avoid missing new subscriptions, follow this pattern:

      * **Provision** membership / access on `customer.subscription.created`, gated on `status in (trialing, active)`.
      * **Confirm or extend** entitlement on `invoice.payment_succeeded` (covers initial payment and renewals).
      * **Sync state** (status changes, plan changes, payment failures) on `customer.subscription.updated`.
      * **Revoke** access on `customer.subscription.deleted`.

      Listening only on `customer.subscription.updated` will cause you to silently miss new subscriptions, since Stripe does not fire `.updated` at sub creation.
    </Info>
  </Step>

  <Step title="Create an event handler">
    Set up an HTTP endpoint to receive and log incoming events. For local testing, use ngrok or [webhook.site](https://webhook.site).

    ```js theme={null}
    // Using Express
    const app = require("express")();
    const bodyParser = require("body-parser");

    app.post(
      "/webhook",
      bodyParser.raw({ type: "application/json" }),
      (req, res) => {
        console.log("Got payload:", req.body);
        res.status(200).end();
      }
    );

    app.listen(4242, () => console.log("Running on port 4242"));
    ```
  </Step>

  <Step title="Create a webhook endpoint">
    Register your handler's public URL in Flex. Here we listen for `checkout.session.completed`:

    ```bash theme={null}
    curl --request POST \
      --url https://api.withflex.com/v1/webhooks \
      --header 'authorization: Bearer fsk_test_…' \
      --header 'content-type: application/json' \
      --data '{
        "webhook": {
          "url": "https://withflex.com/handle_events",
          "events": ["checkout.session.completed"]
        }
      }'
    ```
  </Step>

  <Step title="Create a checkout session">
    Trigger a session to confirm your handler receives events:

    ```bash theme={null}
    curl --request POST \
      --url https://api.withflex.com/v1/checkout/sessions \
      --header 'authorization: Bearer fsk_test_…' \
      --header 'content-type: application/json' \
      --data '{
        "checkout_session": {
          "line_items": [{"price": "fprice_…","quantity": 1}],
          "success_url": "https://withflex.com/thank-you?success=true",
          "cancel_url": "https://withflex.com/thank-you?canceled=true",
          "mode": "payment"
        }
      }'
    ```

    Then go through checkout:

    1. Enter contact info
    2. Fill any intake form
    3. Use card number `4242 4242 4242 4242`, future expiry, any CVV, and postal code 90210
    4. Click **Pay**

    You should see an event payload like:

    ```json theme={null}
    {
      "event_type": "checkout.session.completed",
      "object": {
        "checkout_session": {
          "status": "complete",
          "redirect_url": "https://checkout.withflex.com/pay/…",
          …
        }
      }
    }
    ```
  </Step>

  <Step title="Verify events came from Flex">
    Confirm the signature on incoming requests before processing. See [Verifying webhooks](/developer-guides/webhooks/verifying-webhooks).
  </Step>

  <Step title="Fulfill order">
    Handle `checkout.session.completed` to:

    * Save the order to your database
    * Send a receipt email
    * Update inventory via the Line Items API:

    ```bash theme={null}
    curl --request GET \
      --url https://api.withflex.com/v1/checkout/sessions/fcs_…/line_items \
      --header 'authorization: Bearer fsk_test_…'
    ```
  </Step>

  <Step title="Go live in production">
    Once deployed, register your production [webhook](/developer-guides/webhooks/overview) URL in Flex.
  </Step>
</Steps>
