notamify-sdk (Python)
OpenClaw and agents ready. The notamify CLI ships an agent skill (notamify skill install) with OpenClaw metadata, prints JSON when piped, and uses stable exit codes, so Claude Code, Codex, OpenClaw and other agents can use it directly.
Python SDK and command line for Notamify public APIs:
- Notamify API v2 (
https://api.notamify.com/api/v2) - Watcher API (
https://watcher.notamify.com)
Which Notamify surface to use:
| You are | Use |
|---|---|
| Writing Python that calls Notamify | this SDK: pip install notamify-sdk |
| At a terminal, in scripts or CI, or a coding agent with a shell (Claude Code, Codex) | the notamify CLI: uv tool install notamify |
| A chat app without a shell (ChatGPT, Claude web and desktop) | the hosted MCP server: https://mcp.notamify.com/mcp |
Command line
uv tool install notamify # or: pipx install notamify
notamify --version
uv tool install and pipx install put the notamify command in ~/.local/bin. If your shell then reports command not found: notamify, add that directory to your PATH with uv tool update-shell (or pipx ensurepath) and open a new terminal. Without installing anything, uvx notamify ... runs the latest release.
notamify auth login # sign in with your Notamify account (browser)
notamify auth login --api-key # or use an API key from https://notamify.com/api-manager
notamify notams active EPWA EGLL --start now --hours 24
notamify affected EPWA --affected CLOSED:RUNWAY
notamify briefing flight create --origin EPWA@now/+2h --destination EGLL@+2h/+3h --aircraft B738 --wait
notamify watcher listeners list
notamify webhook listen --tunnel
notamify commands # every command, credit cost and exit code
notamify skill install # agent skill for Claude Code (--dir for others)
Output is text on a terminal and JSON when piped. Errors are written to stderr, with stable exit codes. Commands that may spend more than one credit, or that change Watcher listeners, need --yes; --dry-run previews a request. See cli/README.md.
The CLI code lives in this package (notamify_sdk.cli, also runnable as python -m notamify_sdk.cli); the notamify distribution in cli/ only installs the command.
Features
- Typed API client with one auth token
- Pydantic response/request models
- Pager-style NOTAM listing via
client.notams.*with item iteration andpager.pages - Supported NOTAM endpoints:
GET /notamsGET /notams/rawGET /notams/nearbyGET /notams/archiveGET /notams/recently-expiredGET /notams/{id}GET /notams/briefing/simplePOST /notams/briefingGET /notams/briefing/{uuid}POST /notams/prioritisation
- Watcher listener management + webhook logs/secrets
- Listener
modesupport (proddefault,sandboxfor test-only listeners) - Listener lifecycle support via
lifecycle.enabledandlifecycle.types - Sandbox test delivery endpoint (
POST /listeners/{id}/sandbox:send) - Webhook signature verification (
X-Notamify-Signature) - Typed webhook event models for
interpretationandlifecyclepayloads - Embedded receiver + cloudflared helper for local webhook testing
- Strict receiver mode fails fast when webhook secret is missing
Install
pip install notamify-sdk
Or with uv:
uv add notamify-sdk
For contributors working from a source checkout:
uv sync
Configuration
Environment variables (highest priority):
NOTAMIFY_TOKENNOTAMIFY_API_BASE_URLNOTAMIFY_WATCHER_BASE_URLNOTAMIFY_WEBHOOK_SECRETNOTAMIFY_CONFIG_FILE
Default config file: ~/.config/notamify/config.json
NotamifyClient() without arguments reads the token and base URLs from these sources.
Quick start
Get active NOTAMs
from datetime import datetime, timedelta, timezone
from notamify_sdk import NotamifyClient, ActiveNotamsQuery
client = NotamifyClient() # or NotamifyClient(token="YOUR_API_KEY")
query = ActiveNotamsQuery(
location=["KJFK", "KLAX"],
starts_at=datetime.now(timezone.utc),
ends_at=datetime.now(timezone.utc) + timedelta(days=1),
)
for notam in client.notams.active(query, per_page=30):
print(notam.notam_number, notam.interpretation.excerpt if notam.interpretation else notam.message)
One NOTAM, recently expired NOTAMs, airport briefing
notam = client.get_notam("NOTAM_ID")
expired = client.get_recently_expired_notams({"location": ["EPWA"]})
briefing = client.generate_airport_briefing({"location": "EPWA"})
print(briefing.summary)
Flight briefing
A failed job is returned with status == "failed", so a polling loop can stop on it.
import time
job = client.create_briefing({
"locations": [
{"location": "EPWA", "type": "origin", "starts_at": "2026-11-09T08:00:00Z", "ends_at": "2026-11-09T10:00:00Z"},
{"location": "EGLL", "type": "destination", "starts_at": "2026-11-09T10:30:00Z", "ends_at": "2026-11-09T13:00:00Z"},
],
"aircraft_type": "B738",
})
while (status := client.get_briefing_status(job.uuid)).status.value in ("pending", "processing"):
time.sleep(3)
print(status.status.value, status.response.briefing.text if status.response else "")
Watcher flow
# Watcher sandbox flow
listener = client.create_listener(
"https://example.trycloudflare.com/webhooks/notamify",
mode="sandbox",
lifecycle={"enabled": False},
)
print(listener.webhook_secret)
sandbox_result = client.send_sandbox_message(listener.id, "SANDBOX-NOTAM-1")
print(sandbox_result.notam_id)
# Change some fields and keep the rest. update_listener replaces the whole listener.
client.patch_listener(listener.id, filters={"notam_icao": ["EPWA"]})
The notamify_watcher_sdk package is deprecated and will be removed in 1.0; import from notamify_sdk.
Pagination
The SDK exposes two NOTAM access styles:
client.get_active_notams(...),client.get_raw_notams(...),client.get_nearby_notams(...), andclient.get_historical_notams(...)return a singleNotamListResultpage.client.notams.active(...),client.notams.raw(...),client.notams.nearby(...), andclient.notams.historical(...)return a pager that fetches all pages lazily as you iterate.
Use the pager when you want all NOTAMs across pages:
pager = client.notams.active(
{"location": ["KJFK", "KLAX"]},
per_page=30,
)
for notam in pager:
print(notam.id)
If you want everything in memory at once, materialize the pager with list(...):
all_notams = list(
client.notams.active(
{"location": ["KJFK", "KLAX"]},
per_page=30,
)
)
If you need page metadata such as page, per_page, or total_count, iterate over pager.pages:
pager = client.notams.active(
{"location": ["KJFK", "KLAX"]},
per_page=30,
)
for page in pager.pages:
print(page.page, page.total_count, len(page.notams))
Local Webhook Testing
The example scripts live in the repository and source distribution under examples/.
They are intended to be run from a source checkout or source distribution, not from an installed wheel alone.
- Production: implement the webhook endpoint in your own application code.
- Verify
X-Notamify-SignatureusingNOTAMIFY_WEBHOOK_SECRET. - Production watcher deliveries include
kind,event_id, andnotam. - Lifecycle watcher deliveries also include
change.changed_notam_idfor the original NOTAM that was cancelled or replaced. - Local development: expose your local app endpoint with
cloudflared, then set watcherwebhook_urlto that tunnel URL. - Sandbox test sends use the same webhook payload DTO as production sends, with mock NOTAM content.
Prerequisite: cloudflared must be installed and available in PATH.
export NOTAMIFY_TOKEN="your_notamify_token"
export LOCAL_APP_URL="http://127.0.0.1:8080/webhooks/notamify"
uv run python ./examples/local_service_run.py
Examples
examples/service_receiver.py: minimal production-style webhook receiverexamples/local_service_run.py: cloudflared tunnel + sandbox delivery flowexamples/notams_fetch.py: straightforward NOTAM query examplesexamples/README.md: setup notes and sample payloads
Development
make test # unit tests, CLI tests and the API spec coverage check
make spec # refresh tests/fixtures/openapi.json from the live API
uv tool install --editable ./cli # put this checkout's `notamify` command on PATH
tests/test_spec_coverage.py checks that the SDK covers every operation, parameter and field in the public OpenAPI document. The SDK may model fields the document does not list; the check only fails when the SDK is missing something the document has.
Releasing
notamify-sdk and notamify are released together from one vX.Y.Z tag. Bump version in pyproject.toml and cli/pyproject.toml, and the notamify-sdk== pin in cli/pyproject.toml; the release workflow checks that all three match the tag.
License
MIT
Metadata
Release files for notamify-sdk 0.4.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| notamify_sdk-0.4.0.tar.gz | 99.0 kB | With provenance | Details for notamify_sdk-0.4.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| notamify_sdk-0.4.0-py3-none-any.whl | Python 3 | none | any | Details for notamify_sdk-0.4.0-py3-none-any.whl |
Total release size: 174.4 kB
Release files / notamify_sdk-0.4.0.tar.gz
| Download URL | notamify_sdk-0.4.0.tar.gz |
|---|---|
| Size | 99.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
435529544491b618b85ee38026c9e731f8d40355c1d103d7ca93b037efe6e41c
|
|
BLAKE2b-256 checksum How to use checksums |
948bad88a9cde7b18429b718298becb80edcd928d06664ecefed8d89e2d4abc6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 8, 2026.
Transparency logRelease files / notamify_sdk-0.4.0-py3-none-any.whl
| Download URL | notamify_sdk-0.4.0-py3-none-any.whl |
|---|---|
| Size | 75.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
ddf836984f0d1038fd48c80065b1cf529ad0c63a266f621a73df5dc354ada44d
|
|
BLAKE2b-256 checksum How to use checksums |
77a9c9e19c728da4fdb6c52bdae09c7078e235a9459ebbe60a80ddd298e8f261
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 8, 2026.
Transparency logSecurity for notamify-sdk 0.4.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
Both files in this release have been uploaded with provenance metadata.
Attestation for notamify_sdk-0.4.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 8, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.