> ## 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.

# Unique coupons and personal deadlines

> Issue one-time codes per recipient and give every subscriber their own offer window, from the API, the SDK or an AI agent.

Both features are plan-gated: unique coupons need **Growth**, personal
deadlines need **Pro**. A gated write answers `403` with
`code: FEATURE_LOCKED` and `details.requiredPlan`. Reads, deletes and CSV
exports are never gated.

## Unique coupons

Turn a discount into a unique-per-recipient discount:

```bash theme={"system"}
curl -X POST https://api.pocketsflow.com/discounts \
  -H "Authorization: Bearer pk_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "VIP 20%",
    "code": "VIP",
    "value": 20,
    "mainProductIds": ["665f1c2a9b3e4a0012ab34cd"],
    "uniquePerRecipient": true,
    "uniqueExpiryHours": 48
  }'
```

`code` becomes the prefix of each one-time code and no longer works by itself.

| Method | Path | What it does |
| - | - | - |
| `GET` | `/discounts/{id}/unique-codes` | Issued / redeemed / expired counts and a page of codes (`status`, `limit`, `before`) |
| `POST` | `/discounts/{id}/unique-codes` | Issue codes: `{ "emails": [...] }` (bound) or `{ "count": 500 }` (unbound), optional `expiresInHours` |
| `GET` | `/discounts/{id}/unique-codes/export` | Every code as CSV: `code,email,status,expires_at,redeemed_at` |

In emails, `{{unique_coupon:<discountId>}}` issues one code per recipient at
send time and `{{unique_coupon_url:<discountId>}}` links to checkout with it.

### At checkout

`GET /discounts/apply/{code}/{productId}?email=` (public) resolves a one-time
code only for its email:

| Status | `code` | When |
| - | - | - |
| `200` | — | The discount, plus `uniqueCode: { code, expiresAt, emailBound }` |
| `422` | `UNIQUE_CODE_EMAIL_REQUIRED` | The code is bound to an email and none was sent |
| `403` | `UNIQUE_CODE_EMAIL_MISMATCH` | Another email |
| `409` | `UNIQUE_CODE_IN_USE` | Another open checkout holds the code (up to 30 minutes) |
| `410` | `UNIQUE_CODE_REDEEMED` / `UNIQUE_CODE_EXPIRED` / `UNIQUE_CODE_UNAVAILABLE` | Used, expired, or the seller's plan no longer includes it |

Creating a checkout reserves the code (and a personal offer) for that
checkout for 30 minutes, so two checkouts opened at once can't both be paid
at the discounted price. The payment consumes it; a declined or abandoned
checkout gives it back.

## Personal deadlines

```bash theme={"system"}
curl -X POST https://api.pocketsflow.com/personal-deadlines \
  -H "Authorization: Bearer pk_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "72-hour launch offer",
    "productId": "665f1c2a9b3e4a0012ab34cd",
    "durationHours": 72,
    "offer": { "type": "percentage", "value": 30 },
    "fallback": { "type": "full_price" },
    "trigger": { "type": "audience_joined" }
  }'
```

| Method | Path | What it does |
| - | - | - |
| `GET` | `/personal-deadlines` | Your deadlines with `stats` |
| `POST` | `/personal-deadlines` | Create one |
| `GET` / `POST` / `DELETE` | `/personal-deadlines/{id}` | Read, partially update, delete |
| `GET` | `/personal-deadlines/{id}/entries` | The people on it and their state |
| `POST` | `/personal-deadlines/{id}/start` | Start `email`'s clock now and get their personal link (idempotent) |
| `GET` | `/personal-deadlines/{id}/link?email=` | Their personal link, without starting the clock |
| `GET` | `/personal-deadlines/public/offer?productId=&sid=` | Public: a visitor's own window on a product |

`offer.type` is `percentage`, `fixed` or `price`; `fallback.type` is
`full_price`, `percentage` or `fixed`; `trigger.type` is `audience_joined`,
`lead_magnet` (with `productId`) or `automation_entered` (with
`automationId`).

The personal link (`?pf_sid=…`) identifies the person on your store. It is
the same encrypted visitor token that browse abandonment uses, so one link
serves both. Without the server's signing key, links are plain product links
(`personalized: false`) and personal offers don't apply. The
offer itself is enforced from their server-side clock: after it ends, or once
they bought at the offer price, checkout charges the fallback price whatever
token they bring.

## SDK and MCP

The MCP server exposes `list_unique_codes`, `generate_unique_codes`,
`list_personal_deadlines`, `create_personal_deadline`, `get_personal_deadline`,
`update_personal_deadline`, `delete_personal_deadline`,
`list_personal_deadline_entries`, `start_personal_deadline` and
`get_personal_deadline_link`. The Node.js SDK gains the same operations in its
next release.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.