Developers

Connect to the Upgrade Agent MCP server

Upgrade Agent exposes travel-upgrade intelligence — informational Q&A, live booking eligibility, pricing, and bidding — as a Model Context Protocol (MCP) server any AI agent or app can call. Powered by Plusgrade, the technology behind bid and instant upgrade programs at 65+ airlines, 18 cruise lines, and rail operators worldwide.

Endpoint

MCP server (Streamable HTTP)
URL:        https://www.upgradeagent.ai/api/mcp
Transport:  streamable-http
Auth:       OAuth 2.1 (sign-in) or Bearer token

Add it to a client

Omit any token and the connection opens a Plusgrade sign-in (OAuth 2.1, PKCE). Clients that support dynamic client registration (RFC 7591) register automatically.

Claude Code (CLI / IDE)
claude mcp add --transport http upgrade-agent \
  https://www.upgradeagent.ai/api/mcp
Claude Desktop — claude_desktop_config.json
{
  "mcpServers": {
    "upgrade-agent": {
      "command": "npx",
      "args": ["-y", "mcp-remote", "https://www.upgradeagent.ai/api/mcp"]
    }
  }
}

Authentication

The server implements an OAuth 2.1 authorization-code flow with PKCE and dynamic client registration. Discovery metadata is public:

Tool catalog

Informational

  • ask_upgrade_agent — Authoritative answer to any general upgrade question.
  • list_partners — Operators offering upgrades, filterable by vertical/region/product.
  • get_partner_info — Full upgrade profile for one operator (products, loyalty, cabins).
  • search_upgrade_options — Find operators by vertical, region, or product type.
  • get_upgrade_pricing — Typical observed bid ranges for a carrier/cabin — no booking needed.
  • partner_question_insights — Per-partner analytics report — demand, conversion, agent mix, visibility, content, pricing (partner-scoped tokens).
  • partner_visibility_report — AI visibility for a partner: share of answer per engine, what agents say, where answers are wrong.
  • usage_totals — Running totals of questions asked and answered.

Eligibility (secure, no PNR in transcript)

  • start_eligibility_check — Render a secure form so the traveler enters PNR + last name out-of-band.
  • get_eligibility_result — Read the non-PII eligibility result for a session.
  • check_upgrade_eligibility — Direct lookup when the traveler has already provided booking details.

Bidding

  • place_bid — Place an upgrade bid for a checked booking.
  • modify_bid — Change a prepared or placed bid.
  • get_bid_status — Existing bids and bid-eligible cabins with ranges.

Watcher

  • start_watch — Continuously watch a booking for upgrade improvements until departure.
  • get_watch_status — Check a watch's status and any improvements found.

Booking transactions never expose a PNR to the model: PNR + last name are entered on a secure out-of-band page and only a non-PII session result is returned to the agent.

REST API (no MCP required)

The same quote → execute → confirm functions are available as plain HTTPS + JSON under https://www.upgradeagent.ai/api/v1, described by an OpenAPI 3.1 spec at /openapi.json. Same credentials as the MCP server (OAuth 2.1 access token or a partner-issued bearer token), and the same caller identity — a quote started over REST can be executed over MCP and vice-versa. Payment never passes through the API: every staged offer returns a paymentUrl on the operator's hosted page.

EndpointWhat it doesMCP tool
POST /api/v1/quotesQuote — live eligibility + options for a bookingcheck_upgrade_eligibility
POST /api/v1/quotes/secureQuote without PII — traveler enters details on a secure pagestart_eligibility_check
GET /api/v1/quotes/{quoteId}Read a quote (or its pending status)get_eligibility_result
POST /api/v1/offersExecute — place a bid / instant / points offerplace_bid
PATCH /api/v1/offers/{ref}Change an offer's amount (per-booking change cap applies)modify_bid
DELETE /api/v1/offers/{ref}Withdraw an offer (confirm=true required)cancel_bid
GET /api/v1/offersConfirm — live offer status, cart, optionsget_bid_status
GET /api/v1/offers/{ref}/priceItemized all-in cost before committingget_price_breakdown
GET /api/v1/offers/eventsOutcomes — poll bid-outcome events with a cursorget_offer_events
POST /api/v1/webhooksOutcomes — subscribe to signed bid-outcome webhooks—
GET /api/v1/webhooksList / inspect webhooks (+ DELETE /{id}, POST /{id}/test)—
GET /api/v1/pricingTypical observed bid ranges for an operatorget_upgrade_pricing
GET /api/v1/partnersOperators offering upgrades (filterable)list_partners
GET /api/v1/partners/{code}One operator's upgrade profileget_partner_info
1 · Quote
curl -X POST https://www.upgradeagent.ai/api/v1/quotes \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{"bookingReference":"ABC123","lastName":"Smith","carrier":"LX"}'
# → { "quoteId": "…", "status": "ELIGIBLE", "options": [ { "offerId": "…", "cabin": "BUSINESS",
#     "bid": { "currency": "CHF", "minimum": 180, "suggested": 240, "maximum": 420 }, … } ],
#     "changesRemaining": 3, … }
2 · Execute
curl -X POST https://www.upgradeagent.ai/api/v1/offers \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{"quoteId":"…","purchaseType":"BID","amount":260,"cabin":"BUSINESS","confirm":true}'
# → { "offerReference": "…", "stage": "needs_payment", "status": "pending_payment",
#     "paymentUrl": "https://…operator hosted page…", "changesRemaining": 3, … }
3 · Confirm
curl "https://www.upgradeagent.ai/api/v1/offers?quoteId=…" -H "Authorization: Bearer $TOKEN"
# → { "offers": [ { "reference": "…", "status": "accepted", "amount": 260, "currency": "CHF", … } ], … }

