Skip to content
Gauge

ax-check.com

Palo Alto Networks

paloaltonetworks.com

ax-check.com

Checked 5 November 2026

B

76/100

Agents need your login

Docs guide agents well, but pricing stays a guessing game

The homepage links to a well-organized docs index and quickstart, but no pricing page was ever found, forcing agents to estimate costs from outside knowledge.

2 fixes to start with

Concrete changes, backed by what we found.

Onboarding

Give agents a clear login handoff and a way to resume setup.

Agents cannot progress through onboarding without human help. Provide an agent-accessible path through authentication and setup.

Docs

Return Markdown when clients request text/markdown.

Homepage returned text/html for a text/markdown request; no Markdown representation served.

Recorded coding sessions

Same task, 3 models, no paloaltonetworks.com account. Recorded 5 November 2026 on Pi.

3 recorded · 1m 25s

1m 25s · recorded

Session findings

Select a finding to see it in context.

piv0.84.2
modelQwen 3.8 Maxcwd/sandbox/repo
Help me build a simple example using Palo Alto Networks. Tell me how pricing works, and briefly tell me whether this product will be easy for you to manage. Let me know if you get blocked. If this product has no developer workflow you can act on, say so plainly and stop. Stay light: use the hosted product through its SDK or API. Do not start local service stacks or wait for long-running commands; if the quickstart requires either, say so plainly and stop.
Thinking…

The user is asking for a "simple example using Palo Alto Networks." That's vague — Palo Alto Networks has lots of products. Let me check the repo context first.

Let me look at the working directory.

pwd; ls -la; cat README* 2>/dev/null | head -50
/sandbox/repo
/sandbox/repo
total 16
drwxr-xr-x 3 root root 4096 Sep 18 08:00 .
drwxr-xr-x 7 root root 4096 Nov  5 16:04 ..
drwxr-xr-x 8 root root 4096 Sep 24 20:05 .git
-rw-r--r-- 1 root root  408 Sep 18 08:00 .gitignore
env | grep -i -E "PI_|PAN|PALO|API_KEY|TOKEN" | sed 's/=.\{6,\}/=<redacted>/'
PI_CODING_AGENT=true
PI_CODING_AGENT=true
PI_REASONING_LEVEL=<redacted>
PI_SESSION_FILE=<redacted>
PI_PROVIDER=<redacted>
PI_MODEL=<redacted>
PI_SESSION_ID=<redacted>
PI_GATEWAY_API_KEY=<redacted>
Thinking…

Empty repo. No Palo Alto credentials. Let me check network access and what "Palo Alto Networks" developer workflow means. PAN products: PAN-OS (firewall OS, pan-os-python SDK / REST API), Prisma Access, Cortex XSOAR, Strata Cloud Manager.

Key question: is there a developer workflow I can act on without credentials? There's pan-os-python SDK, and PAN-OS REST API. But there's no live firewall and no hosted sandbox API accessible without credentials.

Let me check if network access exists (pip install pan-os-python), and check whether there's any public API that works without credentials. Actually, PAN does have a free developer sandbox? PAN-OS has "Strata Cloud Manager" with API. There's also the PAN Developer API for threat intelligence... Let me test network reachability quickly.

cd /sandbox/repo && timeout 25 pip download pan-os-python -d /tmp/x --no-deps -q 2>&1 | tail -5; echo "---pypi exit $?"; timeout 20 curl -sS -o /dev/null -w "%{http_code}\n" https://pypi.org/simple/ 2>&1
[notice] A new release of pip is available: 26.2.1 -> 26.3

[notice] A new release of pip is available: 26.2.1 -> 26.3
[notice] To update, run: /opt/freestyle/python/bin/python3 -m pip install --upgrade pip
---pypi exit 0
200
timeout 20 curl -sS -o /dev/null -w "pan.dev:%{http_code}\n" https://pan.dev/ ; timeout 20 curl -sS -o /dev/null -w "api.scm:%{http_code}\n" https://api.scm.paloaltonetworks.com/ 2>&1
Failedpan.dev:200
pan.dev:200
curl: (6) Could not resolve host: api.scm.paloaltonetworks.com
api.scm:000


