{
	  "openapi": "3.1.0",
	  "info": {
    "title": "Notamify Watcher API",
    "version": "1.0.0",
    "description": "HTTP API for Notamify watcher and listener management. Register listeners with webhook and/or email delivery and filter matching NOTAMs by notam_icao, notam_type, airport_type, aircraft_type, aircraft_designator, aircraft_family, category, subcategory, qcode, affected_element, and time_windows. Category supports the wildcard value 'all'. notam_type applies to normal deliveries and accepts N (NOTAMN) and R (NOTAMR). Lifecycle cancellation and replacement notifications are configured separately via the lifecycle object. Optionally include up to three email addresses alongside webhook deliveries."
	  },
	  "servers": [
	    { "url": "https://watcher.notamify.com" }
	  ],
	  "paths": {
    "/stats": {
      "get": {
        "summary": "Watcher statistics",
        "description": "Returns cumulative counters for processed NOTAMs.",
        "responses": {
          "200": {
            "description": "Current stats snapshot",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Stats" }
              }
            }
          },
          "503": {
            "description": "Stats unavailable"
          }
        }
      }
    },
	    "/": {
	      "get": {
	        "summary": "Service info",
	        "responses": {
	          "200": {
	            "description": "OK",
	            "content": {
	              "application/json": {
	                "schema": {
	                  "type": "object",
	                  "properties": {
	                    "message": { "type": "string" }
	                  },
	                  "required": ["message"]
	                }
	              }
	            }
	          }
	        }
	      }
	    },
	    "/healthz": {
	      "get": {
	        "summary": "Health check",
	        "responses": {
	          "200": {
	            "description": "Service healthy",
	            "content": {
	              "application/json": {
	                "schema": {
	                  "type": "object",
	                  "properties": {
	                    "status": { "type": "string", "example": "ok" }
	                  },
	                  "required": ["status"]
	                }
	              }
	            }
	          }
	        }
	      }
	    },
	    "/current-index": {
	      "get": {
	        "summary": "Get current index",
	        "security": [ { "bearerAuth": [] } ],
	        "responses": {
	          "200": {
	            "description": "Current index cursor info",
	            "content": {
	              "application/json": {
	                "schema": { "$ref": "#/components/schemas/CurrentIndexResponse" }
	              }
	            }
	          },
	          "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
	          "403": { "description": "Forbidden",   "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
	          "500": { "description": "Internal Server Error" }
	        }
	      }
	    },
	    "/listeners": {
	      "get": {
	        "summary": "List listeners",
	        "description": "Returns all registered listeners for the authenticated account.",
	        "security": [ { "bearerAuth": [] } ],
	        "responses": {
	          "200": {
	            "description": "List of listeners",
	            "content": {
	              "application/json": {
	                "schema": { "$ref": "#/components/schemas/ListenersResponse" }
	              }
	            }
	          },
	          "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
	          "403": { "description": "Forbidden",   "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
	          "500": { "description": "Internal Server Error" }
	        }
	      },
	      "post": {
	        "summary": "Create listener",
	        "description": "Registers a webhook URL and filters. Filters use OR within a field and AND across fields. For example, category=['AERODROME','AIRSPACE'] matches either category; combining with notam_icao=['EPWA'] requires both fields to match. Using category=['all'] matches any category. mode defaults to 'prod'. lifecycle.enabled controls separate notifications when previously delivered NOTAMs are later cancelled or replaced. lifecycle.types can narrow those events to cancelled and/or replaced. Each owner can have at most one active listener whose webhook host is trycloudflare.com or a subdomain of it.",
	        "security": [ { "bearerAuth": [] } ],
	        "requestBody": {
	          "required": true,
	          "content": {
	            "application/json": {
	              "schema": { "$ref": "#/components/schemas/ListenerRequest" },
	              "examples": {
	                "aerodromeRunwayAtAirports": {
	                  "summary": "AERODROME runway ops for EPWA or EGLL",
	                  "value": {
	                    "name": "Warsaw & Heathrow Runway Closures",
	                    "webhook_url": "https://example.com/notam-webhook",
	                    "filters": {
	                      "notam_icao": ["EPWA", "EGLL"],
	                      "category": ["AERODROME"],
	                      "subcategory": ["RUNWAY_OPERATIONS"]
	                    },
	                    "emails": ["pilot@example.com", "ops@example.com"]
	                  }
	                },
	                "inactiveListener": {
	                  "summary": "Create an inactive listener (paused)",
	                  "value": {
	                    "webhook_url": "https://example.com/notam-webhook",
	                    "filters": {
	                      "notam_icao": ["KJFK"]
	                    },
	                    "active": false
	                  }
	                }
	              }
	            }
	          }
	        },
	        "responses": {
	          "201": {
	            "description": "Listener created",
	            "content": {
	              "application/json": {
	                "schema": { "$ref": "#/components/schemas/ListenerWithSecret" }
	              }
	            }
	          },
	          "400": { "description": "Bad Request",  "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
	          "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
	          "403": { "description": "Forbidden",   "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
	          "500": { "description": "Internal Server Error" }
	        }
	      }
	    },
	    "/listeners/icao-usage": {
	      "get": {
	        "summary": "Get ICAO usage",
	        "description": "Returns the authenticated user's unique listener ICAO codes together with the configured limit and remaining capacity.",
	        "security": [ { "bearerAuth": [] } ],
	        "responses": {
	          "200": {
	            "description": "Current ICAO usage",
	            "content": {
	              "application/json": {
	                "schema": { "$ref": "#/components/schemas/ListenerICAOUsage" }
	              }
	            }
	          },
	          "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
	          "403": { "description": "Forbidden",   "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
	          "500": { "description": "Internal Server Error" }
	        }
	      }
	    },
	    "/team/alert-email-profile:reload": {
	      "post": {
	        "summary": "Reload team alert email profile",
	        "description": "Reloads the authenticated team's alert email profile. Requires the authenticated principal to belong to a team.",
	        "security": [ { "bearerAuth": [] } ],
	        "responses": {
	          "200": {
	            "description": "Team alert email profile reloaded",
	            "content": {
	              "application/json": {
	                "schema": { "$ref": "#/components/schemas/AlertEmailProfileReloadResponse" }
	              }
	            }
	          },
	          "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
	          "403": { "description": "Forbidden",   "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
	          "500": { "description": "Internal Server Error" }
	        }
	      }
	    },
	    "/listeners/{id}": {
	      "parameters": [
	        { "name": "id", "in": "path", "description": "Listener ID", "required": true, "schema": { "type": "string" } }
	      ],
	      "put": {
	        "summary": "Update listener",
	        "description": "Updates webhook URL and/or filters using the same rules as creation. mode can be changed between 'prod' and 'sandbox'. lifecycle.enabled controls separate notifications when previously delivered NOTAMs are later cancelled or replaced. lifecycle.types can narrow those events to cancelled and/or replaced.",
	        "security": [ { "bearerAuth": [] } ],
	        "requestBody": {
	          "required": true,
	          "content": {
	            "application/json": {
	              "schema": { "$ref": "#/components/schemas/ListenerRequest" }
	            }
	          }
	        },
	        "responses": {
	          "200": {
	            "description": "Listener updated",
	            "content": {
	              "application/json": {
	                "schema": { "$ref": "#/components/schemas/Listener" }
	              }
	            }
	          },
	          "400": { "description": "Bad Request",  "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
	          "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
	          "403": { "description": "Forbidden",   "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
	          "404": { "description": "Not Found",   "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
	          "500": { "description": "Internal Server Error" }
	        }
	      },
	      "delete": {
	        "summary": "Delete listener",
	        "security": [ { "bearerAuth": [] } ],
	        "responses": {
	          "204": { "description": "Deleted" },
	          "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
	          "403": { "description": "Forbidden",   "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
	          "404": { "description": "Not Found",   "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
	          "500": { "description": "Internal Server Error" }
	        }
	      }
	    },
	    "/listeners/{id}/sandbox:send": {
	      "parameters": [
	        { "name": "id", "in": "path", "description": "Listener ID", "required": true, "schema": { "type": "string" } }
	      ],
	      "post": {
	        "summary": "Send sandbox test payload",
	        "description": "Sends a synthetic webhook payload to a sandbox listener. The delivered body matches the production webhook shape with mock NOTAM content. Requires listener mode 'sandbox' and does not consume production shipment credits.",
	        "security": [ { "bearerAuth": [] } ],
	        "requestBody": {
	          "required": false,
	          "content": {
	            "application/json": {
	              "schema": {
	                "type": "object",
	                "properties": {
	                  "notam_id": { "type": "string", "description": "Optional synthetic NOTAM id override." }
	                },
	                "additionalProperties": false
	              }
	            }
	          }
	        },
	        "responses": {
	          "200": {
	            "description": "Sandbox payload sent",
	            "content": {
	              "application/json": {
	                "schema": { "$ref": "#/components/schemas/SandboxSendResponse" }
	              }
	            }
	          },
	          "400": { "description": "Bad Request",  "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
	          "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
	          "403": { "description": "Forbidden",   "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
	          "404": { "description": "Not Found",   "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
	          "500": { "description": "Internal Server Error" }
	        }
	      }
	    },
	    "/webhook-secret:rotate": {
	      "post": {
	        "summary": "Rotate webhook secret",
	        "description": "Generates a new webhook secret for the authenticated user. The previous secret remains valid for a short overlap window.",
	        "security": [ { "bearerAuth": [] } ],
	        "responses": {
	          "200": {
	            "description": "Webhook secret rotated",
	            "content": {
	              "application/json": {
	                "schema": {
	                  "type": "object",
	                  "properties": {
	                    "webhook_secret": { "type": "string" }
	                  }
	                }
	              }
	            }
	          },
	          "400": { "description": "Bad Request",  "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
	          "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
	          "403": { "description": "Forbidden",   "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
	          "404": { "description": "Not Found",   "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
	          "500": { "description": "Internal Server Error" }
	        }
	      }
	    }
	    ,
	    "/webhook-secret": {
	      "get": {
	        "summary": "Get webhook secret (masked)",
	        "description": "Returns the masked webhook signing secret for the authenticated user.",
	        "security": [ { "bearerAuth": [] } ],
	        "responses": {
	          "200": {
	            "description": "Masked webhook secret",
	            "content": {
	              "application/json": {
	                "schema": {
	                  "type": "object",
	                  "properties": {
	                    "webhook_secret_masked": { "type": "string" }
	                  }
	                }
	              }
	            }
	          },
	          "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
	          "403": { "description": "Forbidden",   "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
	          "500": { "description": "Internal Server Error" }
	        }
	      }
	    },
	    "/webhook-logs": {
	      "get": {
	        "summary": "List recent webhook logs",
	        "description": "Returns the last 5 successful and last 5 failed webhook delivery logs for the authenticated user.",
	        "security": [ { "bearerAuth": [] } ],
	        "responses": {
	          "200": {
	            "description": "Recent webhook delivery logs",
	            "content": {
	              "application/json": {
	                "schema": { "$ref": "#/components/schemas/WebhookLogsResponse" }
	              }
	            }
	          },
	          "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
	          "403": { "description": "Forbidden",   "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
	          "500": { "description": "Internal Server Error" }
	        }
	      }
	    }
	  },
	  "components": {
	    "securitySchemes": {
	      "bearerAuth": {
	        "type": "http",
	        "scheme": "bearer"
	      }
	    },
	    "schemas": {
	      "Cursor": {
	        "type": "object",
	        "properties": {
	          "id": { "type": "string" },
	          "created_at": { "type": "string", "format": "date-time" }
	        },
	        "required": ["id", "created_at"]
	      },
	      "CurrentIndexResponse": {
	        "type": "object",
	        "properties": {
	          "has_cursor": { "type": "boolean" },
	          "cursor": { "$ref": "#/components/schemas/Cursor" }
	        },
	        "required": ["has_cursor"]
	      },
	      "ListenerMode": {
	        "type": "string",
	        "enum": ["prod", "sandbox"],
	        "description": "Listener delivery mode. 'prod' receives live matching events. 'sandbox' is for manual test sends only."
	      },
	      "ListenerMetadata": {
	        "type": "object",
	        "properties": {
	          "notams_shipped": { "type": "integer", "minimum": 0, "description": "Cumulative number of successful production deliveries sent by this listener." },
	          "consecutive_delivery_failures": { "type": "integer", "minimum": 0, "description": "Current streak of consecutive failed webhook delivery attempts. A successful webhook delivery resets this value to zero. Email delivery attempts do not affect it." },
	          "auto_paused_at": { "type": "string", "format": "date-time", "description": "Timestamp when the listener was automatically deactivated after too many consecutive webhook delivery failures." }
	        },
	        "required": ["notams_shipped", "consecutive_delivery_failures"]
	      },
	      "Lifecycle": {
	        "type": "object",
	        "properties": {
	          "enabled": { "type": "boolean", "description": "When true, the listener may receive additional notifications for NOTAMs that were previously delivered successfully and are later cancelled (NOTAMC) or replaced (NOTAMR). lifecycle.types can narrow which events are delivered. In lifecycle payloads, notam is the NOTAMC/NOTAMR itself and change.changed_notam_id identifies the previously delivered NOTAM that changed. Lifecycle deliveries do not increment shipment credits." },
	          "types": { "type": "array", "items": { "type": "string", "enum": ["CANCELLED", "REPLACED"] }, "description": "Optional lifecycle event types to receive once lifecycle.enabled is true. If omitted, both CANCELLED and REPLACED are eligible." }
	        },
	        "required": ["enabled"]
	      },
	      "LifecycleRequest": {
	        "type": "object",
	        "properties": {
	          "enabled": { "type": "boolean", "default": false, "description": "Enable additional notifications for NOTAMs previously delivered successfully when they are later cancelled (C) or replaced (R). lifecycle.types can narrow which events are delivered. In lifecycle payloads, notam is the NOTAMC/NOTAMR itself and change.changed_notam_id identifies the previously delivered NOTAM that changed. Lifecycle deliveries do not increment shipment credits." },
	          "types": { "type": "array", "items": { "type": "string", "enum": ["CANCELLED", "REPLACED"] }, "description": "Optional lifecycle event types to receive when lifecycle.enabled is true. If omitted, both CANCELLED and REPLACED are eligible." }
	        },
	        "additionalProperties": false
	      },
	      "Listener": {
	        "type": "object",
	        "properties": {
	          "id": { "type": "string" },
	          "team_id": { "type": "string", "description": "Team context when the listener was created or updated by a team-authenticated principal. Team-level alert email profiles apply only when this value is present." },
	          "name": { "type": "string", "maxLength": 100, "description": "Optional human-readable name for the listener (max 100 characters)." },
	          "webhook_url": { "type": "string", "format": "uri", "description": "Destination HTTPS/HTTP endpoint for notifications. Must be a public URL, not localhost or private network ranges. Each owner can have at most one active trycloudflare.com webhook listener." },
	          "emails": { "type": "array", "maxItems": 3, "items": { "type": "string", "format": "email" }, "description": "Optional email recipients for notification delivery." },
		          "filters": { "$ref": "#/components/schemas/Filters" },
		          "lifecycle": { "$ref": "#/components/schemas/Lifecycle" },
		          "metadata": { "$ref": "#/components/schemas/ListenerMetadata" },
		          "active": { "type": "boolean", "description": "Whether the listener is active and will receive notifications." },
		          "mode": { "$ref": "#/components/schemas/ListenerMode" },
	          "created_at": { "type": "string", "format": "date-time" },
	          "updated_at": { "type": "string", "format": "date-time" }
	        },
	        "required": ["id", "filters", "lifecycle", "metadata", "active", "mode", "created_at", "updated_at"]
	      },
	      "ListenerWithSecret": {
	        "allOf": [
	          { "$ref": "#/components/schemas/Listener" },
	          {
	            "type": "object",
	            "properties": {
	              "webhook_secret": { "type": "string", "description": "Webhook signing secret (returned once on creation/rotation)." }
	            }
	          }
	        ]
	      },
	      "ListenersResponse": {
	        "type": "object",
	        "properties": {
	          "listeners": { "type": "array", "items": { "$ref": "#/components/schemas/Listener" } }
	        },
	        "required": ["listeners"]
	      },
	      "ListenerICAOUsage": {
	        "type": "object",
	        "properties": {
	          "icao_codes": {
	            "type": "array",
	            "items": { "type": "string" },
	            "description": "Unique ICAO codes currently used by the authenticated user's listeners."
	          },
	          "used": { "type": "integer", "minimum": 0 },
	          "limit": { "type": "integer", "minimum": 0 },
	          "remaining": { "type": "integer" }
	        },
	        "required": ["icao_codes", "used", "limit", "remaining"]
	      },
	      "AlertEmailProfileSections": {
	        "type": "object",
	        "properties": {
	          "raw_icao_message": { "type": "boolean", "default": false, "description": "When true, standard alert emails include the raw ICAO message text." }
	        },
	        "additionalProperties": false
	      },
	      "AlertEmailProfile": {
	        "type": "object",
	        "properties": {
	          "template": { "type": "string", "default": "standard", "description": "Alert email template. Defaults to 'standard'." },
	          "sections": { "$ref": "#/components/schemas/AlertEmailProfileSections" }
	        }
	      },
	      "AlertEmailProfileReloadResponse": {
	        "type": "object",
	        "properties": {
	          "team_id": { "type": "string" },
	          "alert_email_profile": { "$ref": "#/components/schemas/AlertEmailProfile" }
	        },
	        "required": ["team_id", "alert_email_profile"]
	      },
	      "WebhookLog": {
	        "type": "object",
	        "properties": {
	          "listener_id": { "type": "string" },
	          "webhook_url": { "type": "string", "format": "uri" },
	          "notam_id": { "type": "string" },
	          "status": { "type": "string", "enum": ["success", "error"] },
	          "error": { "type": "string" },
	          "created_at": { "type": "string", "format": "date-time" }
	        },
	        "required": ["listener_id", "webhook_url", "status", "created_at"]
	      },
	      "WebhookLogsResponse": {
	        "type": "object",
	        "properties": {
	          "success": { "type": "array", "items": { "$ref": "#/components/schemas/WebhookLog" } },
	          "errors": { "type": "array", "items": { "$ref": "#/components/schemas/WebhookLog" } }
	        },
	        "required": ["success", "errors"]
	      },
	      "ListenerRequest": {
	        "type": "object",
	        "properties": {
	          "name": { "type": "string", "maxLength": 100, "description": "Optional human-readable name for the listener (max 100 characters)." },
	          "webhook_url": { "type": "string", "format": "uri", "description": "Destination HTTPS/HTTP endpoint for notifications. Must be a public URL, not localhost or private network ranges. Each owner can have at most one active trycloudflare.com webhook listener. Required when emails are omitted or empty." },
	          "emails": { "type": "array", "maxItems": 3, "items": { "type": "string", "format": "email" }, "description": "Optional email recipients for notification delivery. Required when webhook_url is omitted." },
		          "filters": { "$ref": "#/components/schemas/Filters" },
		          "lifecycle": { "$ref": "#/components/schemas/LifecycleRequest" },
		          "active": { "type": "boolean", "default": true, "description": "Whether the listener is active. Defaults to true if not provided. Set to false to temporarily disable notifications without deleting the listener." },
		          "mode": { "$ref": "#/components/schemas/ListenerMode", "default": "prod" }
	        },
	        "required": ["filters"]
	      },
	      "SandboxSendResponse": {
	        "type": "object",
	        "properties": {
	          "listener_id": { "type": "string" },
	          "mode": { "$ref": "#/components/schemas/ListenerMode" },
	          "notam_id": { "type": "string" },
	          "sent_at": { "type": "string", "format": "date-time" }
	        },
	        "required": ["listener_id", "mode", "notam_id", "sent_at"]
	      },
	      "AffectedElementFilter": {
	        "type": "object",
	        "description": "Affected-element filter.",
	        "properties": {
	          "effect": { "type": "string" },
	          "type": { "type": "string" },
	          "subtype": { "type": "string" },
	          "identifier": { "type": "string" },
	          "applies_to": {
	            "type": "object",
	            "description": "Optional applicability filters.",
	            "additionalProperties": {
	              "oneOf": [
	                { "type": "string" },
	                { "type": "array", "items": { "type": "string" } }
	              ]
	            }
	          },
	          "changes": {
	            "type": "array",
	            "items": { "$ref": "#/components/schemas/AffectedElementChangeFilter" },
	            "minItems": 1
	          }
	        },
	        "additionalProperties": false
	      },
	      "AffectedElementChangeValuePredicate": {
	        "type": "object",
	        "description": "Value predicate for an affected-element change.",
	        "properties": {
	          "operator": { "type": "string" },
	          "value": { "type": "number" },
	          "min": { "type": "number" },
	          "max": { "type": "number" },
	          "unit": { "type": "string" }
	        },
	        "required": ["operator"],
	        "additionalProperties": false
	      },
	      "AffectedElementChangeFilter": {
	        "type": "object",
	        "description": "Affected-element change filter.",
	        "properties": {
	          "subject": { "type": "string" },
	          "from": { "$ref": "#/components/schemas/AffectedElementChangeValuePredicate" },
	          "to": { "$ref": "#/components/schemas/AffectedElementChangeValuePredicate" }
	        },
	        "additionalProperties": false
	      },
	      "Filters": {
	        "type": "object",
	        "description": "Listener filter fields. Values are case-insensitive. Within a field, any value may match (OR). Across fields, all fields must match (AND). For category, 'all' matches any category. notam_type applies to normal deliveries and accepts only N/R. Relative time_windows use UTC schedule windows; absolute time_windows use date-time bounds.",
        "properties": {
          "notam_icao": {
            "type": "array",
            "items": { "type": "string" },
            "description": "ICAO airport codes to match (e.g., EPWA, EGLL)."
          },
          "notam_type": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": ["N", "R"]
            },
            "description": "NOTAM type for normal deliveries. Allowed values: N (NOTAMN), R (NOTAMR). Selecting R matches replacement NOTAMs themselves; it does not include the previous NOTAM. Lifecycle cancellation/replacement notifications are configured separately via lifecycle. NOTAMC (C) is not a valid filter value."
          },
          "airport_type": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "small_airport","medium_airport","large_airport"
              ]
            },
            "description": "Airport size to match when ICAO codes are omitted."
          },
          "aircraft_type": {
            "type": "array",
            "items": { "type": "string" },
            "description": "Aircraft type filters."
          },
          "aircraft_designator": {
            "type": "array",
            "items": { "type": "string" },
            "description": "Aircraft designator filters."
          },
          "aircraft_family": {
            "type": "array",
            "items": { "type": "string" },
            "description": "Aircraft family filters."
          },
          "category": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "all",
                "AERODROME","AIRSPACE","NAVIGATION","COMMUNICATION","OPERATIONS","OBSTACLES","ADMINISTRATIVE","WEATHER","SAFETY","OTHER"
              ]
            },
            "description": "Top-level NOTAM categories. Use 'all' to match any category."
          },
          "subcategory": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "RUNWAY_OPERATIONS","TAXIWAY_OPERATIONS","APRON_OPERATIONS","AIRPORT_MAINTENANCE","LIGHTING_SYSTEMS","FIRE_AND_RESCUE_SERVICES","OTHER",
                "AIRSPACE_RESTRICTIONS","AIRSPACE_CHANGES","FLOW_CONTROL","MILITARY_ACTIVITY","SPECIAL_USE_AIRSPACE","TEMPORARY_FLIGHT_RESTRICTIONS",
                "NAVIGATION_AID_STATUS","INSTRUMENT_LANDING_SYSTEMS","APPROACH_PROCEDURES","DEPARTURE_PROCEDURES","ROUTE_CHANGES","CHARTS",
                "RADIO_FREQUENCY_CHANGES","COMMUNICATION_EQUIPMENT_STATUS","ATS_COMMUNICATION","RADAR_SERVICES","SURVEILLANCE_SYSTEMS",
                "FLIGHT_PROCEDURES","OPERATING_RESTRICTIONS","SEARCH_AND_RESCUE","EMERGENCY_SERVICES","UAS_DRONE_OPERATIONS","SPECIAL_OPERATIONS",
                "CRANE_OPERATIONS","OBSTACLE_LIGHTING","CONSTRUCTION_ACTIVITY","TEMPORARY_OBSTACLES",
                "NOTAM_MANAGEMENT","PUBLICATION_UPDATES","OFFICE_HOURS","CONTACT_INFORMATION","CHECKLISTS",
                "WEATHER_SERVICES","WEATHER_WARNINGS","SNOWTAM","METEOROLOGICAL_EQUIPMENT",
                "SECURITY_MEASURES","SAFETY_ADVISORIES",
                "WILDLIFE_HAZARDS","BIRD_ACTIVITY"
              ]
            },
            "description": "Filter on NOTAM subcategory."
          },
          "qcode": {
            "type": "array",
            "items": {
              "type": "string",
              "pattern": "^Q(?:[A-Z]{4}|[A-Z]{2}\\*\\*|\\*\\*[A-Z]{2})$"
            },
            "description": "Q-code filters to match. Use a full ICAO Q-code such as QMRLC for an exact match, QWW** to match the subject portion, or Q**LC to match the condition portion. Other wildcard placements are rejected."
          },
          "time_windows": {
            "type": "array",
            "maxItems": 15,
            "items": {
              "type": "object",
              "properties": {
                "type": {
                  "type": "string",
                  "enum": ["relative", "absolute"],
                  "description": "Window type. Defaults to relative when omitted. Use absolute with start_at/end_at."
                },
                "days": {
                  "type": "array",
                  "items": { "type": "string", "enum": ["MO", "TU", "WE", "TH", "FR", "SA", "SU"] },
                  "description": "Relative windows only: optional day-of-week list (UTC). If omitted, any day matches."
                },
                "start": {
                  "type": "string",
                  "pattern": "^([01]?[0-9]|2[0-3]):[0-5][0-9]$",
                  "description": "Relative windows only: start time (UTC) in 24h format."
                },
                "end": {
                  "type": "string",
                  "pattern": "^(?:([01]?[0-9]|2[0-3]):[0-5][0-9]|24:00)$",
                  "description": "Relative windows only: end time (UTC) in 24h format. May be earlier than start to indicate overnight."
                },
                "start_at": {
                  "type": "string",
                  "format": "date-time",
                  "description": "Absolute windows only: inclusive lower bound as a date-time string."
                },
                "end_at": {
                  "type": "string",
                  "format": "date-time",
                  "description": "Absolute windows only: exclusive upper bound as a date-time string."
                }
              },
              "additionalProperties": false
            },
            "description": "Time filters. Relative windows combine days and/or a UTC time range. Absolute windows use start_at/end_at date-time bounds."
          },
          "affected_element": {
            "type": "array",
            "description": "Affected-element filters.",
            "items": { "$ref": "#/components/schemas/AffectedElementFilter" }
          }
        },
        "additionalProperties": false
      },
      "Error": {
	        "type": "object",
	        "properties": {
	          "error": { "type": "string" }
	        },
	        "required": ["error"]
      },
      "Stats": {
        "type": "object",
        "properties": {
          "start_time": { "type": "string", "format": "date-time" },
          "total": { "type": "integer", "format": "int64" },
          "categories": {
            "type": "object",
            "additionalProperties": { "type": "integer", "format": "int64" }
          }
        },
        "required": ["start_time", "total", "categories"]
      }
	    }
	  }
	}