API access

DFIRe provides a full REST API for programmatic access. Use API keys to authenticate SIEM connectors, SOAR playbooks, custom scripts, and third-party integrations.

Overview

Every action available in the DFIRe web interface is also available through the REST API, apart from managing your own multi-factor authentication, which needs a browser session. API keys allow external systems to authenticate and perform operations with the same permission model as browser-based users.

Key concepts:

  • API Keys are per-user Bearer tokens that inherit the user's full RBAC permissions
  • Service Accounts are dedicated user accounts that authenticate exclusively via API key (no password or SSO login)
  • API Documentation is built into every DFIRe installation as an interactive reference at /api/docs/

API Keys

API keys provide programmatic access to DFIRe. Each key is tied to a specific user and inherits that user's group memberships, permissions, and case access. Any endpoint accessible via the browser is accessible via API key with the same authorization checks, except the multi-factor settings.

Creating an API Key

  1. Open API Keys from the profile menu

    Click your avatar in the header and choose API Keys. Any authenticated user can create API keys for their own account.

  2. Click "Create API Key"

    Provide a descriptive name (e.g., "Splunk SOAR connector") and set an expiration date. The expiration cannot exceed the tenant-configured maximum lifetime.

  3. Copy the raw key immediately

    The full key (starting with dfire_ak_) is displayed only once. Store it securely. DFIRe stores only a SHA-256 hash and cannot recover the original key.

Important: The raw API key is shown only at creation time and after regeneration. If you lose it, you must regenerate the key (which invalidates the old one).

Key Properties

Property Description
Name A descriptive label for identifying the key's purpose.
Description Optional notes about what system uses this key.
Expiration Mandatory. Keys automatically stop working after this date. Bounded by the tenant maximum lifetime setting.
Enabled Keys can be temporarily disabled without deletion. Disabled keys reject all requests.
Key Prefix The first 12 characters of the key (e.g., dfire_ak_a1b2), visible in audit logs for identification.

Managing API Keys

In the same API Keys view you can:

  • Enable / Disable. Temporarily suspend a key without deleting it
  • Regenerate. Create a new key value (the old value stops working immediately). An expired key cannot be regenerated, because the new value would keep the same past expiry. Extend the expiration first, or delete the key and create a new one.
  • Delete. Permanently remove a key
  • View usage. See last used timestamp, IP address, and total request count

Tenant Policy

Administrators can configure API key policy in Settings > Global Settings:

Setting Default Description
Maximum keys per user 3 Limits the number of active (enabled and non-expired) keys a single user can have.
Maximum key lifetime 365 days The furthest expiration date allowed, counted from today, when you create a key or change its expiration.

Admin Key Management

Superusers can manage any account's API keys from Settings → User Accounts, by editing the user. This includes creating, listing, editing, disabling, regenerating, and deleting keys.

The Edit userapikey permission adds key administration to a role without letting it hand out access. It works alongside the user permissions that open Settings → User Accounts in the first place. On that screen, a role needs both to manage anyone else's keys. A key authenticates as the account it belongs to and carries that account's permissions, so issuing one is equivalent to lending out the account. What the permission allows therefore depends on the account:

  • Service accounts: everything, including creating and regenerating keys. This is the account type meant to be driven by a key.
  • Ordinary accounts: listing, editing, disabling, and deleting the keys that already exist. New keys cannot be issued and existing ones cannot be regenerated. People create their own keys from their profile.
  • System Root accounts: nothing. Only another superuser can manage a superuser's keys.
Password change revocation: When an administrator changes another user's password, all of that user's enabled API keys are automatically disabled as a security measure. The user must re-enable or regenerate their keys. Changing your own password does not affect your keys.

Service Accounts

Service accounts are dedicated user accounts designed for automated systems. They authenticate exclusively via API key. Password login and SSO are blocked. A System Root account cannot become a service account.

Creating a Service Account

  1. Create a new user account

    Go to Settings → User Accounts and create a regular user account (for example svc-splunk).

  2. Enable the service account flag

    In the user's profile, check "Service Account". This blocks password and SSO login. The user pickers, such as the ones for the lead and the team, offer the account only to people who may change user accounts. The Lead filter of the case lists offers it to every user while the account is active.

  3. Assign appropriate roles

    Give the service account the roles that grant the permissions it needs. Follow the principle of least privilege.

  4. Create an API key

    Still in Settings → User Accounts, edit the service account and create the key from its API Keys section.