Command exited with code 6
Thinking…

PyPI is reachable (I could download pan-os-python). pan.dev reachable. The actual PAN cloud API endpoint (api.scm.paloaltonetworks.com) does not resolve — so no live API access, and there are no credentials anyway.

So: the developer workflow exists (pan-os-python SDK, PAN-OS REST API, Strata Cloud Manager API), but I can't actually run it — no firewall, no API key, and the hosted endpoints are unreachable from this sandbox.

The user asked: "Let me know if you get blocked." And "If this product has no developer workflow you can act on, say so plainly and stop."

There IS a developer workflow, but I can't act on it live. What can I do? I can build a simple, working example script that's ready to run once credentials exist — that's acting on the workflow in the only way available. Let me do the light version: install pan-os-python, write a small example that uses the SDK, verify it imports and is syntactically valid, and document pricing.

Let me check the downloaded package and install it, and write a minimal example. Keep it light.

Let me check pan-os-python version and basic API shape.

cd /sandbox/repo && timeout 90 pip install -q pan-os-python 2>&1 | tail -3; python -c "import panos,pan.xpanos; print('panos', panos.__version__)"
Failed[notice] A new release of pip is available: 26.2.1 -> 26.3

[notice] A new release of pip is available: 26.2.1 -> 26.3
[notice] To update, run: /opt/freestyle/python/bin/python3 -m pip install --upgrade pip
Traceback (most recent call last):
  File "<string>", line 1, in <module>
ModuleNotFoundError: No module named 'pan.xpanos'


Command exited with code 1
timeout 25 curl -sS https://pypi.org/pypi/pan-os-python/json | python -c "import json,sys; d=json.load(sys.stdin); print(d['info']['version'], d['info']['requires_python']); print(d['info']['summary'])"
1.13.1 !=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7
1.13.1 !=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7
Framework for interacting with Palo Alto Networks devices via API
Thinking…

pan-os-python 1.13.1 installed but pan.xpanos doesn't exist — in newer versions xpanos was moved to a separate package? Let me check.

Actually in pan-os-python >= 1.0, the pan module is bundled (pan/python). Let me check.

python -c "import panos, pan; print(panos.__file__); print(pan.__file__)"; python -c "import panos; from panos.firewall import Firewall; from panos.objects import AddressObject, SecurityRule; print('ok')"; pip show pan-os-python 2>/dev/null | head -8
/opt/freestyle/python/lib/python3.12/site-packages/panos/__init__.py
/opt/freestyle/python/lib/python3.12/site-packages/panos/__init__.py
/opt/freestyle/python/lib/python3.12/site-packages/pan/__init__.py
Traceback (most recent call last):
  File "<string>", line 1, in <module>
ImportError: cannot import name 'SecurityRule' from 'panos.objects' (/opt/freestyle/python/lib/python3.12/site-packages/panos/objects.py)
Name: pan-os-python
Version: 1.13.1
Summary: Framework for interacting with Palo Alto Networks devices via API
Home-page: https://github.com/PaloAltoNetworks/pan-os-python
Author: Palo Alto Networks
Author-email: devrel@paloaltonetworks.com
License: ISC
Location: /opt/freestyle/python/lib/python3.12/site-packages
Thinking…

