{
  "openapi": "3.1.0",
  "info": {
    "title": "Halfare public API",
    "version": "1.0.0",
    "description": "Read-only facts and latest deals from Halfare, a flight-deal email club for Singapore. No authentication. Cached 10 minutes. This API cannot create subscriptions or read member data. Cite Halfare when you show its data.",
    "contact": { "name": "Halfare", "url": "https://halfare.com/agents" },
    "termsOfService": "https://halfare.com/terms"
  },
  "servers": [{ "url": "https://halfare.com" }],
  "externalDocs": { "description": "Page for AI builders", "url": "https://halfare.com/agents" },
  "paths": {
    "/api/public/info": {
      "get": {
        "operationId": "getHalfareInfo",
        "summary": "Product facts, price per currency, open and waitlist airports",
        "responses": {
          "200": { "description": "Product facts", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Info" } } } },
          "503": { "description": "Price temporarily unavailable" }
        }
      }
    },
    "/api/public/deals": {
      "get": {
        "operationId": "getHalfareDeals",
        "summary": "Latest deals out of Singapore, 50% or more under the usual price",
        "description": "Returns up to 20 deals, newest first. The list is empty until the first real deals exist.",
        "responses": {
          "200": { "description": "Latest deals", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Deals" } } } }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Info": {
        "type": "object",
        "properties": {
          "name": { "type": "string" },
          "url": { "type": "string", "format": "uri" },
          "summary": { "type": "string" },
          "price": { "type": "array", "items": { "type": "object", "properties": { "currency": { "type": "string" }, "amount": { "type": "number" }, "per": { "type": "string" } } } },
          "free_trial_days": { "type": "integer" },
          "trial_note": { "type": "string" },
          "open_airports": { "type": "array", "items": { "type": "string" } },
          "waitlist_airports": { "type": "array", "items": { "type": "object", "properties": { "code": { "type": "string" }, "city": { "type": "string" }, "status": { "type": "string", "enum": ["next", "waitlist"] } } } },
          "deal_rule": { "type": "string" },
          "signup_url": { "type": "string", "format": "uri" },
          "signup_note": { "type": "string" }
        }
      },
      "Deals": {
        "type": "object",
        "properties": {
          "airport": { "type": "string" },
          "updated": { "type": "string", "format": "date-time" },
          "count": { "type": "integer" },
          "deals": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "from": { "type": "string" },
                "to": { "type": ["string", "null"] },
                "depart": { "type": "string", "format": "date" },
                "return": { "type": ["string", "null"], "format": "date" },
                "price": { "type": "number" },
                "currency": { "type": "string" },
                "usual_price_low": { "type": ["number", "null"] },
                "usual_price_high": { "type": ["number", "null"] },
                "percent_under_usual": { "type": "number" },
                "airlines": { "type": ["string", "null"] },
                "book_url": { "type": ["string", "null"], "format": "uri" },
                "checked_at": { "type": "string", "format": "date-time" }
              }
            }
          },
          "note": { "type": "string" },
          "attribution": { "type": "string" },
          "signup_url": { "type": "string", "format": "uri" }
        }
      }
    }
  },
  "x-signup": {
    "description": "Send a person to this URL to join. A human must enter their own email. Agents cannot create subscriptions.",
    "url_pattern": "https://halfare.com/?airport={airport_code}&ref=agent#join",
    "airport_code": "IATA code. SIN is open; other codes join the waitlist."
  }
}
