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

# REST API endpoint reference

> Every operation in the Pocketsflow public REST API contract, generated from the OpenAPI spec.

This catalog lists every operation in the public OpenAPI contract: **51 paths and 72 operations**. Every endpoint requires authentication unless noted otherwise. A few SDK helpers (for example `users.update` and `variants`) call routes that are not in the public contract yet; see the [SDK reference](/api-reference/sdk-reference).

<Card title="Interactive API explorer" icon="server" href="https://api.pocketsflow.com/docs">
  Try requests, inspect schemas, and copy generated examples in Scalar.
</Card>

The machine-readable contract is available at [`/docs.json`](https://api.pocketsflow.com/docs.json). This page is generated from the same public contract so the catalog does not drift from the deployed API.

## Conventions

* Base URL: `https://api.pocketsflow.com`
* Authentication: `Authorization: Bearer pk_live_...` or `Authorization: Bearer pk_test_...`
* JSON requests use `Content-Type: application/json`; image uploads use `multipart/form-data`.
* IDs are usually MongoDB ObjectId strings. Processor IDs such as `sub_...`, `plan_...`, `pay_...`, and `mem_...` retain their provider prefixes.

```bash theme={null}
curl https://api.pocketsflow.com/users/me \
  -H "Authorization: Bearer pk_live_xxxxxxxxxxxxxxxxxxxxxxxx"
```

<Warning>
  Keep API keys server-side. Never put a secret key in browser code, a mobile
  app, a public repository, or a URL.
</Warning>

## Account

| Method | Endpoint    | Description                  |
| ------ | ----------- | ---------------------------- |
| `GET`  | `/users/me` | Get current user information |

<AccordionGroup>
  <Accordion title="GET /users/me">
    Retrieve information about the authenticated user, including account details, subdomain, test mode status, and whether the account has sales. Use this to get the user's subdomain for constructing product URLs.

    **Responses**

    | Status | Description                             |
    | ------ | --------------------------------------- |
    | `200`  | User information retrieved successfully |
    | `401`  | Unauthorized - Invalid API key          |
    | `404`  | User not found                          |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>
</AccordionGroup>

## Checkout

| Method | Endpoint             | Description             |
| ------ | -------------------- | ----------------------- |
| `POST` | `/checkout/sessions` | Create checkout session |

<AccordionGroup>
  <Accordion title="POST /checkout/sessions">
    Create a checkout session for a one-time product OR a subscription (recurring) offer — pass either kind of id as `productId`. Returns a URL to redirect customers to complete their purchase. Payment methods (card, Apple Pay, Google Pay, Link, ACH, and country-specific methods such as iDEAL) are taken from the seller's account — there is no payment-method parameter on this endpoint.

    **Request body**

    Content type: `application/json`
    Required fields: `productId`, `successUrl`, `cancelUrl`.

    | Field               | Type           | Required | Description                                                                                                                                                                          |
    | ------------------- | -------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
    | `productId`         | string         | Yes      | Id of the product OR subscription offer to purchase.                                                                                                                                 |
    | `successUrl`        | string (uri)   | Yes      | Redirect URL after successful payment                                                                                                                                                |
    | `cancelUrl`         | string (uri)   | Yes      | Redirect URL if payment is canceled                                                                                                                                                  |
    | `customerEmail`     | string (email) | No       | Customer email. Prefills the email on the checkout page (and inside the payment form) and is attached to the resulting order and webhook payload.                                    |
    | `lockEmail`         | boolean        | No       | With customerEmail, makes the prefilled email read-only so the buyer can't change it.                                                                                                |
    | `clientReferenceId` | string         | No       | Your own correlation id. Echoed back top-level as `clientReferenceId` on the resulting webhooks, including every subscription lifecycle event.                                       |
    | `discountCode`      | string         | No       | Discount code to apply                                                                                                                                                               |
    | `metadata`          | object         | No       | Custom metadata for the checkout, echoed back on webhook payloads. For subscriptions it is captured at activation and replayed on every customer.subscription.\* / invoice.\* event. |

    **Responses**

    | Status | Description              |
    | ------ | ------------------------ |
    | `201`  | Checkout session created |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>
</AccordionGroup>

## Customers

| Method | Endpoint          | Description        |
| ------ | ----------------- | ------------------ |
| `GET`  | `/customers`      | List all customers |
| `GET`  | `/customers/{id}` | Get customer by ID |

<AccordionGroup>
  <Accordion title="GET /customers">
    Retrieve a list of all your customers (deduplicated by email, each with a computed `numberOfOrders`). Optionally filter by product and sort. The full list is returned — this endpoint is not paginated.

    **Parameters**

    | Name        | Location | Required | Type                                                                     | Description                    |
    | ----------- | -------- | -------- | ------------------------------------------------------------------------ | ------------------------------ |
    | `productId` | `query`  | No       | string                                                                   | Filter customers by product ID |
    | `sortBy`    | `query`  | No       | string — email, country, numberOfOrders, createdAt; default: `createdAt` | Field to sort by               |
    | `sortOrder` | `query`  | No       | string — asc, desc; default: `desc`                                      | Sort direction                 |

    **Responses**

    | Status | Description       |
    | ------ | ----------------- |
    | `200`  | List of customers |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>

  <Accordion title="GET /customers/{id}">
    Retrieve a specific customer by their ID

    **Parameters**

    | Name | Location | Required | Type   | Description |
    | ---- | -------- | -------- | ------ | ----------- |
    | `id` | `path`   | Yes      | string | Customer ID |

    **Responses**

    | Status | Description        |
    | ------ | ------------------ |
    | `200`  | Customer details   |
    | `404`  | Customer not found |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>
</AccordionGroup>

## Discounts

| Method   | Endpoint                                      | Description                        |
| -------- | --------------------------------------------- | ---------------------------------- |
| `GET`    | `/discounts`                                  | List all discounts                 |
| `POST`   | `/discounts`                                  | Create a discount                  |
| `GET`    | `/discounts/{id}`                             | Get discount by ID                 |
| `POST`   | `/discounts/{id}`                             | Update discount                    |
| `DELETE` | `/discounts/{id}`                             | Delete discount                    |
| `GET`    | `/discounts/apply/{discountCode}/{productId}` | Validate and apply a discount code |
| `GET`    | `/discounts/check-product/{productId}`        | Check if a product has discounts   |

<AccordionGroup>
  <Accordion title="GET /discounts">
    Retrieve a list of all your discount codes

    **Responses**

    | Status | Description       |
    | ------ | ----------------- |
    | `200`  | List of discounts |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>

  <Accordion title="POST /discounts">
    Create a new discount code

    **Request body**

    Content type: `application/json`
    Required fields: `name`, `code`, `value`, `mainProductIds`.

    | Field            | Type                                              | Required | Description                                      |
    | ---------------- | ------------------------------------------------- | -------- | ------------------------------------------------ |
    | `name`           | string                                            | Yes      | Discount name                                    |
    | `code`           | string                                            | Yes      | Discount code - what customers enter at checkout |
    | `value`          | number                                            | Yes      | Discount value                                   |
    | `valueType`      | string — percentage, fixed; default: `percentage` | No       | Discount type (defaults to percentage)           |
    | `mainProductIds` | array of string                                   | Yes      | Product IDs this discount applies to (required)  |
    | `active`         | boolean; default: `true`                          | No       | Whether discount is active                       |

    **Responses**

    | Status | Description                   |
    | ------ | ----------------------------- |
    | `200`  | Discount created successfully |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>

  <Accordion title="GET /discounts/{id}">
    Retrieve a specific discount by its ID

    **Parameters**

    | Name | Location | Required | Type   | Description |
    | ---- | -------- | -------- | ------ | ----------- |
    | `id` | `path`   | Yes      | string | Discount ID |

    **Responses**

    | Status | Description        |
    | ------ | ------------------ |
    | `200`  | Discount details   |
    | `404`  | Discount not found |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>

  <Accordion title="POST /discounts/{id}">
    Update an existing discount. This is a full update — all listed fields are written to the discount, so send every field you want to keep.

    **Parameters**

    | Name | Location | Required | Type   | Description |
    | ---- | -------- | -------- | ------ | ----------- |
    | `id` | `path`   | Yes      | string | Discount ID |

    **Request body**

    Content type: `application/json`

    | Field            | Type                       | Required | Description                          |
    | ---------------- | -------------------------- | -------- | ------------------------------------ |
    | `name`           | string                     | No       |                                      |
    | `code`           | string                     | No       |                                      |
    | `value`          | number                     | No       |                                      |
    | `valueType`      | string — percentage, fixed | No       |                                      |
    | `active`         | boolean                    | No       |                                      |
    | `mainProductIds` | array of string            | No       | Product IDs this discount applies to |

    **Responses**

    | Status | Description                   |
    | ------ | ----------------------------- |
    | `200`  | Discount updated successfully |
    | `404`  | Discount not found            |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>

  <Accordion title="DELETE /discounts/{id}">
    Delete a discount code

    **Parameters**

    | Name | Location | Required | Type   | Description |
    | ---- | -------- | -------- | ------ | ----------- |
    | `id` | `path`   | Yes      | string | Discount ID |

    **Responses**

    | Status | Description                   |
    | ------ | ----------------------------- |
    | `200`  | Discount deleted successfully |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>

  <Accordion title="GET /discounts/apply/{discountCode}/{productId}">
    PUBLIC (no API key) — used by the checkout. Validates a discount code against a product and returns the discount if it exists, is active, has not expired, and applies to the product. Returns 404 otherwise.

    **Parameters**

    | Name           | Location | Required | Type   | Description                             |
    | -------------- | -------- | -------- | ------ | --------------------------------------- |
    | `discountCode` | `path`   | Yes      | string | The discount code the customer entered  |
    | `productId`    | `path`   | Yes      | string | Product ID to validate the code against |

    **Responses**

    | Status | Description                                                              |
    | ------ | ------------------------------------------------------------------------ |
    | `200`  | The discount is valid — the discount object is returned                  |
    | `404`  | Discount not found, inactive, expired, or not applicable to this product |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>

  <Accordion title="GET /discounts/check-product/{productId}">
    PUBLIC (no API key) — used by the checkout. Returns `true` if any discount applies to the given product, `false` otherwise.

    **Parameters**

    | Name        | Location | Required | Type   | Description         |
    | ----------- | -------- | -------- | ------ | ------------------- |
    | `productId` | `path`   | Yes      | string | Product ID to check |

    **Responses**

    | Status | Description                                         |
    | ------ | --------------------------------------------------- |
    | `200`  | Boolean — whether any discount targets this product |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>
</AccordionGroup>

## Images

| Method   | Endpoint       | Description     |
| -------- | -------------- | --------------- |
| `GET`    | `/images`      | List all images |
| `POST`   | `/images`      | Upload image    |
| `DELETE` | `/images/{id}` | Delete image    |

<AccordionGroup>
  <Accordion title="GET /images">
    Retrieve a list of all your uploaded images

    **Responses**

    | Status | Description    |
    | ------ | -------------- |
    | `200`  | List of images |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>

  <Accordion title="POST /images">
    Upload an image file as multipart/form-data. The file field must be named `image`. Other field names return 400. Requires authentication.

    **Request body**

    Content type: `multipart/form-data`
    Required fields: `image`.

    | Field   | Type            | Required | Description          |
    | ------- | --------------- | -------- | -------------------- |
    | `image` | string (binary) | Yes      | Image file to upload |

    **Responses**

    | Status | Description                                                 |
    | ------ | ----------------------------------------------------------- |
    | `200`  | Image uploaded successfully                                 |
    | `400`  | Unexpected multipart field name or invalid multipart upload |
    | `401`  | Missing or invalid authentication                           |
    | `413`  | File exceeds the authenticated plan's upload limit          |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>

  <Accordion title="DELETE /images/{id}">
    Delete an uploaded image

    **Parameters**

    | Name | Location | Required | Type   | Description |
    | ---- | -------- | -------- | ------ | ----------- |
    | `id` | `path`   | Yes      | string | Image ID    |

    **Responses**

    | Status | Description                |
    | ------ | -------------------------- |
    | `200`  | Image deleted successfully |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>
</AccordionGroup>

## Link in Bio

| Method   | Endpoint                    | Description                  |
| -------- | --------------------------- | ---------------------------- |
| `GET`    | `/creator-pages`            | Get your Link in Bio page    |
| `POST`   | `/creator-pages`            | Update Link in Bio page      |
| `POST`   | `/creator-pages/links`      | Add link to Link in Bio page |
| `PUT`    | `/creator-pages/links/{id}` | Update link                  |
| `DELETE` | `/creator-pages/links/{id}` | Delete link                  |

<AccordionGroup>
  <Accordion title="GET /creator-pages">
    Retrieve your Link in Bio page configuration and content

    **Responses**

    | Status | Description              |
    | ------ | ------------------------ |
    | `200`  | Link in Bio page details |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>

  <Accordion title="POST /creator-pages">
    Update your Link in Bio page settings and content

    **Request body**

    Content type: `application/json`

    | Field          | Type            | Required | Description              |
    | -------------- | --------------- | -------- | ------------------------ |
    | `title`        | string          | No       | Page title               |
    | `bio`          | string          | No       | Bio text                 |
    | `profileImage` | string          | No       | Profile image URL        |
    | `theme`        | string          | No       | Theme color              |
    | `links`        | array of object | No       | List of links to display |

    **Responses**

    | Status | Description                           |
    | ------ | ------------------------------------- |
    | `200`  | Link in Bio page updated successfully |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>

  <Accordion title="POST /creator-pages/links">
    Add a new link to your Link in Bio page

    **Request body**

    Content type: `application/json`
    Required fields: `title`, `url`.

    | Field   | Type         | Required | Description   |
    | ------- | ------------ | -------- | ------------- |
    | `title` | string       | Yes      | Link title    |
    | `url`   | string (uri) | Yes      | Link URL      |
    | `order` | number       | No       | Display order |

    **Responses**

    | Status | Description             |
    | ------ | ----------------------- |
    | `201`  | Link added successfully |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>

  <Accordion title="PUT /creator-pages/links/{id}">
    Update a link on your Link in Bio page

    **Parameters**

    | Name | Location | Required | Type   | Description |
    | ---- | -------- | -------- | ------ | ----------- |
    | `id` | `path`   | Yes      | string | Link ID     |

    **Request body**

    Content type: `application/json`

    | Field   | Type         | Required | Description |
    | ------- | ------------ | -------- | ----------- |
    | `title` | string       | No       |             |
    | `url`   | string (uri) | No       |             |
    | `order` | number       | No       |             |

    **Responses**

    | Status | Description               |
    | ------ | ------------------------- |
    | `200`  | Link updated successfully |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>

  <Accordion title="DELETE /creator-pages/links/{id}">
    Remove a link from your Link in Bio page

    **Parameters**

    | Name | Location | Required | Type   | Description |
    | ---- | -------- | -------- | ------ | ----------- |
    | `id` | `path`   | Yes      | string | Link ID     |

    **Responses**

    | Status | Description               |
    | ------ | ------------------------- |
    | `200`  | Link deleted successfully |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>
</AccordionGroup>

## Orders

| Method | Endpoint       | Description     |
| ------ | -------------- | --------------- |
| `GET`  | `/orders`      | List all orders |
| `GET`  | `/orders/{id}` | Get order by ID |

<AccordionGroup>
  <Accordion title="GET /orders">
    Retrieve a list of your one-time product orders, with pagination and filters. Subscription (recurring) transactions are NOT included here — list every payment (one-time and recurring) with `GET /payments`, and list active subscribers with `GET /subscriptions/subscribers`.

    **Parameters**

    | Name        | Location | Required | Type                   | Description                              |
    | ----------- | -------- | -------- | ---------------------- | ---------------------------------------- |
    | `startDate` | `query`  | No       | string (date)          | Filter orders from this date (ISO 8601)  |
    | `endDate`   | `query`  | No       | string (date)          | Filter orders until this date (ISO 8601) |
    | `productId` | `query`  | No       | string                 | Filter orders by product ID              |
    | `page`      | `query`  | No       | integer; default: `1`  | Page number for pagination               |
    | `pageSize`  | `query`  | No       | integer; default: `20` | Number of orders per page                |

    **Responses**

    | Status | Description                         |
    | ------ | ----------------------------------- |
    | `200`  | List of orders with pagination info |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>

  <Accordion title="GET /orders/{id}">
    Retrieve a specific order by its sale/transaction id (the `_id` of an order returned by GET /orders) — NOT a product id. For a subscription membership and its full payment history, use `GET /orders/subscriptions/{id}` with the SubscriptionCustomer id.

    **Parameters**

    | Name | Location | Required | Type   | Description |
    | ---- | -------- | -------- | ------ | ----------- |
    | `id` | `path`   | Yes      | string | Order ID    |

    **Responses**

    | Status | Description     |
    | ------ | --------------- |
    | `200`  | Order details   |
    | `404`  | Order not found |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>
</AccordionGroup>

## Partners

| Method | Endpoint                      | Description                   |
| ------ | ----------------------------- | ----------------------------- |
| `GET`  | `/partners`                   | Get my partner profile        |
| `POST` | `/partners`                   | Become a partner              |
| `POST` | `/partners/register-referral` | Register a referral signup    |
| `GET`  | `/partners/referrals`         | Get referred users            |
| `GET`  | `/partners/referrals/sales`   | Get sales from referred users |
| `GET`  | `/partners/stats`             | Get partner stats             |

<AccordionGroup>
  <Accordion title="GET /partners">
    Retrieve your partner profile including referral code and denormalized stats.

    **Responses**

    | Status | Description     |
    | ------ | --------------- |
    | `200`  | Partner profile |
    | `404`  | Not a partner   |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>

  <Accordion title="POST /partners">
    Register as a Pocketsflow partner. You'll receive a unique referral code to share. When users sign up using your code, you earn commissions on their sales.

    **Responses**

    | Status | Description                  |
    | ------ | ---------------------------- |
    | `201`  | Partner created successfully |
    | `409`  | Already a partner            |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>

  <Accordion title="POST /partners/register-referral">
    Call this after a user signs up through a partner's referral link. Sets the referral code on the authenticated user and increments the partner's signup count.

    **Request body**

    Content type: `application/json`
    Required fields: `referralCode`.

    | Field          | Type   | Required | Description                                      |
    | -------------- | ------ | -------- | ------------------------------------------------ |
    | `referralCode` | string | Yes      | The partner's referral code from the signup link |

    **Responses**

    | Status | Description                                                         |
    | ------ | ------------------------------------------------------------------- |
    | `200`  | Referral registered successfully                                    |
    | `400`  | Missing referralCode, user already has a referral, or self-referral |
    | `404`  | Invalid or inactive referral code                                   |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>

  <Accordion title="GET /partners/referrals">
    List all users who signed up using your referral code. Each user includes their sales count and total revenue.

    **Parameters**

    | Name    | Location | Required | Type                   | Description |
    | ------- | -------- | -------- | ---------------------- | ----------- |
    | `page`  | `query`  | No       | integer; default: `1`  |             |
    | `limit` | `query`  | No       | integer; default: `20` |             |

    **Responses**

    | Status | Description                                       |
    | ------ | ------------------------------------------------- |
    | `200`  | Paginated list of referred users with sales stats |
    | `404`  | Not a partner                                     |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>

  <Accordion title="GET /partners/referrals/sales">
    Get all sales generated by users who signed up through your referral code.

    **Parameters**

    | Name    | Location | Required | Type                   | Description |
    | ------- | -------- | -------- | ---------------------- | ----------- |
    | `page`  | `query`  | No       | integer; default: `1`  |             |
    | `limit` | `query`  | No       | integer; default: `20` |             |

    **Responses**

    | Status | Description                                 |
    | ------ | ------------------------------------------- |
    | `200`  | Paginated list of sales from referred users |
    | `404`  | Not a partner                               |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>

  <Accordion title="GET /partners/stats">
    Get live-computed aggregated stats: total signups, total sales, total revenue, and total commission earned based on your commission rate.

    **Responses**

    | Status | Description              |
    | ------ | ------------------------ |
    | `200`  | Aggregated partner stats |
    | `404`  | Not a partner            |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>
</AccordionGroup>

## Payments

| Method | Endpoint         | Description                    |
| ------ | ---------------- | ------------------------------ |
| `GET`  | `/payments`      | List payments (unified ledger) |
| `GET`  | `/payments/{id}` | Get a payment by ID            |

<AccordionGroup>
  <Accordion title="GET /payments">
    Retrieve a paginated ledger of ALL payments — one-time product purchases AND subscription payments (the initial charge plus every renewal). Filter by `type` to narrow to one\_time or subscription. Every payment is a `Sale`. Scoped to the authenticated seller and their test/live mode.

    **Parameters**

    | Name             | Location | Required | Type                                                  | Description                                                                                             |
    | ---------------- | -------- | -------- | ----------------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
    | `type`           | `query`  | No       | string — one\_time, subscription, all; default: `all` | Payment type: `one_time` (product purchases), `subscription` (subscription charges), or `all` (default) |
    | `startDate`      | `query`  | No       | string (date)                                         | Filter payments from this date (ISO 8601)                                                               |
    | `endDate`        | `query`  | No       | string (date)                                         | Filter payments until this date (ISO 8601)                                                              |
    | `productId`      | `query`  | No       | string                                                | Filter payments by product id                                                                           |
    | `subscriptionId` | `query`  | No       | string                                                | Filter payments by subscription offer id                                                                |
    | `page`           | `query`  | No       | integer; default: `1`                                 | Page number for pagination                                                                              |
    | `pageSize`       | `query`  | No       | integer; default: `20`                                | Number of payments per page                                                                             |

    **Responses**

    | Status | Description                |
    | ------ | -------------------------- |
    | `200`  | Paginated list of payments |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>

  <Accordion title="GET /payments/{id}">
    Retrieve a single payment (a `Sale`) scoped to the authenticated seller. Resolves the related product OR subscription offer (subscription payments carry an empty productId), the customer, and a `whop` block sourced from the stored payments partner payload. Pass `?live=true` to additionally fetch the authoritative live payment from the payments partner API as `whopLive` (degrades gracefully on any error — never fails the request).

    **Parameters**

    | Name   | Location | Required | Type                      | Description                                                                                            |
    | ------ | -------- | -------- | ------------------------- | ------------------------------------------------------------------------------------------------------ |
    | `id`   | `path`   | Yes      | string                    | Payment id (the Sale \_id)                                                                             |
    | `live` | `query`  | No       | boolean; default: `false` | When true, fetch the authoritative live payment from the payments partner and include it as `whopLive` |

    **Responses**

    | Status | Description       |
    | ------ | ----------------- |
    | `200`  | Payment details   |
    | `404`  | Payment not found |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>
</AccordionGroup>

## Portal

| Method | Endpoint                                                                   | Description                                      |
| ------ | -------------------------------------------------------------------------- | ------------------------------------------------ |
| `GET`  | `/subscriptions/sub/portal-data/{subscriptionId}/{subscriptionCustomerId}` | Get native subscriber portal data                |
| `POST` | `/subscriptions/sub/portal/{subscriptionCustomerId}/cancel`                | Cancel a subscriber's membership (native portal) |
| `POST` | `/subscriptions/sub/portal/{subscriptionCustomerId}/resume`                | Resume a pending cancellation (native portal)    |

<AccordionGroup>
  <Accordion title="GET /subscriptions/sub/portal-data/{subscriptionId}/{subscriptionCustomerId}">
    PUBLIC (no API key). Returns everything the native, subscriber portal renders: the subscription offer, the subscriber (with `status`, `cancelAtPeriodEnd`, and the payments partner `manageUrl` fallback), and the full payment history (initial charge + every renewal, newest first). The `subscriptionId` + `subscriptionCustomerId` pair is the capability — if the subscriber does not belong to that subscription the endpoint 404s (it never reveals whether either id exists on its own). Data is scoped to the subscriber's own seller/test-mode, read off the record.

    **Parameters**

    | Name                     | Location | Required | Type   | Description                                                     |
    | ------------------------ | -------- | -------- | ------ | --------------------------------------------------------------- |
    | `subscriptionId`         | `path`   | Yes      | string | The subscription offer \_id from the portal link                |
    | `subscriptionCustomerId` | `path`   | Yes      | string | The subscriber (SubscriptionCustomer) \_id from the portal link |

    **Responses**

    | Status | Description                     |
    | ------ | ------------------------------- |
    | `200`  | Portal data                     |
    | `404`  | Subscription customer not found |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>

  <Accordion title="POST /subscriptions/sub/portal/{subscriptionCustomerId}/cancel">
    PUBLIC (no API key). Cancels the subscriber's payments partner membership at the end of the current billing period. On success (or when the payments partner reports an immediate cancellation) the subscriber record is updated — a scheduled cancel sets `cancelAtPeriodEnd=true` and leaves `status` active until the payments partner webhook flips it; an immediate cancel sets `status=canceled` + `active=false`. If the payments partner call fails it degrades gracefully: the intent is still recorded and `manageUrl` is returned so the UI can fall back to the payments partner's own page. Never fails the request on a payments partner error.

    **Parameters**

    | Name                     | Location | Required | Type   | Description                                |
    | ------------------------ | -------- | -------- | ------ | ------------------------------------------ |
    | `subscriptionCustomerId` | `path`   | Yes      | string | The subscriber (SubscriptionCustomer) \_id |

    **Responses**

    | Status | Description                     |
    | ------ | ------------------------------- |
    | `200`  | Cancellation recorded           |
    | `404`  | Subscription customer not found |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>

  <Accordion title="POST /subscriptions/sub/portal/{subscriptionCustomerId}/resume">
    PUBLIC (no API key). Reverses a pending cancel (`cancel_at_period_end` → false) on the subscriber's payments partner membership. Sets `cancelAtPeriodEnd=false` (and restores `status=active` if it had been canceled). Degrades gracefully like cancel — the flag is still cleared and `manageUrl` is returned if the payments partner call fails.

    **Parameters**

    | Name                     | Location | Required | Type   | Description                                |
    | ------------------------ | -------- | -------- | ------ | ------------------------------------------ |
    | `subscriptionCustomerId` | `path`   | Yes      | string | The subscriber (SubscriptionCustomer) \_id |

    **Responses**

    | Status | Description                     |
    | ------ | ------------------------------- |
    | `200`  | Pending cancellation reversed   |
    | `404`  | Subscription customer not found |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>
</AccordionGroup>

## Posts

| Method   | Endpoint                       | Description              |
| -------- | ------------------------------ | ------------------------ |
| `GET`    | `/newsletters/posts`           | List all posts           |
| `POST`   | `/newsletters/posts`           | Create a post            |
| `GET`    | `/newsletters/posts/{id}`      | Get post by ID           |
| `POST`   | `/newsletters/posts/{id}`      | Update post              |
| `DELETE` | `/newsletters/posts/{id}`      | Delete post              |
| `POST`   | `/newsletters/posts/{id}/send` | Send post to subscribers |
| `POST`   | `/newsletters/send`            | Send email               |

<AccordionGroup>
  <Accordion title="GET /newsletters/posts">
    Retrieve a list of all your newsletter posts

    **Parameters**

    | Name     | Location | Required | Type                      | Description            |
    | -------- | -------- | -------- | ------------------------- | ---------------------- |
    | `status` | `query`  | No       | string — draft, published | Filter posts by status |

    **Responses**

    | Status | Description   |
    | ------ | ------------- |
    | `200`  | List of posts |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>

  <Accordion title="POST /newsletters/posts">
    Create a new newsletter post

    **Request body**

    Content type: `application/json`
    Required fields: `title`, `content`.

    | Field        | Type                      | Required | Description           |
    | ------------ | ------------------------- | -------- | --------------------- |
    | `title`      | string                    | Yes      | Post title            |
    | `content`    | string                    | Yes      | Post content          |
    | `excerpt`    | string                    | No       | Post excerpt          |
    | `coverImage` | string                    | No       | Cover image URL       |
    | `tags`       | array of string           | No       | Post tags             |
    | `status`     | string — draft, published | No       | Post status           |
    | `publishAt`  | string (date-time)        | No       | Schedule publish date |

    **Responses**

    | Status | Description               |
    | ------ | ------------------------- |
    | `200`  | Post created successfully |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>

  <Accordion title="GET /newsletters/posts/{id}">
    Retrieve a specific post by its ID

    **Parameters**

    | Name | Location | Required | Type   | Description |
    | ---- | -------- | -------- | ------ | ----------- |
    | `id` | `path`   | Yes      | string | Post ID     |

    **Responses**

    | Status | Description  |
    | ------ | ------------ |
    | `200`  | Post details |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>

  <Accordion title="POST /newsletters/posts/{id}">
    Update an existing post. Posts that have already been sent cannot be edited.

    **Parameters**

    | Name | Location | Required | Type   | Description |
    | ---- | -------- | -------- | ------ | ----------- |
    | `id` | `path`   | Yes      | string | Post ID     |

    **Request body**

    Content type: `application/json`

    | Field        | Type                      | Required | Description |
    | ------------ | ------------------------- | -------- | ----------- |
    | `title`      | string                    | No       |             |
    | `content`    | string                    | No       |             |
    | `excerpt`    | string                    | No       |             |
    | `coverImage` | string                    | No       |             |
    | `tags`       | array of string           | No       |             |
    | `status`     | string — draft, published | No       |             |

    **Responses**

    | Status | Description               |
    | ------ | ------------------------- |
    | `200`  | Post updated successfully |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>

  <Accordion title="DELETE /newsletters/posts/{id}">
    Delete a newsletter post

    **Parameters**

    | Name | Location | Required | Type   | Description |
    | ---- | -------- | -------- | ------ | ----------- |
    | `id` | `path`   | Yes      | string | Post ID     |

    **Responses**

    | Status | Description               |
    | ------ | ------------------------- |
    | `200`  | Post deleted successfully |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>

  <Accordion title="POST /newsletters/posts/{id}/send">
    Send a post to all subscribers

    **Parameters**

    | Name | Location | Required | Type   | Description |
    | ---- | -------- | -------- | ------ | ----------- |
    | `id` | `path`   | Yes      | string | Post ID     |

    **Responses**

    | Status | Description                 |
    | ------ | --------------------------- |
    | `200`  | Post published successfully |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>

  <Accordion title="POST /newsletters/send">
    Send an email to up to 100 recipients programmatically. Requires a verified sender email (configure it in Newsletters → Settings). The email is sent with your standard footer, physical address, and unsubscribe link, and is recorded as a sent post (source: api).

    **Request body**

    Content type: `application/json`
    Required fields: `to`, `subject`.

    | Field      | Type                                      | Required | Description                                                                                                   |
    | ---------- | ----------------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------- |
    | `to`       | string (email) \| array of string (email) | Yes      | A recipient email address, or an array of 1-100 addresses                                                     |
    | `subject`  | string                                    | Yes      | Email subject line                                                                                            |
    | `html`     | string                                    | No       | HTML body of the email. Required unless `text` is provided.                                                   |
    | `text`     | string                                    | No       | Plain-text body. Used as the text alternative; if `html` is omitted, a simple HTML body is generated from it. |
    | `fromName` | string                                    | No       | Sender display name. Defaults to your newsletter settings' default from name.                                 |
    | `replyTo`  | string (email)                            | No       | Reply-to address. Defaults to your configured reply-to (or sender) email.                                     |
    | `preview`  | string                                    | No       | Inbox preview text                                                                                            |

    **Responses**

    | Status | Description                                                         |
    | ------ | ------------------------------------------------------------------- |
    | `200`  | Email sent                                                          |
    | `400`  | Validation error (invalid recipients, missing subject/body, ...)    |
    | `401`  | Unauthorized - Invalid API key                                      |
    | `403`  | Sender email not verified (error code EMAIL\_SENDER\_NOT\_VERIFIED) |
    | `502`  | No emails could be sent (error code EMAIL\_SEND\_FAILED)            |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>
</AccordionGroup>

## Products

| Method   | Endpoint                | Description         |
| -------- | ----------------------- | ------------------- |
| `GET`    | `/products`             | List all products   |
| `POST`   | `/products`             | Create a product    |
| `GET`    | `/products/{id}`        | Get product by ID   |
| `DELETE` | `/products/{id}`        | Delete product      |
| `POST`   | `/products/update/{id}` | Update product      |
| `POST`   | `/products/copy/{id}`   | Copy a catalog item |

<AccordionGroup>
  <Accordion title="GET /products">
    Retrieve a list of your one-time products. Subscription (recurring) offers are a separate resource — list them with `GET /subscriptions`.

    **Responses**

    | Status | Description                    |
    | ------ | ------------------------------ |
    | `200`  | List of products               |
    | `401`  | Unauthorized - Invalid API key |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>

  <Accordion title="POST /products">
    Create a new digital product

    **Request body**

    Content type: `application/json`
    Required fields: `name`, `price`.

    | Field              | Type                                | Required | Description                                                                                                                      |
    | ------------------ | ----------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------- |
    | `name`             | string                              | Yes      | Product name (required)                                                                                                          |
    | `price`            | number                              | Yes      | Product price (required)                                                                                                         |
    | `description`      | string                              | No       | Product description                                                                                                              |
    | `subtitle`         | string                              | No       | Product subtitle                                                                                                                 |
    | `published`        | boolean; default: `true`            | No       | Whether product is published                                                                                                     |
    | `slug`             | string                              | No       | Product slug for URL                                                                                                             |
    | `thumbnail`        | string                              | No       | Thumbnail image URL                                                                                                              |
    | `images`           | array of string                     | No       | Product images                                                                                                                   |
    | `payWant`          | boolean; default: `false`           | No       | Enable pay-what-you-want pricing                                                                                                 |
    | `minPrice`         | number                              | No       | Minimum price for pay-what-you-want                                                                                              |
    | `maxPrice`         | number                              | No       | Maximum price for pay-what-you-want                                                                                              |
    | `showSales`        | boolean; default: `true`            | No       | Show sales count                                                                                                                 |
    | `showReviews`      | boolean; default: `true`            | No       | Show reviews                                                                                                                     |
    | `refundPolicy`     | string                              | No       | Refund policy text                                                                                                               |
    | `hasFirstName`     | boolean; default: `false`           | No       | Collect customer first name                                                                                                      |
    | `hasLastName`      | boolean; default: `false`           | No       | Collect customer last name                                                                                                       |
    | `productType`      | string — file, url, course, credits | No       | Catalog type. Additive `credits` is prepaid balance with optional auto-refill. Absent on legacy products.                        |
    | `creditAutoRefill` | object                              | No       | Seller auto-refill setting. `topOffCents` is integer cents (two decimal places). Enabling without a positive top-off is ignored. |

    **Responses**

    | Status | Description                  |
    | ------ | ---------------------------- |
    | `201`  | Product created successfully |
    | `400`  | Invalid request parameters   |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>

  <Accordion title="GET /products/{id}">
    Retrieve a specific one-time product by its ID. A subscription (recurring) offer's id 404s here — fetch it with `GET /subscriptions/{id}` instead.

    **Parameters**

    | Name | Location | Required | Type   | Description |
    | ---- | -------- | -------- | ------ | ----------- |
    | `id` | `path`   | Yes      | string | Product ID  |

    **Responses**

    | Status | Description       |
    | ------ | ----------------- |
    | `200`  | Product details   |
    | `404`  | Product not found |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>

  <Accordion title="DELETE /products/{id}">
    Delete a one-time product. To delete a subscription (recurring) offer, use `DELETE /subscriptions/{id}`.

    **Parameters**

    | Name | Location | Required | Type   | Description |
    | ---- | -------- | -------- | ------ | ----------- |
    | `id` | `path`   | Yes      | string | Product ID  |

    **Responses**

    | Status | Description                  |
    | ------ | ---------------------------- |
    | `200`  | Product deleted successfully |
    | `404`  | Product not found            |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>

  <Accordion title="POST /products/update/{id}">
    Update an existing one-time product. Send JSON or multipart/form-data. To update a subscription (recurring) offer, use `POST /subscriptions/update/{id}`.

    **Parameters**

    | Name | Location | Required | Type   | Description |
    | ---- | -------- | -------- | ------ | ----------- |
    | `id` | `path`   | Yes      | string | Product ID  |

    **Request body**

    Content type: `application/json`

    | Field         | Type    | Required | Description |
    | ------------- | ------- | -------- | ----------- |
    | `name`        | string  | No       |             |
    | `description` | string  | No       |             |
    | `price`       | number  | No       |             |
    | `published`   | boolean | No       |             |

    **Responses**

    | Status | Description                  |
    | ------ | ---------------------------- |
    | `200`  | Product updated successfully |
    | `404`  | Product not found            |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>

  <Accordion title="POST /products/copy/{id}">
    Duplicate one of your one-time products (or a subscription offer, whichever owns the id) as a NEW item. Send `{ "testMode": false }` to copy a test-mode offer into live mode ("Copy to live"); omit the body to copy within the same mode. The copy gets a deduplicated "Name (Copy)" name and starts unpublished when copied into live mode.

    **Parameters**

    | Name | Location | Required | Type   | Description                              |
    | ---- | -------- | -------- | ------ | ---------------------------------------- |
    | `id` | `path`   | Yes      | string | Product or subscription offer id to copy |

    **Request body**

    Content type: `application/json`

    | Field      | Type    | Required | Description                                                         |
    | ---------- | ------- | -------- | ------------------------------------------------------------------- |
    | `testMode` | boolean | No       | Target mode of the copy. Omit to copy within the source's own mode. |

    **Responses**

    | Status | Description            |
    | ------ | ---------------------- |
    | `201`  | The newly created copy |
    | `400`  | Invalid product ID     |
    | `404`  | Product not found      |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>
</AccordionGroup>

## Refunds

| Method | Endpoint        | Description             |
| ------ | --------------- | ----------------------- |
| `GET`  | `/refunds`      | List refund policies    |
| `POST` | `/refunds`      | Create a refund policy  |
| `GET`  | `/refunds/{id}` | Get refund policy by ID |

<AccordionGroup>
  <Accordion title="GET /refunds">
    Retrieve your refund policies, each with `appliedTo` — how many products use it

    **Responses**

    | Status | Description             |
    | ------ | ----------------------- |
    | `200`  | List of refund policies |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>

  <Accordion title="POST /refunds">
    Create a refund policy that products can reference by id (`refundPolicy`). This does NOT refund a payment — refunds are issued from the dashboard.

    **Request body**

    Content type: `application/json`

    | Field        | Type                                  | Required | Description                 |
    | ------------ | ------------------------------------- | -------- | --------------------------- |
    | `name`       | string                                | No       | Internal name of the policy |
    | `policy`     | string                                | No       | Policy text shown to buyers |
    | `period`     | number; default: `0`                  | No       | Length of the refund window |
    | `periodType` | string — days, weeks; default: `days` | No       | Unit of `period`            |

    **Responses**

    | Status | Description           |
    | ------ | --------------------- |
    | `200`  | Refund policy created |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>

  <Accordion title="GET /refunds/{id}">
    Retrieve a refund policy by its ID. Public (no API key): checkout renders it for buyers.

    **Parameters**

    | Name | Location | Required | Type   | Description      |
    | ---- | -------- | -------- | ------ | ---------------- |
    | `id` | `path`   | Yes      | string | Refund policy ID |

    **Responses**

    | Status | Description             |
    | ------ | ----------------------- |
    | `200`  | Refund policy           |
    | `404`  | Refund policy not found |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>
</AccordionGroup>

## Reviews

| Method | Endpoint   | Description          |
| ------ | ---------- | -------------------- |
| `GET`  | `/reviews` | List product reviews |

<AccordionGroup>
  <Accordion title="GET /reviews">
    Retrieve all reviews across your products, newest first. Filtering is not supported on this endpoint.

    **Responses**

    | Status | Description     |
    | ------ | --------------- |
    | `200`  | List of reviews |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>
</AccordionGroup>

## Subscribers

| Method   | Endpoint                        | Description          |
| -------- | ------------------------------- | -------------------- |
| `GET`    | `/newsletters/subscribers`      | List all subscribers |
| `GET`    | `/newsletters/subscribers/{id}` | Get subscriber by ID |
| `DELETE` | `/newsletters/subscribers/{id}` | Remove subscriber    |

<AccordionGroup>
  <Accordion title="GET /newsletters/subscribers">
    Retrieve a list of all your newsletter subscribers

    **Responses**

    | Status | Description         |
    | ------ | ------------------- |
    | `200`  | List of subscribers |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>

  <Accordion title="GET /newsletters/subscribers/{id}">
    Retrieve a specific subscriber by their ID

    **Parameters**

    | Name | Location | Required | Type   | Description   |
    | ---- | -------- | -------- | ------ | ------------- |
    | `id` | `path`   | Yes      | string | Subscriber ID |

    **Responses**

    | Status | Description        |
    | ------ | ------------------ |
    | `200`  | Subscriber details |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>

  <Accordion title="DELETE /newsletters/subscribers/{id}">
    Remove a subscriber from your list

    **Parameters**

    | Name | Location | Required | Type   | Description   |
    | ---- | -------- | -------- | ------ | ------------- |
    | `id` | `path`   | Yes      | string | Subscriber ID |

    **Responses**

    | Status | Description                     |
    | ------ | ------------------------------- |
    | `200`  | Subscriber removed successfully |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>
</AccordionGroup>

## Subscriptions

| Method | Endpoint                          | Description                                        |
| ------ | --------------------------------- | -------------------------------------------------- |
| `GET`  | `/orders/subscriptions/{id}`      | Get a subscriber with payment history (via Orders) |
| `GET`  | `/subscriptions`                  | List all subscription offers                       |
| `POST` | `/subscriptions`                  | Create a subscription offer                        |
| `GET`  | `/subscriptions/subscribers`      | List subscribers                                   |
| `GET`  | `/subscriptions/subscribers/{id}` | Get a subscriber with payment history              |
| `GET`  | `/subscriptions/{id}`             | Get subscription offer by ID                       |
| `POST` | `/subscriptions/{id}/cancel`      | Cancel a subscriber's subscription                 |
| `POST` | `/subscriptions/{id}/pause`       | Pause a subscriber's subscription                  |
| `POST` | `/subscriptions/{id}/resume`      | Resume a paused subscription                       |

<AccordionGroup>
  <Accordion title="GET /orders/subscriptions/{id}">
    Retrieve a single subscriber (SubscriptionCustomer) by id together with its subscription offer, customer, Stripe subscription/invoices (when applicable), the payment-processor-sourced live `status`, and `payments` — every subscription `Sale` for this membership (the initial charge plus every renewal). `{id}` is the SubscriptionCustomer \_id.

    **Parameters**

    | Name | Location | Required | Type   | Description                                   |
    | ---- | -------- | -------- | ------ | --------------------------------------------- |
    | `id` | `path`   | Yes      | string | Subscriber id (the SubscriptionCustomer \_id) |

    **Responses**

    | Status | Description                             |
    | ------ | --------------------------------------- |
    | `200`  | Subscriber details with payment history |
    | `404`  | Subscription not found                  |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>

  <Accordion title="GET /subscriptions">
    Retrieve all of your subscription OFFERS (the recurring products you sell). To list your subscribers (buyers) instead, use `GET /subscriptions/subscribers`. Authenticate with an API key or JWT.

    **Responses**

    | Status | Description                 |
    | ------ | --------------------------- |
    | `200`  | List of subscription offers |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>

  <Accordion title="POST /subscriptions">
    Create a recurring subscription offer for the authenticated seller. Accepts JSON for API clients and multipart/form-data when uploading files or images. Pricing is charged in USD while multi-currency is disabled.

    **Request body**

    Content type: `application/json`
    Required fields: `name`, `price`, `frequency`.

    | Field              | Type                                | Required | Description                                                                                                    |
    | ------------------ | ----------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------- |
    | `name`             | string                              | Yes      | Subscription offer name                                                                                        |
    | `subtitle`         | string                              | No       | Short offer subtitle                                                                                           |
    | `description`      | string                              | No       | Offer description                                                                                              |
    | `price`            | number                              | Yes      | Recurring price in USD                                                                                         |
    | `frequency`        | string — weekly, monthly, yearly    | Yes      | Billing frequency                                                                                              |
    | `trialPeriod`      | integer; default: `0`               | No       | Trial duration in days                                                                                         |
    | `published`        | boolean; default: `true`            | No       | Whether the offer is published                                                                                 |
    | `redirectBackUrl`  | string (uri)                        | No       | Return URL used by the customer billing portal; defaults to [https://pocketsflow.com](https://pocketsflow.com) |
    | `refundPolicy`     | string                              | No       |                                                                                                                |
    | `checkoutText`     | string                              | No       |                                                                                                                |
    | `portalText`       | string                              | No       |                                                                                                                |
    | `privacyPolicy`    | string (uri)                        | No       |                                                                                                                |
    | `termsOfService`   | string (uri)                        | No       |                                                                                                                |
    | `thumbnail`        | string (uri)                        | No       |                                                                                                                |
    | `images`           | array of string                     | No       | Existing image references or uploaded images in multipart requests                                             |
    | `file`             | string \| object                    | No       | File URL or uploaded file reference                                                                            |
    | `url`              | string (uri)                        | No       |                                                                                                                |
    | `isFile`           | boolean                             | No       |                                                                                                                |
    | `hasFirstName`     | boolean; default: `false`           | No       |                                                                                                                |
    | `hasLastName`      | boolean; default: `false`           | No       |                                                                                                                |
    | `callbackUrl`      | string (uri)                        | No       |                                                                                                                |
    | `hasCallbackUrl`   | boolean                             | No       |                                                                                                                |
    | `productType`      | string — file, url, course, credits | No       | Catalog type. Additive `credits` is prepaid balance with optional auto-refill.                                 |
    | `creditAutoRefill` | object                              | No       | Seller auto-refill setting. `topOffCents` is integer cents.                                                    |
    | `ctaText`          | string                              | No       |                                                                                                                |
    | `thankYouText`     | string                              | No       |                                                                                                                |
    | `slug`             | string                              | No       |                                                                                                                |
    | `hasProductPage`   | boolean                             | No       |                                                                                                                |
    | `showSales`        | boolean                             | No       |                                                                                                                |
    | `showReviews`      | boolean                             | No       |                                                                                                                |
    | `maxPrice`         | number                              | No       |                                                                                                                |
    | `minPrice`         | number                              | No       |                                                                                                                |
    | `design`           | object                              | No       |                                                                                                                |
    | `colors`           | object                              | No       |                                                                                                                |
    | `pageStyle`        | object                              | No       |                                                                                                                |
    | `checkoutStyle`    | object                              | No       |                                                                                                                |
    | `checkoutColors`   | object                              | No       |                                                                                                                |

    **Responses**

    | Status | Description                             |
    | ------ | --------------------------------------- |
    | `201`  | Subscription offer created successfully |
    | `400`  | Invalid subscription offer fields       |
    | `401`  | Unauthorized - Invalid API key          |
    | `404`  | Authenticated seller not found          |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>

  <Accordion title="GET /subscriptions/subscribers">
    Retrieve a paginated list of your subscribers (buyers with a membership in one of your subscription offers). Each subscriber carries a payment-processor-sourced live `status` and the joined subscription offer. Scoped to the authenticated seller and their test/live mode.

    **Parameters**

    | Name             | Location | Required | Type                                                                                                                 | Description                                                  |
    | ---------------- | -------- | -------- | -------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------ |
    | `status`         | `query`  | No       | string — incomplete, incomplete\_expired, trialing, active, past\_due, canceled, unpaid, succeeded, refunded, paused | Filter subscribers by their payment-processor-sourced status |
    | `buyerEmail`     | `query`  | No       | string                                                                                                               | Filter subscribers by buyer email                            |
    | `email`          | `query`  | No       | string                                                                                                               | Alias for buyerEmail                                         |
    | `subscriptionId` | `query`  | No       | string                                                                                                               | Filter subscribers by subscription offer id                  |
    | `page`           | `query`  | No       | integer; default: `1`                                                                                                | Page number for pagination                                   |
    | `pageSize`       | `query`  | No       | integer; default: `20`                                                                                               | Number of subscribers per page                               |

    **Responses**

    | Status | Description                   |
    | ------ | ----------------------------- |
    | `200`  | Paginated list of subscribers |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>

  <Accordion title="GET /subscriptions/subscribers/{id}">
    Retrieve a single subscriber, its subscription offer, the customer record, the payment-processor-sourced live `status`, and its full payment history (`payments` = every subscription `Sale` — the initial charge plus every renewal). Pass `?live=true` to additionally fetch the authoritative membership status from the payments partner API as `whopMembership` (degrades gracefully to the stored status on any payments partner error — never fails the request).

    **Parameters**

    | Name   | Location | Required | Type                      | Description                                                                                                        |
    | ------ | -------- | -------- | ------------------------- | ------------------------------------------------------------------------------------------------------------------ |
    | `id`   | `path`   | Yes      | string                    | Subscriber id (the SubscriptionCustomer \_id)                                                                      |
    | `live` | `query`  | No       | boolean; default: `false` | When true, fetch authoritative live membership status from the payments partner and include it as `whopMembership` |

    **Responses**

    | Status | Description                             |
    | ------ | --------------------------------------- |
    | `200`  | Subscriber details with payment history |
    | `404`  | Subscriber not found                    |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>

  <Accordion title="GET /subscriptions/{id}">
    Retrieve a specific subscription OFFER by its ID. Authenticate with an API key or JWT.

    **Parameters**

    | Name | Location | Required | Type   | Description           |
    | ---- | -------- | -------- | ------ | --------------------- |
    | `id` | `path`   | Yes      | string | Subscription offer ID |

    **Responses**

    | Status | Description                |
    | ------ | -------------------------- |
    | `200`  | Subscription offer details |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>

  <Accordion title="POST /subscriptions/{id}/cancel">
    Schedules the subscriber's membership to cancel at the end of the current billing period (same as the subscriber portal). Access continues until then; `cancelAtPeriodEnd` becomes true. `{id}` is the subscriber `_id` or membership id (`mem_…`) — not a `sub_…` id.

    **Parameters**

    | Name | Location | Required | Type   | Description                                                                                                                   |
    | ---- | -------- | -------- | ------ | ----------------------------------------------------------------------------------------------------------------------------- |
    | `id` | `path`   | Yes      | string | The subscriber's `_id` (SubscriptionCustomer) or its membership id (`mem_…`), as returned by `GET /subscriptions/subscribers` |

    **Responses**

    | Status | Description                        |
    | ------ | ---------------------------------- |
    | `200`  | Subscription canceled successfully |
    | `404`  | Subscription not found             |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>

  <Accordion title="POST /subscriptions/{id}/pause">
    Pauses payment collection on the subscriber's membership. The buyer keeps access and is not charged until `/resume`. If the payments partner refuses, nothing changes (502). `{id}` is the subscriber `_id` or membership id (`mem_…`).

    **Parameters**

    | Name | Location | Required | Type   | Description                                                                                                                   |
    | ---- | -------- | -------- | ------ | ----------------------------------------------------------------------------------------------------------------------------- |
    | `id` | `path`   | Yes      | string | The subscriber's `_id` (SubscriptionCustomer) or its membership id (`mem_…`), as returned by `GET /subscriptions/subscribers` |

    **Responses**

    | Status | Description                                                                |
    | ------ | -------------------------------------------------------------------------- |
    | `200`  | Subscription paused successfully                                           |
    | `400`  | The subscriber has no membership on record, so collection cannot be paused |
    | `404`  | Subscription not found                                                     |
    | `502`  | The payments partner refused the pause; nothing was changed                |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>

  <Accordion title="POST /subscriptions/{id}/resume">
    Restarts payment collection on a paused membership, or otherwise reverses a pending cancel-at-period-end (same as the subscriber portal). `{id}` is the subscriber `_id` or membership id (`mem_…`).

    **Parameters**

    | Name | Location | Required | Type   | Description                                                                                                                   |
    | ---- | -------- | -------- | ------ | ----------------------------------------------------------------------------------------------------------------------------- |
    | `id` | `path`   | Yes      | string | The subscriber's `_id` (SubscriptionCustomer) or its membership id (`mem_…`), as returned by `GET /subscriptions/subscribers` |

    **Responses**

    | Status | Description                       |
    | ------ | --------------------------------- |
    | `200`  | Subscription resumed successfully |
    | `404`  | Subscription not found            |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>
</AccordionGroup>

## Upsells

| Method   | Endpoint        | Description      |
| -------- | --------------- | ---------------- |
| `GET`    | `/upsells`      | List all upsells |
| `POST`   | `/upsells`      | Create an upsell |
| `GET`    | `/upsells/{id}` | Get upsell by ID |
| `POST`   | `/upsells/{id}` | Update upsell    |
| `DELETE` | `/upsells/{id}` | Delete upsell    |

<AccordionGroup>
  <Accordion title="GET /upsells">
    Retrieve a list of all your upsell configurations

    **Responses**

    | Status | Description     |
    | ------ | --------------- |
    | `200`  | List of upsells |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>

  <Accordion title="POST /upsells">
    Create a new upsell offer

    **Request body**

    Content type: `application/json`
    Required fields: `mainProductIds`, `upsellProductId`, `upsellPrice`.

    | Field                      | Type                     | Required | Description                                          |
    | -------------------------- | ------------------------ | -------- | ---------------------------------------------------- |
    | `mainProductIds`           | array of string          | Yes      | Product IDs that trigger this upsell (required)      |
    | `upsellProductId`          | string                   | Yes      | Product ID to offer as upsell (required)             |
    | `upsellPrice`              | number                   | Yes      | Upsell price (required)                              |
    | `name`                     | string                   | No       | Upsell name                                          |
    | `offer`                    | string                   | No       | Offer headline text                                  |
    | `upsellDescription`        | string                   | No       | Upsell description shown to customer                 |
    | `primaryButtonText`        | string                   | No       | Primary button text (e.g., 'Yes, add this!')         |
    | `secondaryButtonText`      | string                   | No       | Secondary button text (e.g., 'No thanks')            |
    | `active`                   | boolean; default: `true` | No       | Whether upsell is active                             |
    | `upsellBackground`         | string                   | No       | Card background color override (hex, e.g. '#fffbe6') |
    | `upsellBorder`             | string                   | No       | Card border color override (hex, e.g. '#d9c98f')     |
    | `upsellHeadline`           | string                   | No       | Headline text color override (hex, e.g. '#14532d')   |
    | `upsellDescriptionColor`   | string                   | No       | Description text color override (hex)                |
    | `upsellCheckboxColor`      | string                   | No       | Checkbox accent color override (hex)                 |
    | `upsellCheckboxBackground` | string                   | No       | Unchecked checkbox box fill color override (hex)     |
    | `upsellHeadingFont`        | string                   | No       | Title font override (font key, e.g. 'poppins')       |
    | `upsellBodyFont`           | string                   | No       | Body font override (font key, e.g. 'serif')          |

    **Responses**

    | Status | Description                 |
    | ------ | --------------------------- |
    | `200`  | Upsell created successfully |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>

  <Accordion title="GET /upsells/{id}">
    Retrieve a specific upsell by its ID

    **Parameters**

    | Name | Location | Required | Type   | Description |
    | ---- | -------- | -------- | ------ | ----------- |
    | `id` | `path`   | Yes      | string | Upsell ID   |

    **Responses**

    | Status | Description    |
    | ------ | -------------- |
    | `200`  | Upsell details |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>

  <Accordion title="POST /upsells/{id}">
    Update an existing upsell. This is a full update — all listed fields are written to the upsell, so send every field you want to keep.

    **Parameters**

    | Name | Location | Required | Type   | Description |
    | ---- | -------- | -------- | ------ | ----------- |
    | `id` | `path`   | Yes      | string | Upsell ID   |

    **Request body**

    Content type: `application/json`

    | Field                      | Type            | Required | Description                          |
    | -------------------------- | --------------- | -------- | ------------------------------------ |
    | `name`                     | string          | No       |                                      |
    | `offer`                    | string          | No       |                                      |
    | `mainProductIds`           | array of string | No       | Product IDs that trigger this upsell |
    | `upsellProductId`          | string          | No       |                                      |
    | `upsellPrice`              | number          | No       |                                      |
    | `upsellDescription`        | string          | No       |                                      |
    | `primaryButtonText`        | string          | No       |                                      |
    | `secondaryButtonText`      | string          | No       |                                      |
    | `active`                   | boolean         | No       |                                      |
    | `upsellBackground`         | string          | No       |                                      |
    | `upsellBorder`             | string          | No       |                                      |
    | `upsellHeadline`           | string          | No       |                                      |
    | `upsellDescriptionColor`   | string          | No       |                                      |
    | `upsellCheckboxColor`      | string          | No       |                                      |
    | `upsellCheckboxBackground` | string          | No       |                                      |
    | `upsellHeadingFont`        | string          | No       |                                      |
    | `upsellBodyFont`           | string          | No       |                                      |

    **Responses**

    | Status | Description                 |
    | ------ | --------------------------- |
    | `200`  | Upsell updated successfully |
    | `404`  | Upsell not found            |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>

  <Accordion title="DELETE /upsells/{id}">
    Delete an upsell offer

    **Parameters**

    | Name | Location | Required | Type   | Description |
    | ---- | -------- | -------- | ------ | ----------- |
    | `id` | `path`   | Yes      | string | Upsell ID   |

    **Responses**

    | Status | Description                 |
    | ------ | --------------------------- |
    | `200`  | Upsell deleted successfully |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>
</AccordionGroup>

## Webhooks

| Method   | Endpoint              | Description       |
| -------- | --------------------- | ----------------- |
| `GET`    | `/webhooks`           | List all webhooks |
| `POST`   | `/webhooks`           | Create a webhook  |
| `GET`    | `/webhooks/{id}`      | Get webhook by ID |
| `PATCH`  | `/webhooks/{id}`      | Update webhook    |
| `DELETE` | `/webhooks/{id}`      | Delete webhook    |
| `POST`   | `/webhooks/{id}/test` | Test webhook      |

<AccordionGroup>
  <Accordion title="GET /webhooks">
    Retrieve a list of all your webhook endpoints

    **Responses**

    | Status | Description      |
    | ------ | ---------------- |
    | `200`  | List of webhooks |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>

  <Accordion title="POST /webhooks">
    Create a new webhook endpoint to receive events

    **Request body**

    Content type: `application/json`
    Required fields: `url`, `events`.

    | Field         | Type                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              | Required | Description                               |
    | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ----------------------------------------- |
    | `url`         | string (uri)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      | Yes      | Webhook endpoint URL (must be HTTPS)      |
    | `events`      | array of string — order.completed, order.refunded, product.created, product.updated, product.deleted, review\.created, customer.created, customer.subscription.created, customer.subscription.updated, customer.subscription.deleted, customer.subscription.pause, customer.subscription.resumed, customer.subscription.trial\_will\_end, invoice.created, invoice.upcoming, invoice.payment\_succeeded, invoice.payment\_failed, payment\_intent.succeeded, payment\_intent.payment\_failed, credit.granted, credit.balance\_changed, credit.auto\_refill.succeeded, credit.auto\_refill.failed, credit.consent.enabled, credit.consent.disabled | Yes      | List of events to subscribe to (required) |
    | `description` | string                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            | No       | Optional description                      |

    **Responses**

    | Status | Description                                                                                         |
    | ------ | --------------------------------------------------------------------------------------------------- |
    | `200`  | Webhook created successfully. New webhooks start active; use `PATCH /webhooks/{id}` to disable one. |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>

  <Accordion title="GET /webhooks/{id}">
    Retrieve a specific webhook by its ID

    **Parameters**

    | Name | Location | Required | Type   | Description |
    | ---- | -------- | -------- | ------ | ----------- |
    | `id` | `path`   | Yes      | string | Webhook ID  |

    **Responses**

    | Status | Description     |
    | ------ | --------------- |
    | `200`  | Webhook details |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>

  <Accordion title="PATCH /webhooks/{id}">
    Update an existing webhook

    **Parameters**

    | Name | Location | Required | Type   | Description |
    | ---- | -------- | -------- | ------ | ----------- |
    | `id` | `path`   | Yes      | string | Webhook ID  |

    **Request body**

    Content type: `application/json`

    | Field         | Type            | Required | Description |
    | ------------- | --------------- | -------- | ----------- |
    | `url`         | string (uri)    | No       |             |
    | `events`      | array of string | No       |             |
    | `description` | string          | No       |             |
    | `active`      | boolean         | No       |             |

    **Responses**

    | Status | Description                  |
    | ------ | ---------------------------- |
    | `200`  | Webhook updated successfully |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>

  <Accordion title="DELETE /webhooks/{id}">
    Delete a webhook endpoint

    **Parameters**

    | Name | Location | Required | Type   | Description |
    | ---- | -------- | -------- | ------ | ----------- |
    | `id` | `path`   | Yes      | string | Webhook ID  |

    **Responses**

    | Status | Description                  |
    | ------ | ---------------------------- |
    | `200`  | Webhook deleted successfully |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>

  <Accordion title="POST /webhooks/{id}/test">
    Send a test event to the webhook endpoint

    **Parameters**

    | Name | Location | Required | Type   | Description |
    | ---- | -------- | -------- | ------ | ----------- |
    | `id` | `path`   | Yes      | string | Webhook ID  |

    **Responses**

    | Status | Description                  |
    | ------ | ---------------------------- |
    | `200`  | Test event sent successfully |

    Try it in the [interactive API explorer](https://api.pocketsflow.com/docs).
  </Accordion>
</AccordionGroup>

## Need a typed client?

Use the [Pocketsflow Node.js SDK](/api-reference/sdk) for typed server-side calls, or import [`/docs.json`](https://api.pocketsflow.com/docs.json) into your preferred OpenAPI generator.