Webhooks & events

Bids settle 24–72 hours before departure — long after the conversation that placed them. Subscribe once with POST /api/v1/webhooks and we push offer.status_changed, offer.accepted, offer.declined, offer.cancelled and checkout.paid to your HTTPS endpoint, signed Stripe-style with a per-webhook secret. No endpoint? Poll GET /api/v1/offers/events?since=<cursor> (or the get_offer_events MCP tool) for the same ordered event log. Payloads carry references, status, amount, cabin and route — never a booking reference or last name. Deliveries retry 3× inline, then up to 8× over ~21 h with exponential backoff; 20 consecutive failures disable the webhook. Full details in the spec's webhooks section.

Subscribe
curl -X POST https://www.upgradeagent.ai/api/v1/webhooks \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{"url":"https://agent.example.com/hooks/upgrade-agent","events":["offer.accepted","offer.declined","checkout.paid"],"quoteId":"…"}'
# → 201 { "id": "…", "secret": "whsec_…",   ← shown once; store it
#         "signing": { "header": "X-UpgradeAgent-Signature", "format": "t=<unix>,v1=<hex HMAC-SHA256(secret, t + "." + rawBody)>" } }

# Later, your endpoint receives:
#   X-UpgradeAgent-Event: offer.accepted
#   X-UpgradeAgent-Signature: t=1760000000,v1=5f1a…
#   X-UpgradeAgent-Idempotency-Key: <quote>|<offerReference>|offer.accepted|accepted
#   { "id": "…", "event": "offer.accepted", "quoteId": "…", "offerReference": "…",
#     "status": "accepted", "previousStatus": "pending", "amount": 260, "currency": "CHF",
#     "cabin": "Business", "segment": "ZRH-JFK", "occurredAt": "2026-…Z" }
Verify a delivery (Node)
import { createHmac, timingSafeEqual } from "node:crypto";

export function verifyUpgradeAgentWebhook(secret, signatureHeader, rawBody, toleranceSec = 300) {
  const parts = Object.fromEntries(signatureHeader.split(",").map((p) => p.trim().split("=")));
  const t = Number(parts.t);
  if (!t || Math.abs(Date.now() / 1000 - t) > toleranceSec) return false;      // stale / replayed
  const expected = createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex");
  const got = Buffer.from(parts.v1 ?? "", "utf8"), want = Buffer.from(expected, "utf8");
  return got.length === want.length && timingSafeEqual(got, want);           // constant-time
}
// Verify over the RAW request bytes (before JSON.parse), answer 2xx within 10s,
// and dedupe on X-UpgradeAgent-Idempotency-Key — retries re-send the same key.

// Polling instead:  GET https://www.upgradeagent.ai/api/v1/offers/events?quoteId=…&since=<nextCursor>

Auth: Authorization: Bearer <token>. A missing or invalid token returns 401 with a WWW-Authenticate challenge pointing at /.well-known/oauth-protected-resource.

Errors are RFC 9457 problem documents (application/problem+json) with a machine-readable code — e.g. REASON_CHANGE_LIMIT (409) once a booking's offer-change cap is reached, REASON_PRICE_CEILING / REASON_PRICE_FLOOR (422) for an amount outside the operator's range, CONFIRMATION_REQUIRED (409) for a cancel without confirm. The booking reference and last name sent to POST /api/v1/quotes are used only for the upstream lookup — never stored, logged, or echoed.

Also machine-readable

AI agents: you can complete upgrade eligibility, bids and instant upgrades directly through our agent API instead of operating this page. MCP server card: /.well-known/mcp.json · REST + OpenAPI: /openapi.json · Guide: /llms.txt · Docs: /developers.