{
  "openapi": "3.1.0",
  "info": {
    "title": "Pillport public API",
    "version": "1.0.0",
    "description": "Read-only medicine equivalents across countries. For information and education only; not medical advice.",
    "contact": {
      "email": "hello@pillport.online"
    }
  },
  "servers": [
    {
      "url": "https://pillport.online"
    }
  ],
  "paths": {
    "/api/v1/medicines": {
      "get": {
        "summary": "List medicines",
        "responses": {
          "200": {
            "description": "All medicines (slug, generic name, alternate names, drug class, ATC code)"
          }
        }
      }
    },
    "/api/v1/medicines/{slug}": {
      "get": {
        "summary": "One medicine with brands by country",
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "paracetamol"
          }
        ],
        "responses": {
          "200": {
            "description": "Medicine detail with brands_by_country, verification status and sources"
          },
          "404": {
            "description": "Unknown slug"
          }
        }
      }
    },
    "/api/v1/equivalent": {
      "get": {
        "summary": "Find the equivalent of a brand in another country",
        "parameters": [
          {
            "name": "brand",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "maxLength": 80
            },
            "example": "panadol"
          },
          {
            "name": "to",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 2,
              "maxLength": 2
            },
            "example": "US"
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "minLength": 2,
              "maxLength": 2
            },
            "description": "Disambiguates brand names used for more than one medicine"
          }
        ],
        "responses": {
          "200": {
            "description": "Equivalent answer, or { ambiguous: true, candidates } when the brand name maps to several medicines"
          },
          "400": {
            "description": "Invalid query"
          },
          "404": {
            "description": "Unknown brand or country"
          },
          "429": {
            "description": "Rate limit exceeded (60 requests per minute per IP)"
          }
        },
        "security": [
          {},
          {
            "apiKey": []
          }
        ]
      }
    },
    "/api/v1/countries": {
      "get": {
        "summary": "Countries and their medicine regulators",
        "responses": {
          "200": {
            "description": "Country list"
          }
        }
      }
    },
    "/api/search-index": {
      "get": {
        "summary": "Compact search index (name, slug, kind, country)",
        "responses": {
          "200": {
            "description": "Index rows"
          }
        }
      }
    },
    "/api/health": {
      "get": {
        "summary": "Health check",
        "responses": {
          "200": {
            "description": "Service status and version"
          }
        }
      }
    },
    "/api/v1/pk/simulate": {
      "post": {
        "summary": "Simulate a one-compartment PK regimen",
        "description": "Educational model. Not for clinical dosing.",
        "security": [
          {},
          {
            "apiKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "route",
                  "dose_mg",
                  "interval_h",
                  "n_doses",
                  "volume_l",
                  "clearance_l_per_h"
                ],
                "properties": {
                  "route": {
                    "type": "string",
                    "enum": [
                      "bolus",
                      "infusion",
                      "oral"
                    ]
                  },
                  "dose_mg": {
                    "type": "number",
                    "exclusiveMinimum": 0
                  },
                  "interval_h": {
                    "type": "number",
                    "exclusiveMinimum": 0
                  },
                  "n_doses": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 60
                  },
                  "volume_l": {
                    "type": "number",
                    "exclusiveMinimum": 0
                  },
                  "clearance_l_per_h": {
                    "type": "number",
                    "exclusiveMinimum": 0
                  },
                  "infusion_h": {
                    "type": "number"
                  },
                  "ka_per_h": {
                    "type": "number"
                  },
                  "bioavailability": {
                    "type": "number",
                    "maximum": 1
                  },
                  "target_low": {
                    "type": "number"
                  },
                  "target_high": {
                    "type": "number"
                  },
                  "samples": {
                    "type": "integer",
                    "minimum": 10,
                    "maximum": 600
                  }
                }
              },
              "example": {
                "route": "oral",
                "dose_mg": 1000,
                "interval_h": 6,
                "n_doses": 4,
                "volume_l": 50,
                "clearance_l_per_h": 18,
                "ka_per_h": 1.5,
                "bioavailability": 0.9
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Stats, concentration points and a disclaimer"
          },
          "400": {
            "description": "Invalid input"
          },
          "401": {
            "description": "Invalid or revoked API key"
          },
          "429": {
            "description": "Rate limit or monthly quota reached (see Retry-After)"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "apiKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "Optional. Create a key at /app/api-keys for 600 requests/minute and a monthly quota. Without a key: 60 requests/minute per IP."
      }
    }
  }
}
