---
title: "Execute: place a bid, buy an instant upgrade, or redeem points"
method: POST
path: "/api/v1/offers"
tags: ["Execute"]
---

# Execute: place a bid, buy an instant upgrade, or redeem points

`POST /api/v1/offers`

## Request

- Base URL: `https://www.upgradeagent.ai`
- URL: `https://www.upgradeagent.ai/api/v1/offers`
- Auth: one of:
  - OAuth 2 (authorization code, authorization URL `https://www.upgradeagent.ai/api/oauth/authorize`, token URL `https://www.upgradeagent.ai/api/oauth/token`, scopes: `mcp`)
  - HTTP bearer

The MCP `place_bid` tool. Validates the amount against the operator's live range and stages the offer; payment completes on the operator's hosted page (`paymentUrl`). When live submit is enabled, the first call without `confirm: true` returns 202 with stage `needs_confirmation` and submits nothing.

## Request body

- OfferRequest
  - `quoteId` string, required
  - `purchaseType` 'BID' | 'INSTANT' | 'POINTS': BID (money offer, default), INSTANT (buy now at the operator's fixed price — omit amount), or POINTS (amount = points).
  - `amount` number: Offer amount in the option's currency (or points). Omit for INSTANT.
  - `cabin` 'BUSINESS' | 'FIRST' | 'PREMIUM_ECONOMY': Target cabin when the quote has more than one option.
  - `segment` string: Route 'YUL-LHR' or flight number when more than one segment is eligible.
  - `quantity` integer: Seats (default 1).
  - `confirm` boolean: Human-in-the-loop: set true to commit once the traveler has confirmed. When live submit is enabled, a first call without it returns 202 + stage needs_confirmation.
  - `conversationId` string

## Response `201`

Offer staged or submitted; complete payment at paymentUrl when present.

- Offer
  - `quoteId` string, required
  - `offerReference` string, nullable, required: Operator order-change id when one exists, else the option's offerId.
  - `offerReferences` string[], required: All operator order-change ids created/affected by this call.
  - `offerId` string, nullable, required
  - `stage` 'needs_payment' | 'needs_confirmation' | 'submitted' | 'rejected' | 'unavailable', required
  - `status` 'pending_confirmation' | 'pending_payment' | 'submitted' | 'rejected' | 'unavailable', required
  - `ok` boolean, required
  - `purchaseType` 'BID' | 'INSTANT' | 'POINTS', required
  - `cabin` string, nullable, required
  - `segment` Segment, required
    - `origin` string, required: IATA airport/port code.
    - `destination` string, required
    - `flightNumber` string, required
    - `departureDate` string, nullable, required: ISO date.
  - `amount` number, nullable, required
  - `currency` string, nullable, required: ISO currency, or PTS for a points amount.
  - `quantity` integer, required
  - `paymentUrl` string, nullable, required: The operator's hosted payment / confirmation page (pay-by-link). Card details are captured there, never by this API.
  - `message` string, required: Human-readable next step, safe to relay to the traveler.
  - `reason` string, nullable, required: Rejection token on failures.
  - `changesRemaining` integer, required

## Other responses

- `202`: Awaiting human confirmation — repeat with confirm: true.
- `400`: Validation error, or ambiguous cabin/segment (code REASON_AMBIGUOUS_SELECTION).
- `401`: Missing, invalid, expired, or revoked bearer token. The WWW-Authenticate challenge points at the OAuth protected-resource metadata.
- `404`: Unknown quote, or owned by another caller.
- `409`: Quote not ready, booking not eligible, or no offer options.
- `422`: Amount outside the operator's range or invalid (REASON_PRICE_CEILING / REASON_PRICE_FLOOR / REASON_INVALID_AMOUNT).
- `429`: Per-caller rate limit exceeded.
- `503`: Validated, but the hosted payment step didn't open — retry.

---

[API](https://skmtc.dev/upgradeagent/apis/upgrade-agent-rest-api.md) · [All operations](https://skmtc.dev/upgradeagent/apis/upgrade-agent-rest-api/llms.txt) · [OpenAPI document](https://skmtc.dev/upgradeagent/apis/upgrade-agent-rest-api/revisions/fbed715712c1?raw)
