> For the complete documentation index, see [llms.txt](https://skymerse.gitbook.io/notamify-api/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://skymerse.gitbook.io/notamify-api/notam-watcher/notam-watcher-api.md).

# NOTAM Watcher API

The **Notamify Watcher Service** allows automatic retrieval of new interpretations in Notamify based on configurable filters.\
The service supports listener management via webhooks, enabling applications to subscribe to NOTAM updates by airport code, category, subcategory, or specific NOTAM identifiers.

The Watcher service charges credits based on the number of NOTAM deliveries sent to registered listeners:

* **Default: 1 credit = 5 shipments** — 1 credit is deducted for every 5 NOTAMs shipped to your listeners.
* An account-specific shipments-per-credit allowance may override the default rate.
* [Lifecycle ](/notamify-api/notam-watcher/watcher-api-webhook-messages.md#lifecycle-message-example)messages are not chargeable.
* If the user has no credits remaining, further shipments are blocked until credits are topped up.

An account can have up to 15 listeners.

If you specified `webhook_url` the service will provide each new notam for the filter as described in [Watcher API Webhook messages](/notamify-api/notam-watcher/watcher-api-webhook-messages.md).

Watcher API expects to receive a `2xx` success response, such as `200`, after delivering a webhook message. 25 consecutive failed deliveries will pause the listener by setting `active: false`.

#### Python SDK Example

The [Notamify Python SDK](https://github.com/skymerse/notamify-sdk-python) provides typed methods for all Watcher operations:

```python
from notamify_sdk import NotamifyClient

client = NotamifyClient(token="YOUR_API_KEY")

# List all listeners
listeners = client.list_listeners()
for listener in listeners:
    print(f"{listener.name} ({listener.id}) — active: {listener.active}")

# Create a listener with filters
listener = client.create_listener(
    name="JFK Runway Monitor",
    webhook_url="https://your-server.com/webhooks/notamify",
    filters={
        "notam_icao": ["KJFK"],
        "category": ["RUNWAY"],
    },
    lifecycle_enabled=True,
    mode="prod",
)
print(f"Created listener: {listener.id}")

# Update a listener
updated = client.update_listener(
    listener.id,
    filters={
        "notam_icao": ["KJFK", "KEWR"],
        "category": ["AERODROME", "OBSTACLES"],
    },
)

# Delete a listener
client.delete_listener(listener.id)

# Sandbox testing — trigger a test delivery
result = client.send_sandbox_message(listener.id)
print(f"Sandbox delivery: {result}")
```

Use [Notamify API](/notamify-api/basics/authentication-guide.md) key to validate the requests. Received webhook messages should be authenticated via Webhook Secret. Read more: [Webhook Security](/notamify-api/notam-watcher/webhook-security.md)

## List listeners

> Returns all registered listeners for the authenticated account.

```json
{"openapi":"3.1.0","info":{"title":"Notamify Watcher API","version":"1.0.0"},"servers":[{"url":"https://watcher.notamify.com"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"ListenersResponse":{"type":"object","properties":{"listeners":{"type":"array","items":{"$ref":"#/components/schemas/Listener"}}},"required":["listeners"]},"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"]},"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},"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},"AffectedElementChangeFilter":{"type":"object","description":"Affected-element change filter.","properties":{"subject":{"type":"string"},"from":{"$ref":"#/components/schemas/AffectedElementChangeValuePredicate"},"to":{"$ref":"#/components/schemas/AffectedElementChangeValuePredicate"}},"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},"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"]},"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"]},"ListenerMode":{"type":"string","enum":["prod","sandbox"],"description":"Listener delivery mode. 'prod' receives live matching events. 'sandbox' is for manual test sends only."},"Error":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}},"paths":{"/listeners":{"get":{"summary":"List listeners","description":"Returns all registered listeners for the authenticated account.","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"}}}}}}
```

## Create listener

> 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.

```json
{"openapi":"3.1.0","info":{"title":"Notamify Watcher API","version":"1.0.0"},"servers":[{"url":"https://watcher.notamify.com"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"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"]},"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},"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},"AffectedElementChangeFilter":{"type":"object","description":"Affected-element change filter.","properties":{"subject":{"type":"string"},"from":{"$ref":"#/components/schemas/AffectedElementChangeValuePredicate"},"to":{"$ref":"#/components/schemas/AffectedElementChangeValuePredicate"}},"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},"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},"ListenerMode":{"type":"string","enum":["prod","sandbox"],"description":"Listener delivery mode. 'prod' receives live matching events. 'sandbox' is for manual test sends only."},"ListenerWithSecret":{"allOf":[{"$ref":"#/components/schemas/Listener"},{"type":"object","properties":{"webhook_secret":{"type":"string","description":"Webhook signing secret (returned once on creation/rotation)."}}}]},"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"]},"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"]},"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"]},"Error":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}},"paths":{"/listeners":{"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.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListenerRequest"}}}},"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"}}}}}}
```

## Update listener

> 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.

```json
{"openapi":"3.1.0","info":{"title":"Notamify Watcher API","version":"1.0.0"},"servers":[{"url":"https://watcher.notamify.com"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"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"]},"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},"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},"AffectedElementChangeFilter":{"type":"object","description":"Affected-element change filter.","properties":{"subject":{"type":"string"},"from":{"$ref":"#/components/schemas/AffectedElementChangeValuePredicate"},"to":{"$ref":"#/components/schemas/AffectedElementChangeValuePredicate"}},"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},"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},"ListenerMode":{"type":"string","enum":["prod","sandbox"],"description":"Listener delivery mode. 'prod' receives live matching events. 'sandbox' is for manual test sends only."},"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"]},"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"]},"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"]},"Error":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}},"paths":{"/listeners/{id}":{"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.","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 /listeners/{id}

> Delete listener

```json
{"openapi":"3.1.0","info":{"title":"Notamify Watcher API","version":"1.0.0"},"servers":[{"url":"https://watcher.notamify.com"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}},"paths":{"/listeners/{id}":{"delete":{"summary":"Delete listener","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"}}}}}}
```