Making an account a service account is permanent, and it signs the account out everywhere. Only a System Root user can turn the setting back off. The change ends every open browser session immediately and deletes every API key the account holds, so anyone signed in is returned to the login screen and anything authenticating with a key stops working straight away. Issue a new key afterwards and update the integrations that use it.

The setting is one-way because it decides who may issue keys for the account, and a key authenticates as the account it belongs to. A converted account stays converted and can no longer sign in with a password or SSO, so the change is immediately visible to the person who uses it. Every conversion is recorded in the audit log against the account, whoever made it, and the API key they used if they worked through the API.

Custom Permissions via Roles

API keys inherit all permissions from the user account they belong to, including its roles. To grant a service account (or any API key holder) a custom set of permissions, create a dedicated role in Settings → Access Roles and grant it only the capabilities that integration needs, then assign the role to the account. This lets you enforce least privilege: a SIEM connector role might hold only view capabilities on cases and indicators, while a SOAR playbook role could additionally hold create and edit capabilities on cases. See Users and roles → Editing roles.

Audit trail: All actions performed via API key are logged with the key prefix (e.g., dfire_ak_a1b2...) in the audit log, making it easy to trace which integration performed each action.

Authentication

API requests are authenticated using the Authorization header with a Bearer token:

Authorization: Bearer dfire_ak_your_key_here

Example: List Cases

curl -H "Authorization: Bearer dfire_ak_abc123..." \
     https://your-dfire-instance.com/api/cases/

Example: Create a Case

curl -X POST \
     -H "Authorization: Bearer dfire_ak_abc123..." \
     -H "Content-Type: application/json" \
     -d '{"title": "Phishing incident", "case_mode": "incident", "severity": "high"}' \
     https://your-dfire-instance.com/api/cases/

Setting case attributes

The attributes field holds the values of the playbook's custom fields. Send it as one JSON object. Each key is the field's Database key from the playbook's Custom Fields, not the label the case shows. Choose the playbook with case_type, which takes the playbook's ID (see Looking up record IDs).

curl -X POST \
     -H "Authorization: Bearer dfire_ak_abc123..." \
     -H "Content-Type: application/json" \
     -d '{"title": "Wazuh alert 5712", "case_type": 4, "severity": "medium",
          "external_id": "WAZUH-5712",
          "attributes": {"wazuh_agent": "agent-01", "rule_level": "12",
                         "personal_data_involved": false, "first_seen": "2026-10-15"}}' \
     https://your-dfire-instance.com/api/cases/

Send a text field as a string, a Yes/No field as true or false, and a date as a YYYY-MM-DD string. The web app saves a number field as a string, so send numbers as strings to match the values people enter.

DFIRe stores the object as you send it. It does not check the keys or the value types against the playbook, and it does not enforce required fields. It refuses a value that is not a JSON object with status 400. That includes a string, a list, and a JSON object sent inside a string. A PATCH that carries attributes replaces the whole object, so send every value you want to keep. A PATCH without attributes leaves them unchanged.

Authentication Behavior

Scenario Result
Valid, enabled, non-expired key Request proceeds with the key owner's permissions
Expired key 401 Unauthorized
Disabled key 401 Unauthorized
Invalid key value 401 Unauthorized
Key owner's account is inactive 401 Unauthorized
Too many failed attempts from same IP 401 Unauthorized (rate limited)
No Authorization header Falls through to session auth (browser login)
Brute-force protection: After 10 failed authentication attempts from the same IP address within 5 minutes, further API key authentication is blocked for 10 minutes. Successful authentication resets the counter.

Multi-Factor Authentication and API keys

An API key is a credential in its own right. DFIRe never asks it for a code, whether or not its owner has multi-factor authentication turned on. Treat a key as equal to the account it belongs to: give it an expiry, keep it out of shared storage, and disable it once it is no longer needed.

