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

# Execution

> Quote-then-execute buys and sells on the Pure marketplace

Create a quote, optionally pick add-ons, then execute with `expectedTotal` set to that quote’s `total`. Pricing lives in Postgres as a Port cart — not in this API’s memory — and expires in **60 seconds**.

<Note>
  Quotes and execute require an **Admin** API key (`stytch_admin`). Payment
  methods, payout methods, and trading status use **Member** access
  (`stytch_member`). Every execution route is also gated by an organization
  allowlist — **403** if your org is not allowlisted. See
  [Authentication](/api-reference/authentication).
</Note>

## How a quote works

`POST /execution/v2/{buy|sell}/quotes` creates a cart in the database and returns a pricing snapshot: `quoteId`, `lineItems`, `fees`, `optionals`, `subtotal`, `total`, and `expiresAt`.

That `quoteId` is the cart UUID. Refresh, optionals, and execute all load the same cart. After 60 seconds the cart row can still exist, but the price is no longer valid until you refresh or create a new quote.

Execute re-prices from live listings and offers, then checks `expectedTotal`:

* **Buy** — reject if the live charge went **up** (ceiling)
* **Sell** — reject if the live payout went **down** (floor)

A cheaper buy or a richer sell still goes through. `expectedTotal` is a bound, not a frozen fill. Field-by-field schemas live in the **API Reference** tab.

```mermaid theme={null}
sequenceDiagram
    participant You
    participant API as Pure API

    You->>API: POST /execution/v2/buy/quotes
    API-->>You: quoteId + total (60s)

    You->>API: POST .../execute (expectedTotal = quote.total)
    API->>API: Re-price, then enforce the bound
    API-->>You: orderId, or 409 subtotal_mismatch
```

## Buy

```bash theme={null}
curl -X POST https://api.collectpure.com/execution/v2/buy/quotes \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "items": [{ "listingId": "LISTING_UUID", "quantity": 1 }],
    "paymentMethod": "pm_XXXXX"
  }'

curl -X POST https://api.collectpure.com/execution/v2/buy/quotes/QUOTE_ID/execute \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "expectedTotal": TOTAL_FROM_QUOTE,
    "paymentMethod": "pm_XXXXX",
    "shipping": {
      "name": "Jane Doe",
      "line1": "123 Main St",
      "city": "Austin",
      "state": "TX",
      "postalCode": "78701",
      "country": "US"
    }
  }'
```

`paymentMethod` is `wire_transfer` or a Stripe `pm_` / `ba_` id — not the `stripe` / `stripe_ach` labels from the payment-methods list. Omit `shipping` when [vault shipping](/api-reference/execution-optionals) is selected. Side-specific details: [Buy](/api-reference/execution-buy).

## Sell

```bash theme={null}
curl -X POST https://api.collectpure.com/execution/v2/sell/quotes \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "items": [{ "offerId": "OFFER_UUID", "quantity": 1 }]
  }'

curl -X POST https://api.collectpure.com/execution/v2/sell/quotes/QUOTE_ID/execute \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "expectedTotal": TOTAL_FROM_QUOTE
  }'
```

Sell items can also be `productId` + `variantId` + `quantity`. Listing conflicts, instant payout, and optional-fee reconciliation: [Sell](/api-reference/execution-sell).

## After execute — where the order lives

Order list endpoints are named from **Pure’s warehouse**, not from your quote side. Execute succeeding is not the same as a shipping label existing.

| You executed | `orderId` is     | Fetch it at                             | Why                                     |
| ------------ | ---------------- | --------------------------------------- | --------------------------------------- |
| **Sell**     | A purchase order | `GET /orders/get-purchase-order/v1?id=` | Pure is buying from you (inbound metal) |
| **Buy**      | A sale order     | `GET /orders/get-sale-orders/v1`        | Pure is selling to you (outbound metal) |

A sell showing up under purchase orders is expected. Poll `GET /orders/get-purchase-order/v1?id={orderId}` for `shippingLabelUrl` — labels are generated **after** confirm, not in the execute response. That can take well more than 10–15 minutes.

## Shared rules

| Topic        | Rule                                                                                                         |
| ------------ | ------------------------------------------------------------------------------------------------------------ |
| TTL          | 60 seconds. On `410` or `subtotal_mismatch`, create a **new** quote. Do not retry the old `expectedTotal`.   |
| Optionals    | Select with `selectedOptionalIds`. Catalog and eligibility: [Optionals](/api-reference/execution-optionals). |
| Promotions   | Preview on `.../promotion-preview`. Apply with `promotionCode` on execute, not on create.                    |
| Trading halt | Execute may return `system_check_failed`. Poll `GET /execution/v2/trading-status`.                           |
| Errors       | One table for both sides: [Errors](/api-reference/execution-errors).                                         |
| Sandbox      | Same routes, no real money: [Sandbox](/api-reference/execution-sandbox).                                     |

## Roles

| Family                                                                    | Role            |
| ------------------------------------------------------------------------- | --------------- |
| Buy/sell quotes, execute, optionals, promotion preview, listing conflicts | `stytch_admin`  |
| Payment methods, payout methods, trading status                           | `stytch_member` |