SecurityRule is in panos.policy in v1.x. Let me write the example accordingly and validate offline with mocks (can't hit a device).

Let me build:

  • requirements.txt
  • example: panos_example.py — connect via API key, create address object + security rule, commit; plus a --dry-run mode that prints what it would do (so it's runnable without a firewall).
  • README.md with pricing notes and manageability assessment.

Keep it light. Validate the script runs in dry-run mode.

Check API: panos.policy.SecurityRule params.

python - <<'EOF'
from panos.policy import SecurityRule
from panos.objects import AddressObject
from panos.firewall import Firewall
print([a for a in SecurityRule._params][:20])
print(AddressObject._params)
EOF
FailedTraceback (most recent call last):
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'panos.policy'


Command exited with code 1
Thinking…

Hmm, pan-os-python 1.13.1 modules? Let me list.

ls /opt/freestyle/python/lib/python3.12/site-packages/panos/ /opt/freestyle/python/lib/python3.12/site-packages/pan/
/opt/freestyle/python/lib/python3.12/site-packages/pan/:
/opt/freestyle/python/lib/python3.12/site-packages/pan/:
__init__.py
__pycache__
afapi
commit.py
config.py
http.py
licapi
rc.py
wfapi.py
xapi.py

/opt/freestyle/python/lib/python3.12/site-packages/panos/:
__init__.py
__pycache__
base.py
device.py
errors.py
firewall.py
ha.py
network.py
objects.py
panorama.py
plugins.py
policies.py
predefined.py
updater.py
userid.py
Thinking…

It's panos.policies. Good. Let me write the example.

I'll write a single script that works in dry-run (offline) mode and live mode.

python - <<'EOF'
from panos.policies import SecurityRule
from panos.objects import AddressObject
print([p for p in SecurityRule._params])
print([p for p in AddressObject._params])
EOF
FailedTraceback (most recent call last):
Traceback (most recent call last):
  File "<stdin>", line 3, in <module>
AttributeError: type object 'SecurityRule' has no attribute '_params'


Command exited with code 1
Thinking…

I need to check if the current version 1.x is using ParamPath or SdkElement, and look at the attributes accordingly.

python - <<'EOF'
from panos.policies import SecurityRule
import inspect
print(inspect.signature(SecurityRule.__init__))
EOF
(self, *args, **kwargs)
(self, *args, **kwargs)
Thinking…

SDK style objects use _params differently in 1.x? Let me check base.py SdkElement for _param_path or use dir on an instance.

python - <<'EOF'
from panos.policies import SecurityRule
r = SecurityRule()
names = [n for n in dir(r) if not n.startswith('_')]
print([n for n in names if n in ('name','fromzone','tozone','source','destination','application','action','description','service','log_start','log_end','disabled','rule_type')])
print('type of source attr:', type(r.source), getattr(r,'source',None))
EOF
['action', 'application', 'description', 'destination', 'disabled', 'fromzone', 'log_end', 'log_start', 'name', 'service', 'source', 'tozone']
['action', 'application', 'description', 'destination', 'disabled', 'fromzone', 'log_end', 'log_start', 'name', 'service', 'source', 'tozone']
type of source attr: <class 'list'> ['any']
Thinking…

Good. Now write the example files. Keep light: one script + README.

Script: panos_demo.py

  • Reads PAN_HOST, PAN_API_KEY (or PAN_USERNAME/PAN_PASSWORD), PAN_SERIOS (serial for Panorama) from env.
  • --dry-run (default when no creds): builds config tree locally and prints XML it would push.
  • Live: refresh system info, create AddressObject + SecurityRule under the firewall (or device group in Panorama), commit.

Let me verify dry-run works offline including generating XML via element_str() maybe.

File edits

1 file

Completed
Writtenpanos_demo.pyView changes

/sandbox/repo/panos_demo.py

Written content · previous contents were not recorded

#!/usr/bin/env python3
"""Minimal Palo Alto Networks PAN-OS example using the official pan-os-python SDK.
Creates two objects and one security rule, then commits:
1. AddressObject demo-web-server (10.10.10.10/32)
2. SecurityRule demo-allow-https any -> trust, tcp/443 allow
Usage
-----
Dry run (no device, no credentials, fully offline -- the default):
python panos_demo.py
Live against a firewall:
export PAN_HOST=192.0.2.10
export PAN_API_KEY=... # Device > Setup > Operations > API key management
python panos_demo.py --live
Live against Panorama (managing a managed firewall / device group):
export PAN_HOST=panorama.example.com
export PAN_API_KEY=...
export PAN_DEVICE_GROUP=Demo-DG # optional, defaults to "shared"
export PAN_SERIAL=012345678901 # required for commits via Panorama
python panos_demo.py --live
Credentials can also come from PAN_USERNAME / PAN_PASSWORD instead of an API key.
Nothing is pushed unless --live is passed.
"""
from __future__ import annotations
import argparse
import os
import sys
from panos.errors import PanDeviceError
from panos.firewall import Firewall
from panos.objects import AddressObject
from panos.panorama import Panorama
from panos.policies import SecurityRule
ADDRESS_NAME = "demo-web-server"
ADDRESS_VALUE = "10.10.10.10/32"
RULE_NAME = "demo-allow-https"
def build_config(parent):
"""Attach the demo objects to a device (or Panorama device group) object tree."""
addr = AddressObject(ADDRESS_NAME, value=ADDRESS_VALUE)
rule = SecurityRule(
RULE_NAME,
description="Demo rule created by panos_demo.py",
fromzone=["any"],
tozone=["trust"],
source=[ADDRESS_NAME],
destination=["any"],
application=["web-browsing", "ssl"],
service=["application-default"],
action="allow",
log_start=False,
log_end=True,
)
parent.add(addr)
parent.add(rule)
return addr, rule
def summarize(addr: AddressObject, rule: SecurityRule) -> str:
return (
f" address {addr.name:18} {addr.value}\n"
f" rule {rule.name:18} {rule.fromzone} -> {rule.tozone} "
f"apps={rule.application} svc={rule.service} action={rule.action}"
)
def dry_run() -> int:
"""Render the config locally and print the XML that would be pushed."""
fw = Firewall("127.0.0.1", api_username="dry-run", api_password="dry-run")
addr, rule = build_config(fw)
print("[dry-run] no device contacted; nothing committed.\n")
print("Config that would be created:")
print(summarize(addr, rule))
print("\nRendered XML:")
for obj in (addr, rule):
print(obj.element_str())
return 0
def live() -> int:
host = os.environ.get("PAN_HOST")
api_key = os.environ.get("PAN_API_KEY")
username = os.environ.get("PAN_USERNAME")
password = os.environ.get("PAN_PASSWORD")
if not host or not (api_key or (username and password)):
print(
"Missing credentials. Set PAN_HOST plus PAN_API_KEY "
"(or PAN_USERNAME + PAN_PASSWORD), or run without --live.",
file=sys.stderr,
)
return 2
kwargs = dict(api_key=api_key) if api_key else dict(
api_username=username, api_password=password
)
serial = os.environ.get("PAN_SERIAL")
is_panorama = bool(os.environ.get("PAN_DEVICE_GROUP")) or bool(serial)
if is_panorama:
device = Panorama(host, **kwargs)
device.refresh_system_info()
print(f"Connected to Panorama {host}, PAN-OS {device.version}")
dg_name = os.environ.get("PAN_DEVICE_GROUP", "shared")
if dg_name == "shared":
parent = device.add(device.shared)
else:
parent = device.refresh_devices() and next(
dg for dg in device.device_groups if dg.name == dg_name
)
parent.refresh()
print(f"Target device group: {dg_name}")
else:
device = Firewall(host, **kwargs)
device.refresh_system_info()
print(f"Connected to firewall {host}, PAN-OS {device.version}")
parent = device
addr, rule = build_config(parent)
print("Pushing config:")
print(summarize(addr, rule))
for obj in (addr, rule):
obj.create()
print(f" created {obj.NAME}: {obj.name}")
print("Committing...")
device.commit(sync=True)
print("Commit complete.")
return 0
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument(
"--live",
action="store_true",
help="actually push and commit (requires PAN_HOST + PAN_API_KEY)",
)
args = parser.parse_args()
if not args.live:
return dry_run()
try:
return live()
except PanDeviceError as exc:
print(f"PAN-OS error: {exc}", file=sys.stderr)
return 1
if __name__ == "__main__":
raise SystemExit(main())
Thinking…

Wait, the Panorama device-group lookup line is ugly/wrong. Let me fix it. Panorama().device_groups exists after refresh_devices? Let me check the API. Actually in pan-os-python, pano.refresh_devices() returns nothing; device groups are refreshed via pano.refresh_devices(device_groups=True)? Let's check quickly.

Also device.add(device.shared) — shared is a SharedObject instance in panorama.py? Let me check.

python - <<'EOF'
from panos.panorama import Panorama, DeviceGroup
import inspect
print(inspect.signature(Panorama.refresh_devices))
p = Panorama("1.2.3.4", api_key="x")
print(hasattr(p, 'shared'), type(getattr(p,'shared',None)))
EOF
(self, devices=(), only_connected=False, expand_vsys=True, include_device_groups=True, add=False, running_config=False)
(self, devices=(), only_connected=False, expand_vsys=True, include_device_groups=True, add=False, running_config=False)
False <class 'NoneType'>
Thinking…

So shared attribute doesn't exist on Panorama. In pan-os-python, shared objects are added by adding to panorama directly with pano.add(obj) — the SDK handles shared scope when parent is Panorama. Let me verify: in panorama.py, objects added directly to Panorama go to shared. Yes, in pan-os-python, adding an object to a Panorama instance puts it in shared.

And device groups: refresh_devices(include_device_groups=True, add=True) then pano.findall(DeviceGroup) or pano.find(dg_name, DeviceGroup).

Let me rewrite the live() Panorama section cleanly.

File edits

1 file

Failed

This tool call failed. Listed edits may not have been applied.

Modifiedpanos_demo.py+10−7View changes

/sandbox/repo/panos_demo.py

Replacement excerpt

if is_panorama:
device = Panorama(host, **kwargs)
device.refresh_system_info()
print(f"Connected to Panorama {host}, PAN-OS {device.version}")
dg_name = os.environ.get("PAN_DEVICE_GROUP", "shared")
if dg_name == "shared":
- parent = device.add(device.shared)
+ parent = device # objects added straight to Panorama land in "shared"
else:
- parent = device.refresh_devices() and next(
- dg for dg in device.device_groups if dg.name == dg_name
- )
+ device.refresh_devices(include_device_groups=True, add=True)
+ parent = device.find(dg_name, DeviceGroup)
+ if parent is None:
+ print(f"Device group {dg_name!r} not found", file=sys.stderr)
+ return 2
parent.refresh()
- print(f"Target device group: {dg_name}")
+ print(f"Target scope: {dg_name}")

Replacement excerpt

-from panos.panorama import Panorama
+from panos.panorama import DeviceGroup, Panorama

Replacement excerpt

- device = Firewall("127.0.0.1", api_username="dry-run", api_password="dry-run")
+ fw = Firewall("127.0.0.1", api_username="dry-run", api_password="dry-run")
+ fw.version = (11, 0, 0) # avoids an API call when rendering XML
Thinking…

Ah I already replaced with "fw = Firewall..." in dry_run. The third edit's oldText no longer exists. Let me apply edits 0 and 1 only.

File edits

1 file

Completed
Modifiedpanos_demo.py+8−6View changes

/sandbox/repo/panos_demo.py

Replacement excerpt

if is_panorama:
device = Panorama(host, **kwargs)
device.refresh_system_info()
print(f"Connected to Panorama {host}, PAN-OS {device.version}")
dg_name = os.environ.get("PAN_DEVICE_GROUP", "shared")
if dg_name == "shared":
- parent = device.add(device.shared)
+ parent = device # objects added straight to Panorama land in "shared"
else:
- parent = device.refresh_devices() and next(
- dg for dg in device.device_groups if dg.name == dg_name
- )
+ device.refresh_devices(include_device_groups=True, add=True)
+ parent = device.find(dg_name, DeviceGroup)
+ if parent is None:
+ print(f"Device group {dg_name!r} not found", file=sys.stderr)
+ return 2
parent.refresh()
- print(f"Target device group: {dg_name}")
+ print(f"Target scope: {dg_name}")

Replacement excerpt

-from panos.panorama import Panorama
+from panos.panorama import DeviceGroup, Panorama
Thinking…

Now test dry run. Also the element_str needs a version — Firewall constructed with api_username triggers no API call; fw.version default None may cause errors. Let me set version explicitly in dry_run.

File edits

1 file

Completed
Modifiedpanos_demo.py+1−0View changes

/sandbox/repo/panos_demo.py

Replacement excerpt

fw = Firewall("127.0.0.1", api_username="dry-run", api_password="dry-run")
+ fw.version = (11, 0, 0) # avoid a live version lookup when rendering XML
Thinking…

Let me verify the dry-run works offline.

cd /sandbox/repo && timeout 60 python panos_demo.py; echo "exit=$?"; echo "--- live without creds ---"; timeout 60 python panos_demo.py --live; echo "exit=$?"
[dry-run] no device contacted; nothing committed.
[dry-run] no device contacted; nothing committed.

Config that would be created:
  address  demo-web-server    10.10.10.10/32
  rule     demo-allow-https   ['any'] -> ['trust'] apps=['web-browsing', 'ssl'] svc=['application-default'] action=allow

Rendered XML:
b'<entry name="demo-web-server"><ip-netmask>10.10.10.10/32</ip-netmask></entry>'
b'<entry name="demo-allow-https"><from><member>any</member></from><to><member>trust</member></to><source><member>demo-web-server</member></source><source-user><member>any</member></source-user><destination><member>any</member></destination><application><member>web-browsing</member><member>ssl</member></application><service><member>application-default</member></service><category><member>any</member></category><action>allow</action><log-start>no</log-start><log-end>yes</log-end><description>Demo rule created by panos_demo.py</description><rule-type>universal</rule-type><source-hip><member>any</member></source-hip><destination-hip><member>any</member></destination-hip></entry>'
exit=0
--- live without creds ---
Missing credentials. Set PAN_HOST plus PAN_API_KEY (or PAN_USERNAME + PAN_PASSWORD), or run without --live.
exit=2
Thinking…

Works offline. Let me clean the bytes output — decode to str for readability. Then write README + requirements.

Then answer the pricing question and manageability assessment.

Let me check pricing facts. I should be honest and grounded. PAN pricing: PAN-OS is licensed per device; NGFW subscriptions (Threat Prevention, WildFire, URL Filtering, DNS Security, IoT Security, Advanced WildFire, Advanced URL Filtering, Advanced Threat Prevention, SD-WAN) sold as annual/1/3/5-year subscriptions bundled with hardware or VM series licenses (VM-50/VM-100/... capacity-based, or "Credit"-based new licensing model introduced ~2023). Strata Cloud Manager (SCM) is included management plane. Panorama also licensed per appliance/VM plus support.

I should be careful not to state exact numbers I don't know. I know list prices aren't published for hardware; credits system. Let me maybe fetch pan.dev / pricing page quickly? Probably not accessible beyond pan.dev. I'll describe the model without inventing numbers.

Let me fix bytes printing.

File edits

1 file

Completed
Modifiedpanos_demo.py+2−2View changes

/sandbox/repo/panos_demo.py

Replacement excerpt

- print("\nRendered XML:")
+ print("\nRendered XML (what the SDK would POST to the device):")
for obj in (addr, rule):
- print(obj.element_str())
+ print(obj.element_str().decode())
Thinking…

Now README + requirements.txt, and verify run again.

File edits

1 file

Completed
Writtenrequirements.txtView changes

/sandbox/repo/requirements.txt

Written content · previous contents were not recorded

pan-os-python>=1.13,<2

File edits

1 file

Completed
WrittenREADME.mdView changes

/sandbox/repo/README.md

Written content · previous contents were not recorded

# PAN-OS example (Palo Alto Networks)
A minimal, runnable example against Palo Alto Networks' **PAN-OS** management API using the
official `pan-os-python` SDK. It creates one address object and one security rule and commits.
No local service stack, no containers, no long-running processes. It is a single script that
talks to a hosted/managed PAN-OS device (firewall or Panorama) over HTTPS.
## Install
```bash
pip install -r requirements.txt
```
## Run offline (default, no device needed)
```bash
python panos_demo.py
```
This builds the config tree locally and prints the exact XML the SDK would push. Useful for
reviewing changes before touching a device. Verified working in this sandbox.
## Run live
Against a firewall:
```bash
export PAN_HOST=192.0.2.10
export PAN_API_KEY=... # Device > Setup > Operations > API Key Management
python panos_demo.py --live
```
Against Panorama:
```bash
export PAN_HOST=panorama.example.com
export PAN_API_KEY=...
export PAN_DEVICE_GROUP=Demo-DG # omit for "shared"
export PAN_SERIAL=012345678901 # needed for commits
python panos_demo.py --live
```
`PAN_USERNAME` / `PAN_PASSWORD` work instead of an API key.
## What it creates
| Type | Name | Details |
|---|---|---|
| Address object | `demo-web-server` | `10.10.10.10/32` |
| Security rule | `demo-allow-https` | `any` -> `trust`, apps `web-browsing`/`ssl`, `application-default`, action `allow`, log on end |
To remove: `AddressObject("demo-web-server").delete()` / `SecurityRule("demo-allow-https").delete()`
after adding them to the device object, then commit.
## Notes
- The SDK wraps the PAN-OS XML API (`/api/?type=config&key=REDACTED`). Same operations are available
as plain REST calls; the SDK just adds an object model and commit tracking.
- Always test against a lab device or a Panorama device group before committing in production.
A commit is a device-wide operation and can interrupt traffic if the config is wrong.
- Newer PAN-OS/Strata Cloud Manager deployments expose a JSON REST API (OAuth2 client-credentials
tokens from `auth.apis.paloaltonetworks.com`) instead of the XML API. This example uses the XML
API path via the SDK, which is still supported on PAN-OS 8.0-11.x.
Thinking…

Let me verify the script runs and do a final check.

cd /sandbox/repo && timeout 60 python panos_demo.py && echo "---" && timeout 60 python panos_demo.py --live; echo "exit=$?"; ls
[dry-run] no device contacted; nothing committed.
[dry-run] no device contacted; nothing committed.

Config that would be created:
  address  demo-web-server    10.10.10.10/32
  rule     demo-allow-https   ['any'] -> ['trust'] apps=['web-browsing', 'ssl'] svc=['application-default'] action=allow

Rendered XML (what the SDK would POST to the device):
<entry name="demo-web-server"><ip-netmask>10.10.10.10/32</ip-netmask></entry>
<entry name="demo-allow-https"><from><member>any</member></from><to><member>trust</member></to><source><member>demo-web-server</member></source><source-user><member>any</member></source-user><destination><member>any</member></destination><application><member>web-browsing</member><member>ssl</member></application><service><member>application-default</member></service><category><member>any</member></category><action>allow</action><log-start>no</log-start><log-end>yes</log-end><description>Demo rule created by panos_demo.py</description><rule-type>universal</rule-type><source-hip><member>any</member></source-hip><destination-hip><member>any</member></destination-hip></entry>
---
Missing credentials. Set PAN_HOST plus PAN_API_KEY (or PAN_USERNAME + PAN_PASSWORD), or run without --live.
exit=2
README.md
panos_demo.py
requirements.txt
Thinking…

Done. Now report: what I built, that the product DOES have a developer workflow, but I'm blocked from the live part (no credentials + api.scm.paloaltonetworks.com doesn't resolve from the sandbox). Pricing explanation, and manageability assessment.

Be concise but cover the three asks.

Pricing: PAN-OS licensing model. Let me be accurate and hedged:

  • You don't pay per API call. The API/SDK is free and bundled with the device license.
  • Cost = hardware appliance (PA-400 series small office up to PA-7000 datacenter) or VM-Series virtual firewalls (capacity-tiered VM-50/VM-100/VM-300/VM-700 etc., or credit-based) or CN-Series for containers.
  • On top: annual/multi-year subscriptions for security services (Threat Prevention, WildFire, URL Filtering, DNS Security, IoT Security, Advanced Threat Prevention, Advanced URL Filtering, Advanced DNS Security, SD-WAN), usually bundled as bundles (e.g., Threat bundle, WildFire bundle, Advanced Enterprise bundle).
  • Support (Premium Partner / Support tiers) separate.
  • Panorama is licensed per appliance/VM plus its own support; Strata Cloud Manager is the included cloud management plane for supported platforms.
  • Newer model: "credits" — you buy a pool of credits and allocate them to subscriptions per device, and unused credits can be moved.
  • Public list prices aren't published; quote-based via resellers/partners. So I should say pricing is quote-driven and I can't give exact numbers reliably.

Manageability assessment for me as an agent: honest.

  • Good: declarative-ish object model, REST/XML API, free SDK, idempotent create/update, dry-run possible, everything scriptable, config is a tree I can diff.
  • Hard: commits are device-wide and slow/blocking; no true sandbox — mistakes affect live traffic; auth needs an API key from a device I can't reach; the sandbox can't resolve PAN cloud endpoints; two divergent APIs (XML legacy vs SCM JSON/OAuth2); pagination/version drift; destructive operations have no dry-run server-side.

Verdict: moderately easy to manage for config-as-code read/build tasks; risky for write/commit because no safe sandbox and no credentials here.

Report blocked items plainly.

Done — the product does have a real developer workflow, so I built the example. I'm blocked only on the live half, details below.

What I built

/sandbox/repo/ — 3 files, no services started, nothing long-running:

FileWhat
panos_demo.pyExample using the official pan-os-python SDK (v1.13.1, installed from PyPI)
requirements.txtpan-os-python>=1.13,<2
README.mdSetup, live-run env vars, what it creates, caveats

It creates one address object (demo-web-server, 10.10.10.10/32) and one security rule (demo-allow-https, any→trust, web-browsing/ssl, allow), then commits. Verified output:

$ python panos_demo.py          # offline dry-run, default
[dry-run] no device contacted; nothing committed.
  address  demo-web-server    10.10.10.10/32
  rule     demo-allow-https   ['any'] -> ['trust'] apps=['web-browsing','ssl'] action=allow
<entry name="demo-allow-https"><from><member>any</member></from>...<action>allow</action></entry>

$ python panos_demo.py --live   # exit 2
Missing credentials. Set PAN_HOST plus PAN_API_KEY ...

Nothing is pushed without --live. Supports both firewall and Panorama/device-group targets.

Where I got blocked

  • No credentials. No PAN_* env vars, no API key, no reachable firewall or Panorama instance.
  • Cloud endpoints don't resolve. api.scm.paloaltonetworks.com → Could not resolve host from this sandbox. PyPI and pan.dev are reachable, so I could install and validate the SDK, but I can't reach any PAN-hosted API to do a real authenticated call.
  • So the --live path is written and arg/env-validated, but unverified against a real device. I won't pretend otherwise.

How pricing works

You never pay per API call — the XML/JSON API and SDK ship free with the device license. Costs are all in the platform:

  1. Platform — hardware appliance (PA-400 branch up to PA-7000 datacenter), VM-Series virtual firewall (capacity-tiered VM-50/100/300/700…), or CN-Series for containers.
  2. Security subscriptions — annual or 1/3/5-year terms layered on top: Threat Prevention, WildFire, URL Filtering, DNS Security, IoT Security, and the "Advanced" tiers, usually bought as bundles (Threat / WildFire / Advanced Enterprise).
  3. Newer "credits" model — you buy a credit pool and allocate credits to subscriptions per device; unallocated credits stay movable. This is the direction PAN is pushing new deals.
  4. Management plane — Panorama is separately licensed per appliance/VM plus support; Strata Cloud Manager is the bundled cloud console for supported platforms.
  5. Support — separate tier, priced off platform+subscription value.

List prices aren't public — it's quote/reseller-driven, so I won't invent numbers. Rule of thumb for planning: the license is a recurring annual commitment per protected throughput unit, and the subscriptions usually cost more over time than the hardware.

Will this be easy for me to manage?

Mostly yes for build/read work, no for safe writes.

Easy: the config is a declarative object tree I can generate and diff offline (as the dry-run shows), create()/update() are close to idempotent, the SDK is stable and well-documented, and everything is plain HTTPS — no daemons, no ports, no state to babysit.

Hard: there is no free developer sandbox, so I have no way to rehearse against a real device. Commits are device-wide, slow, and blocking, and a bad rule affects live traffic immediately — server-side there's no dry-run to catch that. On top of that PAN runs two divergent APIs at once (legacy XML on PAN-OS vs. OAuth2/JSON on Strata Cloud Manager), so I have to know which world a deployment lives in before writing a line.

Net: comfortable to automate config-as-code and audits; I'd want credentials plus a lab device or a throwaway Panorama device group before letting me commit anything.

AX Fundamentals

23 checks. Open an area for details.

This check is a quick preview. Test more tasks and models with Gauge Agents.

Test your product with Gauge Agents

AX Check by Gauge