A key cannot set up, change or remove multi-factor authentication. DFIRe refuses those requests unless they come from a signed-in browser session. A key that could also enrol an authenticator would turn a leaked key into permanent control of the account.

Administering other people's accounts is different, and a key with the permission to change users can do it. That includes clearing a user's multi-factor authentication and restoring the sign-ins a tenant-wide requirement has used up.

API Documentation

Every DFIRe installation includes built-in API reference documentation generated from the live application. The documentation is always up-to-date and reflects the exact endpoints, parameters, and response formats available in your version.

Accessing the API Reference

Resource URL Description
API Reference /api/docs/ Interactive ReDoc documentation with endpoint descriptions, request/response schemas, and authentication details.
OpenAPI Schema /api/docs/schema/ Raw OpenAPI 3.0 YAML schema. Import into Postman, Insomnia, or code generators.

Both endpoints require authentication (browser session or API key). Links are also available in Settings > Global Settings under the API Documentation section.

The API reference works without internet access. Its script is included in DFIRe, and it uses system fonts.

Looking up record IDs

Many API fields take the ID of another record. For example, lead_investigator takes a user ID and case_type takes a playbook ID. The interface shows these records by name only, so a superuser finds their IDs in Settings → Integration IDs.

  1. Select a record type

    Choose it under Record type, for example User accounts or Playbooks.

  2. Find the record

    Search by name or by ID. User accounts also match on the username.

  3. Copy the ID

    Click the ID to copy it to the clipboard.

Above the list, the tab names the endpoints and fields that take the ID. Each field shows the format it expects: 1 for a single ID, [1] or [1, 2] for a list. The list includes deactivated accounts and inactive projects, marked Inactive, because existing records can still refer to them.

Record types: user accounts, playbooks, evidence types, evidence workflow steps, triage flags, incident phases, incident categories, outcome verdicts, projects, access roles and legal entities.

Key Endpoint Groups

The API is organized into the following groups:

Group Base Path Description
Cases /api/cases/ Case CRUD, timers, indicators, timeline, exports, tag suggestions
Items /api/items/ Evidence item management. Without case, the list returns every item you can see, with its case in case_details
Attachments /api/attachments/ Encrypted file uploads and downloads
IOC /api/indicators/ Indicator registry, enrichment, bulk operations, tag suggestions
API Keys /api/api-keys/ API key management
Users /api/users/ User management and profiles
Search /api/search/ Full-text search across all entities
Webhooks /api/webhooks/ Outgoing webhook configuration
Audit Log /api/audit-logs/ Immutable audit trail, and the action and record types its filters take
Dashboard Sync /api/remote-systems/ Health of the Dashboard Sync Senders and Sync now. With include_remote=true, /api/cases/ merges their cases in. See Dashboard Sync
Sync feed /api/sync/v1/cases/ The cases this installation sends to receiving installations. Accepts only the sync token
System /api/system-settings/ Tenant configuration and admin operations

See the built-in API reference at /api/docs/ for complete endpoint details, request/response schemas, and parameter documentation.

Filtering lists

The case list, the indicator registry and the audit log take a filter chain. Each filter row is one f query parameter in the form <operator>:<key>:<comparison>:<value>. These are the rows that Filter builds in the interface, and a filtered list shows them in its page address.

curl -H "Authorization: Bearer dfire_ak_abc123..." \
     "https://your-dfire-instance.com/api/cases/?f=and:severity:equals:high&f=not:project:equals:12"

DFIRe reads the rows from left to right, without precedence. The operator and keeps the records that matched so far and also match the row. The operator or adds the records that match the row, and not leaves them out. An or on the first row counts as and. The value is everything after the third colon, so it can hold a colon. Encode it for the URL, for example %20 for a space and %26 for &.

Kind of key Comparisons
Text contains, not-contains, equals, not-equals
Tags The same as text. A row matches when one of the tags matches. A not- comparison matches when no tag does, including on a record without tags.
Choice equals, not-equals
Date after, before

Text and tag comparisons ignore letter case. To match it, add .case to the comparison, as in equals.case. A choice key takes the value the API returns, such as high or amber_strict, or an ID. On the case list, project, lead, phase, category and verdict also take none, which selects the cases without one.

