{
 "openapi": "3.1.0",
 "info": {
  "title": "recallsapi.com",
  "version": "0.1.0",
  "summary": "US recalls from CPSC, FDA and NHTSA in one API (USDA FSIS coming soon), with product matching and catalog monitoring.",
  "description": "Every record links to its agency source with an as-of date. Matches carry a confidence level and the reasons behind it; a match is information to review, not a legal or safety determination. Sold by PrimeZen LLC.",
  "contact": {
   "name": "recallsapi.com support",
   "email": "hello@recallsapi.com",
   "url": "https://recallsapi.com"
  },
  "termsOfService": "https://recallsapi.com/terms"
 },
 "servers": [
  {
   "url": "https://api.recallsapi.com"
  }
 ],
 "security": [
  {
   "bearer": []
  }
 ],
 "paths": {
  "/v1/health": {
   "get": {
    "operationId": "health",
    "summary": "Freshness of every source",
    "security": [],
    "responses": {
     "200": {
      "description": "All sources fresh",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "503": {
      "description": "At least one source is stale",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     }
    }
   }
  },
  "/v1/keys": {
   "post": {
    "operationId": "createKey",
    "summary": "Get a free API key",
    "security": [],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "required": [
         "email"
        ],
        "properties": {
         "email": {
          "type": "string",
          "format": "email"
         }
        }
       }
      }
     }
    },
    "description": "Creates a Free account and sends its key to the email address, and only there. One free account per inbox: +tags and Gmail dots count as the same inbox.",
    "responses": {
     "201": {
      "description": "Created with the key in the response (test deployments without key email)",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "api_key": {
           "type": "string"
          },
          "account_id": {
           "type": "string"
          },
          "plan": {
           "type": "string"
          },
          "limits": {
           "type": "object",
           "properties": {
            "label": {
             "type": "string"
            },
            "monthly_usd": {
             "type": "number"
            },
            "daily_calls": {
             "type": "integer"
            },
            "catalogs": {
             "type": "integer"
            },
            "monitored_products": {
             "type": "integer",
             "description": "Across all catalogs on the account"
            },
            "alerts": {
             "type": "boolean"
            }
           }
          }
         }
        }
       }
      }
     },
     "202": {
      "description": "Created; the key is on its way by email",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "sent": {
           "type": "boolean"
          },
          "email": {
           "type": "string"
          },
          "note": {
           "type": "string"
          }
         }
        }
       }
      }
     },
     "409": {
      "description": "An account exists for this inbox",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "429": {
      "description": "Too many keys from this network or email domain today",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "503": {
      "description": "Signup is not available right now",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/v1/check": {
   "get": {
    "operationId": "checkProduct",
    "summary": "Is this product recalled?",
    "description": "Give any mix of name, brand, barcode, model, NDC and lot. Identifiers are normalized (UPC to GTIN-14, NDC to 11 digits) before matching.",
    "parameters": [
     {
      "name": "name",
      "in": "query",
      "schema": {
       "type": "string"
      },
      "description": "Product name or description"
     },
     {
      "name": "brand",
      "in": "query",
      "schema": {
       "type": "string"
      },
      "description": "Brand or manufacturer"
     },
     {
      "name": "upc",
      "in": "query",
      "schema": {
       "type": "string"
      },
      "description": "UPC, EAN or GTIN barcode"
     },
     {
      "name": "model",
      "in": "query",
      "schema": {
       "type": "string"
      },
      "description": "Model or part number"
     },
     {
      "name": "ndc",
      "in": "query",
      "schema": {
       "type": "string"
      },
      "description": "National Drug Code (any layout)"
     },
     {
      "name": "lot",
      "in": "query",
      "schema": {
       "type": "string"
      },
      "description": "Lot or batch code"
     }
    ],
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "resolved": {
           "type": "object"
          },
          "matches": {
           "type": "array",
           "items": {
            "$ref": "#/components/schemas/Match"
           }
          }
         }
        }
       }
      }
     },
     "400": {
      "description": "Invalid input",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "401": {
      "description": "Missing or invalid API key",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "429": {
      "description": "Daily quota reached",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/v1/check/batch": {
   "post": {
    "operationId": "checkProducts",
    "summary": "Check up to 100 products",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "items": {
          "type": "array",
          "maxItems": 100,
          "items": {
           "type": "object",
           "properties": {
            "name": {
             "type": "string"
            },
            "brand": {
             "type": "string"
            },
            "upc": {
             "type": "string"
            },
            "model": {
             "type": "string"
            },
            "ndc": {
             "type": "string"
            },
            "lot": {
             "type": "string"
            }
           }
          }
         }
        }
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "400": {
      "description": "Invalid input",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "401": {
      "description": "Missing or invalid API key",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "429": {
      "description": "Daily quota reached",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/v1/recalls": {
   "get": {
    "operationId": "searchRecalls",
    "summary": "Search recalls",
    "parameters": [
     {
      "name": "q",
      "in": "query",
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "category",
      "in": "query",
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "source",
      "in": "query",
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "since",
      "in": "query",
      "schema": {
       "type": "string",
       "format": "date"
      }
     },
     {
      "name": "until",
      "in": "query",
      "schema": {
       "type": "string",
       "format": "date"
      }
     },
     {
      "name": "limit",
      "in": "query",
      "schema": {
       "type": "integer",
       "minimum": 1,
       "maximum": 100,
       "default": 20
      }
     },
     {
      "name": "cursor",
      "in": "query",
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "results": {
           "type": "array",
           "items": {
            "$ref": "#/components/schemas/Recall"
           }
          },
          "next_cursor": {
           "type": [
            "string",
            "null"
           ]
          }
         }
        }
       }
      }
     },
     "400": {
      "description": "Invalid input",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "401": {
      "description": "Missing or invalid API key",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "429": {
      "description": "Daily quota reached",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/v1/recalls/{id}": {
   "get": {
    "operationId": "getRecall",
    "summary": "One recall with identifiers",
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Recall"
        }
       }
      }
     },
     "400": {
      "description": "Invalid input",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "401": {
      "description": "Missing or invalid API key",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "404": {
      "description": "Not found",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "429": {
      "description": "Daily quota reached",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/v1/vehicles/{vin}": {
   "get": {
    "operationId": "checkVin",
    "summary": "NHTSA campaigns for a VIN",
    "parameters": [
     {
      "name": "vin",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string",
       "minLength": 17,
       "maxLength": 17
      }
     }
    ],
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "400": {
      "description": "Invalid input",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "401": {
      "description": "Missing or invalid API key",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "429": {
      "description": "Daily quota reached",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/v1/vehicles": {
   "get": {
    "operationId": "checkVehicle",
    "summary": "NHTSA campaigns by make, model and year",
    "parameters": [
     {
      "name": "make",
      "in": "query",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "model",
      "in": "query",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "year",
      "in": "query",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "400": {
      "description": "Invalid input",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "401": {
      "description": "Missing or invalid API key",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "429": {
      "description": "Daily quota reached",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/v1/catalogs": {
   "get": {
    "operationId": "listCatalogs",
    "summary": "Your monitored catalogs",
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "400": {
      "description": "Invalid input",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "401": {
      "description": "Missing or invalid API key",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "429": {
      "description": "Daily quota reached",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   },
   "post": {
    "operationId": "createCatalog",
    "summary": "Create a monitored catalog",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "required": [
         "name"
        ],
        "properties": {
         "name": {
          "type": "string"
         },
         "alert_email": {
          "type": "string",
          "format": "email"
         },
         "webhook_url": {
          "type": "string",
          "format": "uri"
         },
         "min_confidence": {
          "type": "string",
          "enum": [
           "exact",
           "strong",
           "possible"
          ]
         }
        }
       }
      }
     }
    },
    "responses": {
     "201": {
      "description": "Created; includes webhook_secret for signature checks",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "400": {
      "description": "Invalid input",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "401": {
      "description": "Missing or invalid API key",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "402": {
      "description": "Plan limit",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "429": {
      "description": "Daily quota reached",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/v1/catalogs/{id}/items": {
   "post": {
    "operationId": "addItems",
    "summary": "Add or replace items (JSON or CSV); returns matches found in recall history",
    "description": "Up to 5,000 rows per upload: CSV (or a marketplace export as it comes) up to 10 MB, JSON up to 5 MB. Monitored products count across all catalogs on the account.",
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "items": {
          "type": "array",
          "items": {
           "type": "object",
           "properties": {
            "sku": {
             "type": "string"
            },
            "name": {
             "type": "string"
            },
            "brand": {
             "type": "string"
            },
            "upc": {
             "type": "string"
            },
            "model": {
             "type": "string"
            },
            "ndc": {
             "type": "string"
            },
            "lot": {
             "type": "string"
            },
            "vin": {
             "type": "string"
            },
            "marketplace": {
             "type": "string"
            }
           }
          }
         }
        }
       }
      },
      "text/csv": {
       "schema": {
        "type": "string"
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "400": {
      "description": "Invalid input",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "401": {
      "description": "Missing or invalid API key",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "429": {
      "description": "Daily quota reached",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   },
   "get": {
    "operationId": "listItems",
    "summary": "Items in a catalog, by SKU, a page at a time",
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "limit",
      "in": "query",
      "schema": {
       "type": "integer",
       "minimum": 1,
       "maximum": 5000,
       "default": 5000
      }
     },
     {
      "name": "cursor",
      "in": "query",
      "schema": {
       "type": "string"
      },
      "description": "next_cursor from the previous page"
     }
    ],
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "items": {
           "type": "array",
           "items": {
            "type": "object"
           }
          },
          "next_cursor": {
           "type": [
            "string",
            "null"
           ]
          }
         }
        }
       }
      }
     },
     "400": {
      "description": "Invalid input",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "401": {
      "description": "Missing or invalid API key",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "429": {
      "description": "Daily quota reached",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/v1/catalogs/{id}/matches": {
   "get": {
    "operationId": "listMatches",
    "summary": "Recall matches for a catalog, newest first, a page at a time",
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "status",
      "in": "query",
      "schema": {
       "type": "string",
       "enum": [
        "open",
        "dismissed",
        "all"
       ]
      }
     },
     {
      "name": "limit",
      "in": "query",
      "schema": {
       "type": "integer",
       "minimum": 1,
       "maximum": 5000,
       "default": 100
      }
     },
     {
      "name": "cursor",
      "in": "query",
      "schema": {
       "type": "string"
      },
      "description": "next_cursor from the previous page"
     }
    ],
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "matches": {
           "type": "array",
           "items": {
            "type": "object"
           }
          },
          "next_cursor": {
           "type": [
            "string",
            "null"
           ]
          }
         }
        }
       }
      }
     },
     "400": {
      "description": "Invalid input",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "401": {
      "description": "Missing or invalid API key",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "429": {
      "description": "Daily quota reached",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/v1/account": {
   "get": {
    "operationId": "account",
    "summary": "Plan, limits and usage today",
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "account_id": {
           "type": "string"
          },
          "email": {
           "type": "string"
          },
          "plan": {
           "type": "string",
           "enum": [
            "free",
            "starter",
            "growth",
            "scale"
           ]
          },
          "status": {
           "type": "string"
          },
          "limits": {
           "type": "object",
           "properties": {
            "label": {
             "type": "string"
            },
            "monthly_usd": {
             "type": "number"
            },
            "daily_calls": {
             "type": "integer"
            },
            "catalogs": {
             "type": "integer"
            },
            "monitored_products": {
             "type": "integer",
             "description": "Across all catalogs on the account"
            },
            "alerts": {
             "type": "boolean"
            }
           }
          },
          "calls_today": {
           "type": "integer"
          }
         }
        }
       }
      }
     },
     "400": {
      "description": "Invalid input",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "401": {
      "description": "Missing or invalid API key",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "429": {
      "description": "Daily quota reached",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/v1/catalogs/{id}": {
   "delete": {
    "operationId": "deleteCatalog",
    "summary": "Delete a catalog with its items and matches",
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "deleted": {
           "type": "boolean"
          }
         }
        }
       }
      }
     },
     "400": {
      "description": "Invalid input",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "401": {
      "description": "Missing or invalid API key",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "404": {
      "description": "Not found",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "429": {
      "description": "Daily quota reached",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/v1/catalogs/{id}/matches/{itemId}/{recallId}/dismiss": {
   "post": {
    "operationId": "dismissMatch",
    "summary": "Dismiss a match that does not apply",
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "itemId",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "recallId",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "dismissed": {
           "type": "boolean"
          }
         }
        }
       }
      }
     },
     "400": {
      "description": "Invalid input",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "401": {
      "description": "Missing or invalid API key",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "404": {
      "description": "No open match",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "429": {
      "description": "Daily quota reached",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/v1/billing/checkout": {
   "post": {
    "operationId": "checkout",
    "summary": "Start a Stripe Checkout for a paid plan; returns {url}",
    "description": "Starter $29, Growth $79, Scale $199 a month; a year is 10 times the monthly price. Card payments.",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "required": [
         "plan"
        ],
        "properties": {
         "plan": {
          "type": "string",
          "enum": [
           "starter",
           "growth",
           "scale"
          ]
         },
         "interval": {
          "type": "string",
          "enum": [
           "month",
           "year"
          ],
          "default": "month"
         }
        }
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "url": {
           "type": "string",
           "format": "uri"
          }
         }
        }
       }
      }
     },
     "400": {
      "description": "Invalid input",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "401": {
      "description": "Missing or invalid API key",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "409": {
      "description": "The account already has a subscription; change it in the billing portal",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "429": {
      "description": "Daily quota reached",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "503": {
      "description": "Plan not on sale yet",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/v1/billing/portal": {
   "post": {
    "operationId": "billingPortal",
    "summary": "Open the Stripe customer portal; returns {url}",
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "url": {
           "type": "string",
           "format": "uri"
          }
         }
        }
       }
      }
     },
     "400": {
      "description": "Invalid input",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "401": {
      "description": "Missing or invalid API key",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "429": {
      "description": "Daily quota reached",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/mcp": {
   "post": {
    "operationId": "mcp",
    "summary": "MCP server (Streamable HTTP, JSON responses). initialize and tools/list are open; tools/call needs the API key",
    "security": [],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "description": "JSON-RPC 2.0 message"
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "description": "JSON-RPC 2.0 response"
        }
       }
      }
     },
     "202": {
      "description": "Notification accepted"
     }
    }
   }
  }
 },
 "components": {
  "securitySchemes": {
   "bearer": {
    "type": "http",
    "scheme": "bearer",
    "description": "API key from POST /v1/keys"
   }
  },
  "schemas": {
   "Recall": {
    "type": "object",
    "properties": {
     "id": {
      "type": "string",
      "examples": [
       "fda-H-1339-2026"
      ]
     },
     "agency": {
      "type": "string",
      "enum": [
       "CPSC",
       "FDA",
       "NHTSA",
       "USDA FSIS"
      ]
     },
     "source": {
      "type": "string",
      "enum": [
       "cpsc",
       "fda_food",
       "fda_drug",
       "fda_device",
       "nhtsa",
       "fsis"
      ]
     },
     "source_id": {
      "type": "string",
      "description": "The agency recall number"
     },
     "category": {
      "type": "string",
      "enum": [
       "consumer_product",
       "food",
       "drug",
       "device",
       "vehicle",
       "vehicle_equipment",
       "tire",
       "child_seat",
       "meat_poultry"
      ]
     },
     "title": {
      "type": "string"
     },
     "description": {
      "type": [
       "string",
       "null"
      ]
     },
     "hazard": {
      "type": [
       "string",
       "null"
      ]
     },
     "remedy": {
      "type": [
       "string",
       "null"
      ]
     },
     "classification": {
      "type": [
       "string",
       "null"
      ],
      "description": "FDA and FSIS class (Class I, II, III) or NHTSA recall type"
     },
     "status": {
      "type": [
       "string",
       "null"
      ]
     },
     "firms": {
      "type": "array",
      "items": {
       "type": "string"
      }
     },
     "products": {
      "type": "array",
      "items": {
       "type": "string"
      }
     },
     "distribution": {
      "type": [
       "string",
       "null"
      ]
     },
     "units": {
      "type": [
       "string",
       "null"
      ]
     },
     "flags": {
      "type": "array",
      "items": {
       "type": "string",
       "enum": [
        "do_not_drive",
        "park_outside",
        "public_health_alert",
        "outbreak",
        "fda_mandated",
        "lots_truncated"
       ]
      }
     },
     "recall_date": {
      "type": [
       "string",
       "null"
      ],
      "format": "date"
     },
     "report_date": {
      "type": [
       "string",
       "null"
      ],
      "format": "date"
     },
     "url": {
      "type": "string",
      "format": "uri",
      "description": "Agency notice"
     },
     "source_url": {
      "type": "string",
      "format": "uri",
      "description": "Machine-readable source record"
     },
     "as_of": {
      "type": "string",
      "format": "date-time",
      "description": "When recallsapi.com last saw this record change"
     },
     "identifiers": {
      "type": "array",
      "items": {
       "type": "object",
       "properties": {
        "kind": {
         "type": "string"
        },
        "value": {
         "type": "string"
        },
        "raw": {
         "type": "string"
        }
       }
      }
     }
    }
   },
   "Match": {
    "type": "object",
    "properties": {
     "confidence": {
      "type": "string",
      "enum": [
       "exact",
       "strong",
       "possible"
      ],
      "description": "exact: barcode or NDC package code; strong: identifier confirmed by brand or a distinctive model; possible: brand and name overlap or a weak identifier"
     },
     "reasons": {
      "type": "array",
      "items": {
       "type": "string"
      }
     },
     "recall": {
      "$ref": "#/components/schemas/Recall"
     }
    }
   },
   "Error": {
    "type": "object",
    "properties": {
     "error": {
      "type": "object",
      "properties": {
       "code": {
        "type": "string"
       },
       "message": {
        "type": "string"
       },
       "details": {}
      }
     }
    }
   }
  }
 }
}
