The FortiSOAR Analyst exam (NSE6_FSR_AN-7.6) is Fortinet's NSE 6 exam for people who build and run automation in FortiSOAR 7.6. It has 35–45 questions in 75 minutes and costs USD 200, and it is mostly about playbooks, Jinja, JSON queries and APIs rather than clicking through the GUI. If you can read a playbook step, predict what a Jinja expression returns and explain why a connector call failed, you are most of the way there. This guide covers each exam domain with the expressions and API calls you will actually meet.
NSE6_FSR_AN-7.6 at a glance
| Item | Detail |
|---|---|
| Exam code | NSE6_FSR_AN-7.6 |
| Exam name | Fortinet NSE 6 - FortiSOAR 7.6 Analyst |
| Certification track | Fortinet NSE 6 Certified - Security Operations |
| Questions | 35–45 |
| Duration | 75 minutes |
| Result | Pass/fail |
| Price | USD 200 |
| Product version | FortiSOAR 7.6 |
| Delivery | Pearson VUE |
The official FortiSOAR Analyst exam page lists the current objectives, and the full topic breakdown is on the NSE6_FSR_AN-7.6 syllabus page.
Domain weights: where the marks are
| Domain | Weight |
|---|---|
| Playbook development | 25–35% |
| FortiSOAR architecture and data models | 20–30% |
| APIs and connectors | 15–25% |
| Troubleshooting | 15–25% |
| Incident handling | 5–15% |
Playbooks, APIs and troubleshooting together can make up as much as 85% of the exam, and all three come down to reading data structures. Spend your study time accordingly.
Domain 1: Architecture and data models (20–30%)
Short definitions to keep straight:
- SOAR vs SIEM: a SIEM collects and correlates logs and raises alerts. A SOAR platform takes those alerts and automates and orchestrates the response. FortiSOAR usually sits downstream of FortiSIEM or FortiAnalyzer.
- Automation vs orchestration: automation runs one task without a person. Orchestration coordinates many automated tasks across several tools into one workflow.
- Deployment models: a single node, high-availability clusters, and multi-tenant (MSSP) setups where a master node manages tenant nodes. Agents run actions inside network segments the FortiSOAR node can't reach directly, and the Secure Message Exchange (SME) carries traffic between nodes and agents.
- Content Hub: where you install connectors, solution packs and widgets.
The data model is a favourite source of questions:
| Object | What it is | Example |
|---|---|---|
| Module | A record type, like a database table | Alerts, Incidents, Indicators, Assets |
| Field | An attribute of a module |
severity, sourceIp, status
|
| Picklist | A controlled list of values for a field | Severity: Critical, High, Medium, Low |
| Relationship | A link between modules | An incident relates to many alerts and indicators |
Access control is built from users, roles (what you can do in each module) and teams (which records you can see). Know the difference between record ownership, which is team based and decides visibility, and assignment, which is a single user who works on the record.
Domain 2: Playbook development (25–35%)
Variables you will see in every question
FortiSOAR passes data between steps through the vars namespace:
| Expression | Returns |
|---|---|
{{vars.input.records[0]}} |
The record that triggered the playbook |
{{vars.input.records[0].sourceIp}} |
One field of that record |
{{vars.steps.Get_Alerts.data}} |
The output of an earlier step named "Get Alerts" |
{{vars.item}} |
The current element inside a for-each loop |
{{vars.request.data}} |
The body sent to an API-triggered playbook |
Step names become identifiers, with spaces replaced by underscores, which is why Get Alerts is referenced as Get_Alerts.
Jinja filters
{# How many alerts came back? #}
{{ vars.steps.Get_Alerts.data | length }}
{# Unique source IPs, as a list #}
{{ vars.steps.Get_Alerts.data | map(attribute='sourceIp') | unique | list }}
{# Fall back to a default when a field is empty #}
{{ vars.input.records[0].assignedTo | default('soc-tier1') }}
{# Build a readable summary string #}
{{ "Alert " ~ vars.input.records[0].name ~ " has severity " ~ vars.input.records[0].severity.itemValue }}
Watch picklist fields. A picklist value is an object, not a string, so comparing severity == 'High' fails where severity.itemValue == 'High' works. That exact trap shows up in troubleshooting scenarios.
Conditions and loops
- Decision steps route the playbook with if, elif and else conditions built from operators such as equals, contains, in and greater than.
- Step conditions skip a single step when a condition is false, without branching.
- For-each loops run a step once per list element, with the current element in
vars.item. Loop over a de-duplicated list, or the playbook will enrich the same indicator several times. - Ingestion playbooks and preprocessing rules decide how alerts from a SIEM become records, including de-duplication before records are created.
JSON Query and YAQL
Take this step output:
{
"data": [
{"name": "Brute force", "severity": "High", "sourceIp": "203.0.113.7"},
{"name": "Port scan", "severity": "Low", "sourceIp": "198.51.100.4"},
{"name": "Brute force", "severity": "High", "sourceIp": "203.0.113.9"}
]
}
JSON Query uses JMESPath syntax through the json_query filter:
{{ vars.steps.Get_Alerts | json_query("data[?severity=='High'].sourceIp") }}
{# -> ["203.0.113.7", "203.0.113.9"] #}
The same selection in YAQL reads like a method chain:
$.data.where($.severity = 'High').select($.sourceIp)
For the exam, know how to read both and recognise them side by side. JSON Query is a compact path language with [?...] filters. YAQL uses $ for the current context and chains where(), select() and similar functions.
Domain 3: Incident handling (5–15%)
This is the smallest domain and mostly vocabulary:
- Incident phases follow a response lifecycle (from identification through containment and eradication to recovery), and phase changes can trigger playbooks.
- Queues and shifts spread work across analysts, so new incidents are assigned automatically to whoever is on shift.
- War rooms are collaboration spaces for major incidents, with their own tasks, participants and timeline.
- Correlation links related records across modules. Visual correlation shows the graph, and MITRE ATT&CK tactics and techniques can be mapped onto incidents.
Domain 4: APIs and connectors (15–25%)
FortiSOAR REST API
FortiSOAR's own API is REST. You authenticate, get a token and send it as a Bearer header:
# 1. Authenticate
TOKEN=$(curl -sk -X POST https://fortisoar.example.com/auth/authenticate \
-H "Content-Type: application/json" \
-d '{"credentials": {"loginid": "api-user", "password": "********"}}' | jq -r .token)
# 2. Read alerts (GET), then create one (POST)
curl -sk https://fortisoar.example.com/api/3/alerts?\$limit=5 \
-H "Authorization: Bearer $TOKEN"
curl -sk -X POST https://fortisoar.example.com/api/3/alerts \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"name": "Test alert from API", "sourceIp": "203.0.113.7"}'
Map HTTP methods to CRUD: POST creates, GET reads, PUT replaces, PATCH updates and DELETE removes. To start a playbook from outside, use a custom API endpoint trigger, and the caller's JSON body reaches the playbook as vars.request.data.
REST vs JSON-RPC, using FortiManager as the example
FortiManager's API is JSON-RPC: every call is a POST to one URL, and the operation goes in the body.
{
"id": 1,
"method": "get",
"params": [{"url": "/dvmdb/adom/root/device"}],
"session": "<session-id-from-login>"
}
| REST | JSON-RPC | |
|---|---|---|
| Endpoint | Many URLs, one per resource | One URL for everything |
| Operation | HTTP method (GET, POST, PUT, DELETE) |
method field in the body |
| Auth in this exam | Bearer token header |
session field in the body |
| Example | FortiSOAR API | FortiManager API |
A connector wraps an API so playbooks can call it as actions. Configure it once with the server address, credentials and SSL verification. For a product with no connector in the Content Hub, build a custom connector: define its configuration fields and actions, then write the Python that makes the API call and returns the result.
Domain 5: Troubleshooting (15–25%)
Most troubleshooting questions follow one path: open the executed playbook log, find the failing step, compare its evaluated arguments with what you expected, then fix the Jinja or the connector configuration.
| Symptom | First thing to check |
|---|---|
| Step fails with "undefined" | Step name changed, so vars.steps.Old_Name no longer exists |
| Condition never matches | Comparing a picklist object to a string; use .itemValue
|
| Loop processes duplicates | Missing unique on the list before the for-each |
| Connector action times out | Connector health check, network path, or agent connectivity |
| Playbook never starts | Trigger conditions or module, or the playbook is inactive |
Useful tools: the playbook logging level (raise it to debug while testing, then lower it again), the executed playbook log with each step's input, output and evaluated arguments, and the Jinja editor, which tests an expression against sample JSON before you put it in a playbook. On the server, csadm services --status shows service health. Connector and workflow logs live under /var/log/cyops/.
A four-week study plan
| Week | Focus | Practical goal |
|---|---|---|
| 1 | Architecture, data model, access control | Explain modules, picklists, teams and deployment models from memory |
| 2 | Playbooks and Jinja | Write 20 expressions in the Jinja editor against sample alert JSON |
| 3 | JSON Query, YAQL, APIs | Translate queries between JSON Query and YAQL; run the curl calls above |
| 4 | Troubleshooting, incident handling, review | Break playbooks on purpose and fix them from the logs; timed practice |
In week 4, try the free FortiSOAR Analyst sample questions from NWExam under a 75-minute limit, and use the FortiSOAR 7.6 documentation to look up any connector or playbook step you got wrong.
FAQ
How many questions are on the FortiSOAR Analyst exam?
NSE6_FSR_AN-7.6 has 35–45 questions in 75 minutes, and the result is pass/fail.
What is the hardest part of NSE6_FSR_AN-7.6?
For most candidates it is playbook development (25–35%), especially predicting what Jinja, JSON Query and YAQL expressions return against a given JSON input.
Do I need to know Python for the FortiSOAR Analyst exam?
Not deeply. You need to read JSON, Jinja and API requests. Python only matters at the level of knowing that custom connectors are written in it.
Which certification does the FortiSOAR Analyst exam count toward?
It is part of the Fortinet NSE 6 Certified - Security Operations track.
What is the difference between REST and JSON-RPC in this exam?
REST uses many URLs and HTTP methods (the FortiSOAR API). JSON-RPC uses one URL and puts the method in the request body (the FortiManager API).
Exam-day checklist
-
vars.input.records[0]is the triggering record,vars.steps.<Step_Name>is earlier output, andvars.itemis the loop element. - Picklists compare on
.itemValue. - JSON Query filters with
[?field=='value'], and YAQL uses$.where(...).select(...). - REST is many URLs plus HTTP verbs. JSON-RPC is one URL plus a method in the body.
- Troubleshoot from the executed playbook log: find the step, read its evaluated arguments, then fix the expression.
- With up to 45 questions in 75 minutes you have about 100 seconds each, so take the time to trace JSON carefully.
If you can predict the output of every expression in this guide before testing it, you are ready for the FortiSOAR Analyst exam.