A date is a day (2026-09-30), a minute (2026-09-30T14:05) or an ISO 8601 time with an offset (2026-09-30T14:05:00+03:00). DFIRe reads a day or a minute in UTC. after starts at the next day or minute, and before ends where the day or minute starts. For example, f=and:created:after:2026-09-30 keeps the cases created from 1 October 00:00 UTC.

Endpoints Keys
GET /api/cases/, GET /api/cases/dashboard-stats/ Text: title, number, description. Tags: tags. Choice: severity, status (new, in_progress, resolved), sla (at_risk, breached), mode, type (playbook ID), project, lead (user ID), phase, category (incident category ID), verdict (outcome verdict ID), and system (local or a Dashboard Sync Sender ID) for users who can see remote cases. Date: created, updated, closed.
GET /api/statistics/, GET /api/statistics/cases/ The keys of the case list, without system. Statistics count only the cases of this installation. The response repeats the rows it counted in filters.
GET /api/indicators/, GET /api/indicators/classification-counts/ Text: value, notes. Tags: tags. Choice: type (STIX type), confidence, tlp, published and revoked (yes, no). Date: first_seen, last_seen.
GET /api/audit-logs/ Text: user, record, ip. Choice: action, record_type. Date: time.

The indicator registry has no classification key. Use the classification parameter. A bulk indicator request that selects with filter_params takes the rows as a list in filter_params.f. An unknown key in filter_params returns status 400, and the error names the key. GET /api/audit-logs/action-types/ and GET /api/audit-logs/record-types/ list the values of action and record_type. With include_remote=true, the chain of the case list also applies to the cases received through Dashboard Sync.

A chain holds at most 20 rows, and a value at most 2,048 characters. A row that DFIRe cannot read returns status 400, and the error names the row by its number. The other query parameters of a list keep working, and the chain narrows their result.

List responses

Each entry of GET /api/cases/ carries the tags of the case and updated_at, the time the case record last changed. Its lead_is_service_account is true when the lead investigator is a service account. origin is null for a case on this installation. With include_remote=true, the list also holds the cases received through Dashboard Sync, and their origin is the ID of the Dashboard Sync Sender. Remote cases need the permissions core.view_case and core.view_remotecase. With remote cases, ordering takes only created_at, -created_at and sla.

GET /api/indicators/?tree=true returns the registry as a hierarchy. Each matching indicator comes with the indicators above it. Such a parent has context set to true when it does not match the filters itself. Each row has its depth, 0 at the top level. limit and offset count top-level indicators, and each comes with its rows. The response adds top_level_count.

In the tree, ordering sorts the indicators at each level among themselves. It takes value, stix_type, classification, confidence, tlp, tag_count, case_count, enrichment, is_published, first_seen, last_seen, created_at and updated_at, with a leading - for descending order. Empty values come last in both directions. The default is -updated_at.

GET /api/audit-logs/ sorts by timestamp, user_name, action or target_model. It breaks ties on the entry ID, so paging through the log never skips or repeats an entry.

For a user with the permission auth.change_user, GET /api/users/ lists every account. For other users it lists only the active accounts, without service accounts. With include_service_accounts=true, their list also holds the active service accounts.

GET /api/cases/tags/ and GET /api/indicators/tags/ return the most used tags. See case tags and indicator tags.

Security Best Practices

  • Use service accounts for integrations. Avoid using personal API keys for automated systems. Service accounts make it clear which permissions are granted to which integration.
  • Set short expiration dates. Rotate keys regularly. Use the shortest lifetime that is practical for your integration.
  • Store keys in secrets managers. Never hardcode API keys in scripts, configuration files, or version control. Use your platform's secrets management (AWS Secrets Manager, HashiCorp Vault, environment variables).
  • Apply least privilege. Create dedicated groups with minimal permissions for each integration. A SIEM connector that only reads cases should not have write access.
  • Monitor usage. Review API key usage statistics and audit logs regularly. Disable keys that show unexpected activity or are no longer in use.
  • Disable before deleting. If you suspect that a key has leaked, disable it first. The key stops working immediately. Whoever held the key could act as its account, so also check that account for other keys you do not recognize. Then investigate before deciding whether to delete or regenerate.