Getting Started¶
Install¶
pip install pyfsr
Optional extras:
pip install "pyfsr[mcp]" # bundled Model Context Protocol server
pip install "pyfsr[dev]" # linters + test + docs + mcp extras
Connect¶
Create a FortiSOAR client with either an API token or a
(username, password) tuple:
from pyfsr import FortiSOAR
# API token (recommended)
client = FortiSOAR("soar.example.com", "your-api-token")
# Username / password
client = FortiSOAR("soar.example.com", ("admin", "password"))
For self-signed appliances you can disable certificate verification (and silence the resulting warnings):
client = FortiSOAR(
"soar.example.com",
"your-api-token",
verify_ssl=False,
suppress_insecure_warnings=True,
)
See Authentication for environment-based config.
First calls¶
>>> client = demo_client()
>>> # Generic CRUD against any module
>>> incidents = client.records("incidents")
>>> incident = incidents.get("0740411d-e852-4eee-b33b-596210d09a9b")
>>> incident["name"]
'pyfsr doctest incident'
>>> # Raw REST escape hatch
>>> data = client.get("/api/3/alerts")
>>> data["hydra:totalItems"]
1
client.alerts.list()/.get(uuid) work the same way as the generic path above,
via the typed, module-specific AlertsAPI — see
Working with Records for the typed-model walkthrough.
Creating records & picklists¶
Picklist fields (severity, status, …) are stored as IRIs, not friendly
strings — but pyfsr resolves friendly values for you automatically, so you can
just pass "High":
alert = client.alerts.create(
name="Test Alert",
description="This is a test alert",
severity="High", # resolved to its IRI automatically
)
Same on the generic record path — captured live (created, fetched, deleted in the same session; box left with no extra incidents):
>>> created = client.records("incidents").create(
... {"name": "pyfsr doctest incident", "description": "temporary, will be deleted",
... "severity": "Critical"},
... resolve_picklists=False, # already an IRI-resolved doctest fixture; see note below
... )
>>> created["name"]
'pyfsr doctest incident'
Note
Resolution is on by default (the example above passes resolve_picklists=False
only because this doctest replays a captured response rather than a live
metadata lookup). Pass it yourself to skip resolution — and the metadata lookup
it needs — when every value you send is already an IRI.
Next steps¶
Working with Records — generic CRUD and typed models
Querying — the fluent
QueryDSLAI & Agents — drive FortiSOAR from an LLM