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.

Triggering playbooks

Fire a playbook and wait for it to finish in one call with run_and_wait():

result = client.playbooks.run_and_wait("My Playbook", timeout=60)
if result.succeeded:
    for step in result.steps:
        print(f"  {step.name:30} {step.status:10} {step.duration_ms}ms")
else:
    print(f"failed at: {result.failure.failing_step}")
    print(f"  error: {result.failure.error_message}")

For playbooks that pause on a Manual Input step, use trigger() then answer() to resume. See Playbook Authoring & Deployment for the full interactive flow.

Next steps