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

# Buy When the Price Drops

> Buy a product automatically when its total falls under a limit that the user approved

Your app can buy a product when its price falls under a limit. Crossmint does not watch prices. Your app starts a checkout on a schedule, and the spending cap stops the checkout while the total is too high. When the total is under the limit, an order intent that the user approved before pays for the order.

<video className="w-full rounded-xl" autoPlay muted loop playsInline src="https://mintcdn.com/crossmint/eLFFFOlQTcnBWJ-s/images/agents/checkouts/price-drop.mp4?fit=max&auto=format&n=eLFFFOlQTcnBWJ-s&q=85&s=354d3fdde9f7d0fc048bf25c2b8bf468" data-path="images/agents/checkouts/price-drop.mp4" />

## Prerequisites

* **Agent Checkouts integration** — complete the [quickstart](/agents/agent-checkouts-quickstart) and [Pay for a Checkout](/agents/checkouts/payments).
* **A scheduler** — a cron job or a queue in your backend that starts a checkout at fixed times.
* **Keys** — a production server key with the Agent Checkouts scopes, and a client key with `order-intents.create` and `order-intents.read`.

## Watch the Price and Buy

<Steps>
  <Step title="Ask the user to approve the limit">
    Create an order intent for the limit, for as long as you watch the price. The user approves it one time, in your app. Omit `merchant`: Agent Checkouts gives the merchant when it pays.

    ```typescript theme={null}
    const expiresAt = new Date(Date.now() + 14 * 24 * 60 * 60 * 1000).toISOString();

    const response = await fetch("https://www.crossmint.com/api/unstable/order-intents", {
        method: "POST",
        headers: {
            "Content-Type": "application/json",
            "X-API-KEY": "YOUR_CLIENT_API_KEY",
            Authorization: "Bearer YOUR_USER_JWT",
        },
        body: JSON.stringify({
            paymentMethodId: "YOUR_PAYMENT_METHOD_ID",
            amount: { value: "250.00", currency: "USD" },
            description: "Wireless headphones when the price is 250 USD or less",
            expiresAt,
        }),
    });
    if (!response.ok) {
        throw new Error(`Could not create order intent: ${response.status}`);
    }
    const { orderIntentId } = await response.json();
    ```

    Verify the card rail if it is `pending_verification`, and store the `orderIntentId`. See [Approve an Order Intent](/agents/payment-methods/cards/create-agent-card#verify-the-selected-rail).
  </Step>

  <Step title="Start a checkout on a schedule">
    On each run of your scheduler, start a checkout with `maxCost` equal to the limit:

    ```typescript theme={null}
    const response = await fetch("https://www.crossmint.com/api/unstable/agent-checkouts", {
        method: "POST",
        headers: {
            "Content-Type": "application/json",
            "X-API-KEY": process.env.CROSSMINT_SERVER_API_KEY!,
            "x-crossmint-user-id": "YOUR_USER_ID",
        },
        body: JSON.stringify({
            request: {
                startUrl: "https://shop.example.com/products/wireless-headphones",
                task: "Buy one pair of the wireless headphones in black. Use standard shipping and pay by card.",
            },
            buyerProfileId: "YOUR_BUYER_PROFILE_ID",
            constraints: { maxCost: { amount: "250.00", currency: "USD" } },
        }),
    });
    if (!response.ok) {
        throw new Error(`Could not start checkout: ${response.status}`);
    }
    const { runId } = await response.json();
    ```

    A [buyer profile](/agents/checkouts/configure) gives the shipping address, so that the checkout does not stop to ask for it.
  </Step>

  <Step title="Act on the result">
    [Follow the checkout](/agents/checkouts/follow-run) and act on what happens. Run only one checkout at a time for this purchase: do not start the next scheduled checkout while one is still active.

    | What happens | What your app does |
    | - | - |
    | The checkout ends as `blocked` with `policy.max_cost_exceeded` | The total is still higher than the limit. Try again at the next run. |
    | The checkout sends a payment request | The total is under the limit. Stop the schedule first, then answer with the stored `orderIntentId`. See [Pay With an Order Intent](/agents/checkouts/payments#pay-with-an-order-intent). |
    | The checkout ends as `succeeded` | Tell the user, and [cancel the order intent](/agents/payment-methods/cards/remove-cards), so that it cannot pay again. |
  </Step>
</Steps>

## Common Gotchas

<AccordionGroup>
  <Accordion title="Two checkouts can buy the product twice">
    Each checkout that reaches the payment step can use the order intent while its available amount covers the total. Run one checkout at a time, stop the schedule before you answer a payment request, and cancel the order intent after the purchase.
  </Accordion>

  <Accordion title="Each check costs a checkout">
    Crossmint bills each checkout that starts, also when it ends as `blocked`. Check at a reasonable interval, for example once a day.
  </Accordion>

  <Accordion title="The limit includes shipping and tax">
    `maxCost` applies to the total of the order. Tell the user that the limit includes shipping and tax.
  </Accordion>

  <Accordion title="The payment answer gets rail_unavailable">
    When the saved card has no network rail, the checkout uses the encrypted card, which needs the card's security code. Crossmint keeps the code for a limited time. Ask the user to [enter the CVC again](/agents/payment-methods/cards/recollect-cvc), then answer the new payment request.
  </Accordion>

  <Accordion title="The order intent expired">
    The payment answer fails after the order intent's `expiresAt`. Ask the user to approve a new order intent, or stop the schedule.
  </Accordion>
</AccordionGroup>

## Next Steps

<CardGroup cols={3}>
  <Card title="Check a Price Without Buying" icon="tag" href="/agents/checkouts/use-cases/check-a-price">
    Get the exact total of an order
  </Card>

  <Card title="Statuses, Results, and Errors" icon="list-check" href="/agents/checkouts/statuses">
    Handle every result of a checkout
  </Card>

  <Card title="Create a Checkout" icon="brackets-curly" href="/api-reference/agent-checkouts/create-agent-checkout">
    Review the complete create request schema
  </Card>
</CardGroup>
