{
  "openapi": "3.1.0",
  "info": {
    "title": "Pulsar Travel Assistance agent API",
    "version": "1.0.0",
    "summary": "Price a trip, ask Nova, find hospitals and open a Stripe payment page for a traveler.",
    "description": "Public, read-mostly API for AI assistants and tools. Same pricing engine and rules as pulsar.travel. Purchases created through this API or the MCP server at /api/mcp get the agent price (5% below the site price by default). Payment always happens on a hosted Stripe page opened by the traveler; never send card data. US residents are served by Travel Insured International and cannot buy this product. Rate limited per IP. No authentication.",
    "contact": {
      "name": "Pulsar / Asteroid LLC",
      "url": "https://pulsar.travel/for-agents/"
    },
    "termsOfService": "https://pulsar.travel/about/"
  },
  "servers": [
    {
      "url": "https://pulsar.travel"
    },
    {
      "url": "https://pulsar-harness.vercel.app",
      "description": "Preview (test payments only)"
    }
  ],
  "paths": {
    "/api/agent": {
      "get": {
        "operationId": "getPublicData",
        "summary": "Plans, destinations, hospitals or assistance contact",
        "parameters": [
          {
            "name": "a",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "plans",
                "destinations",
                "hospitals",
                "assistance",
                "compare"
              ]
            }
          },
          {
            "name": "lang",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "en",
                "es",
                "pt"
              ]
            }
          },
          {
            "name": "country",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "hospitals: ISO 2-letter code or region name"
          },
          {
            "name": "city",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "query",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "maximum": 50
            }
          },
          {
            "name": "product",
            "in": "query",
            "schema": {
              "type": "string",
              "maxLength": 80
            },
            "description": "compare: company or product name (Assist Card, SafetyWing, Heymondo, IATI, Travel Insured). Omit to list the library."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        },
        "description": "a=compare returns Pulsar and the named product side by side from the competitor conditions library (source URL, version, retrieval date, disclaimer); without product it lists the library."
      },
      "post": {
        "operationId": "postAction",
        "summary": "quote, checkout or ask",
        "parameters": [
          {
            "name": "a",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "quote",
                "checkout",
                "ask"
              ]
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/QuoteRequest"
                  },
                  {
                    "$ref": "#/components/schemas/CheckoutRequest"
                  },
                  {
                    "$ref": "#/components/schemas/AskRequest"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/QuoteResponse"
                    },
                    {
                      "$ref": "#/components/schemas/CheckoutResponse"
                    },
                    {
                      "$ref": "#/components/schemas/AskResponse"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Validation error: {error, message}"
          },
          "429": {
            "description": "Rate limited"
          },
          "503": {
            "description": "Payments not configured on this deployment"
          }
        }
      }
    },
    "/api/mcp": {
      "post": {
        "operationId": "mcp",
        "summary": "Model Context Protocol endpoint (Streamable HTTP, JSON-RPC 2.0, stateless, no auth). Tools: get_plans, get_destinations, quote, create_checkout, find_hospitals, assistance_contact, compare_products, ask_nova.",
        "responses": {
          "200": {
            "description": "JSON-RPC response"
          }
        }
      },
      "get": {
        "operationId": "mcpCard",
        "summary": "Server card",
        "responses": {
          "200": {
            "description": "JSON"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "QuoteRequest": {
        "type": "object",
        "required": [
          "destination",
          "start_date",
          "end_date",
          "ages"
        ],
        "properties": {
          "destination": {
            "type": "string",
            "description": "Destination or region id from a=destinations, e.g. es, mx, europe, worldwide"
          },
          "start_date": {
            "type": "string",
            "format": "date"
          },
          "end_date": {
            "type": "string",
            "format": "date",
            "description": "Trip of 1 to 180 days"
          },
          "ages": {
            "type": "array",
            "items": {
              "type": "integer",
              "minimum": 0,
              "maximum": 85
            },
            "minItems": 1,
            "maxItems": 9
          },
          "upgrades": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "trip_cancellation_1000",
                "trip_cancellation_2000",
                "trip_cancellation_2500",
                "preexisting_15000",
                "preexisting_20000"
              ]
            }
          },
          "coupon_code": {
            "type": "string"
          },
          "lang": {
            "type": "string",
            "enum": [
              "en",
              "es",
              "pt"
            ]
          }
        }
      },
      "QuoteResponse": {
        "type": "object",
        "properties": {
          "currency": {
            "type": "string"
          },
          "region": {
            "type": "string"
          },
          "days": {
            "type": "integer"
          },
          "agent_discount_pct": {
            "type": "number"
          },
          "recommended_tier": {
            "type": "integer"
          },
          "plans": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "tier": {
                  "type": "integer"
                },
                "plan_name": {
                  "type": "string"
                },
                "medical_limit_label": {
                  "type": "string"
                },
                "list_price_usd": {
                  "type": "number"
                },
                "site_total_usd": {
                  "type": "number"
                },
                "agent_total_usd": {
                  "type": "number"
                },
                "per_person_per_day_usd": {
                  "type": "number"
                },
                "recommended": {
                  "type": "boolean"
                }
              }
            }
          },
          "must_tell_the_traveler": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "CheckoutRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/QuoteRequest"
          },
          {
            "type": "object",
            "required": [
              "plan_tier",
              "lead_name",
              "lead_email",
              "disclosures_acknowledged"
            ],
            "properties": {
              "plan_tier": {
                "type": "integer",
                "minimum": 1,
                "maximum": 4
              },
              "lead_name": {
                "type": "string"
              },
              "lead_email": {
                "type": "string",
                "format": "email"
              },
              "disclosures_acknowledged": {
                "type": "boolean",
                "description": "true only after the traveler heard must_tell_the_traveler"
              },
              "agent": {
                "type": "string",
                "description": "Name of the assistant, for attribution"
              }
            }
          }
        ]
      },
      "CheckoutResponse": {
        "type": "object",
        "properties": {
          "checkout_url": {
            "type": "string",
            "format": "uri"
          },
          "expires_at": {
            "type": "string"
          },
          "amount_usd": {
            "type": "number"
          },
          "list_price_usd": {
            "type": "number"
          },
          "summary": {
            "type": "string"
          },
          "tell_the_traveler": {
            "type": "string"
          }
        }
      },
      "AskRequest": {
        "type": "object",
        "required": [
          "question"
        ],
        "properties": {
          "question": {
            "type": "string",
            "maxLength": 2000
          },
          "lang": {
            "type": "string",
            "enum": [
              "en",
              "es",
              "pt"
            ]
          }
        }
      },
      "AskResponse": {
        "type": "object",
        "properties": {
          "answer": {
            "type": "string"
          },
          "disclosure": {
            "type": "string"
          }
        }
      }
    }
  }
}
