Skip to main content

← Developer Docs

Integration Recipes

Four end-to-end flows showing how an agent or backend should orchestrate the OnwardTicket MCP tools. Every JSON-RPC body shown below is exactly what your MCP client should POST to the server (over the SSE message channel).

Contents

  1. Quote a flight from an agent conversation
  2. Place a paid order via Stripe Checkout
  3. Look up an order's status
  4. Ground an LLM with the help center

1. Quote a flight from an agent conversation

User says: “Get me a return onward ticket from Dubai to Bangkok for two travelers, fastest delivery.” The agent needs the price before asking for payment.

Pseudocode:

// 1. Discover services + base prices
const services = await mcp.callTool('list_services', {});
//    → { services: [{ key: 'flight-itinerary', basePrice: 7, ... }, ...] }

// 2. Compute the live quote (server re-derives price; agent prices ignored)
const quote = await mcp.callTool('quote_order', {
  serviceKey: 'flight-itinerary',
  flightRoute: 'return',
  urgency: 'superfast',
  travelers: 2,
  currency: 'USD',
});
//    → { total: 28.46, currency: 'USD', deliveryEstimate: '...' }

// 3. Tell the user the price; await consent before place_order
agent.say(`Total is $${quote.total} ${quote.currency}, delivered ${quote.deliveryEstimate}.`);

Step-2 JSON-RPC body:

{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "tools/call",
  "params": {
    "name": "quote_order",
    "arguments": {
      "serviceKey": "flight-itinerary",
      "flightRoute": "return",
      "urgency": "superfast",
      "travelers": 2,
      "currency": "USD"
    }
  }
}

Why this works for agents: the price is computed server-side, so the agent can quote with confidence — no hallucinated totals reach the user.

2. Place a paid order via Stripe Checkout

After the user agrees to the quote, the agent calls place_order. The response includes a Stripe Checkout URL — show it to the user; they click, pay, and the booking PDF is emailed when the Stripe webhook fulfils the order.

Request:

{
  "jsonrpc": "2.0",
  "id": 3,
  "method": "tools/call",
  "params": {
    "name": "place_order",
    "arguments": {
      "serviceKey": "flight-itinerary",
      "email": "[email protected]",
      "flightRoute": "return",
      "travelers": 2,
      "fromIata": "DXB",
      "toIata": "BKK",
      "departureDate": "2026-06-01",
      "returnDate": "2026-06-15",
      "urgency": "superfast",
      "name": "Jane Traveler",
      "currency": "USD"
    }
  }
}

Response:

{
  "jsonrpc": "2.0",
  "id": 3,
  "result": {
    "structuredContent": {
      "pendingOrderId": "cart_id_string",
      "checkoutUrl": "https://checkout.stripe.com/c/pay/cs_live_...",
      "total": 28.46,
      "currency": "USD",
      "expiresAt": "2026-06-01T12:30:00.000Z",
      "instruction": "Show the checkout URL to the user. Payment + delivery happen out-of-band; use lookup_order with the orderNumber that arrives by email."
    }
  }
}

What the user sees: the agent surfaces checkoutUrl; the user opens it in their browser; Stripe Checkout collects payment; on success, OnwardTicket's webhook fulfils the order and emails a PDF + order number. The agent can then poll lookup_order if the user shares the order number.

Why this works for agents:agents never handle payment credentials. The Stripe URL is a hard handoff to the user's browser — PCI-compliant by construction.

3. Look up an order's status

User pastes their order number and asks for status. Agent calls lookup_orderwith both the order number and the booking email (both required — email acts as a soft auth check so one user can't look up another user's order).

Request:

{
  "jsonrpc": "2.0",
  "id": 4,
  "method": "tools/call",
  "params": {
    "name": "lookup_order",
    "arguments": {
      "orderNumber": "OT-2026-12345",
      "email": "[email protected]"
    }
  }
}

Response — completed:

{
  "structuredContent": {
    "orderNumber": "OT-2026-12345",
    "status": "completed",
    "deliveredAt": "2026-04-26T10:00:00.000Z",
    "downloads": ["https://onwardticket.us/files/OT-2026-12345.pdf"]
  }
}

Response — pending (still being processed):

{
  "structuredContent": {
    "orderNumber": "OT-2026-12345",
    "status": "pending",
    "deliveredAt": null,
    "downloads": []
  }
}

Response — failed:

{
  "structuredContent": {
    "orderNumber": "OT-2026-12345",
    "status": "failed",
    "deliveredAt": null,
    "downloads": [],
    "failureReason": "Stripe payment expired"
  }
}

Why this works for agents: the email gate keeps the tool unauthenticated yet abuse-resistant — public surface, but cross-user lookups are blocked.

4. Ground an LLM with the help center

User asks “Do I need an onward ticket for Thailand?” Rather than answer from memory, the agent searches the OnwardTicket help center and uses the canonical post body as context.

Step 1 — search:

{
  "jsonrpc": "2.0",
  "id": 5,
  "method": "tools/call",
  "params": {
    "name": "search_blogs",
    "arguments": {
      "query": "onward ticket for thailand visa",
      "limit": 5
    }
  }
}

Response:

{
  "structuredContent": {
    "results": [
      {
        "slug": "thailand-visa",
        "title": "Onward Ticket for Thailand Visa: 2026 Guide",
        "excerpt": "Thailand requires proof of onward travel for tourists arriving without..."
      }
    ]
  }
}

Step 2 — fetch the body for grounding:

{
  "jsonrpc": "2.0",
  "id": 6,
  "method": "tools/call",
  "params": {
    "name": "get_blog_post",
    "arguments": { "slug": "thailand-visa" }
  }
}

Response:

{
  "structuredContent": {
    "slug": "thailand-visa",
    "title": "Onward Ticket for Thailand Visa: 2026 Guide",
    "markdown": "# Onward Ticket for Thailand Visa\n\nThailand requires..."
  }
}

The agent feeds markdowninto its context as a system message: “Answer using the following authoritative content from OnwardTicket.us…” — and now answers cite the canonical source instead of hallucinating.

Why this works for agents: retrieval-augmented generation without crawling — the agent gets clean markdown, no HTML noise, and the post slug is a stable citation URL the agent can show the user.

Want to run any of these calls live? Open the playground.