Integrations

Webhooks and Email

Tell an external system, or a person, when something happens in DFIRe.

Overview

A notifier watches for events and delivers on one of two channels. A Webhook notifier sends an HTTP POST request to a URL you configure. Use it for SIEMs, ticketing tools, paging services, or custom automation. An Email notifier sends a message to the people you name. See Email notifiers.

Webhook Secrets let you store sensitive values like API keys and reference them in webhook payloads.

Notifiers live in Settings > Webhooks & Email. The page has two tabs: Notifiers (for the notifiers themselves) and Webhook secrets (for stored credentials).

Outgoing Webhooks

Outgoing webhooks send HTTP POST requests to a configured URL when specific events occur in DFIRe. Use them to integrate with notification services (Pushover, PagerDuty), ticketing systems (Jira, ServiceNow), SIEMs, or custom automation.

Creating an Outgoing Webhook

  1. Click "Add notifier" in the Outgoing Webhooks section
  2. Configure basic settings
    • Name: Descriptive name for the webhook
    • Endpoint URL: The URL to receive webhook payloads. DFIRe refuses a loopback or link-local address, including the cloud metadata address. It also refuses its own hostnames, since a webhook to itself would loop. Other private network addresses are accepted, so a webhook can reach another service on the same network
    • Description: Optional description of what this webhook does
  3. Select trigger events

    Choose which events should trigger this webhook.

  4. Optionally set a content filter

    Restrict which events fire the webhook by trigger tag (for runbook and automation events) or by timeline content. See Trigger tags.

  5. Configure authentication
  6. Customize the payload template
  7. Save the webhook

Email notifiers

Every notifier has a channel, chosen at the top of the editor. A Webhook notifier sends an HTTP request to a URL. An Email notifier sends a message to the people you name. Both channels share everything else: the trigger events, the content filter, the value mappings and the same template variables. While you write, switching the channel keeps what you typed on the other side, so you lose nothing by trying one and going back. A saved notifier keeps the fields of the channel it was saved on.

An email notifier needs Email Delivery configured. Until you select a provider there, the editor offers the Webhook channel only, and the Email channel names what to configure. A notifier already on the Email channel stays on it, and records a failed delivery instead of sending.

DFIRe sends the body inside the installation's layout: a header above it and a footer below. The message carries an HTML part and a plain text part. The plain text part is the Markdown source rather than a rendering of it.

FieldWhat to enter
RecipientsOne line, separated by commas. Mix typed addresses and variables in any order, for example [email protected], {{email.case_lead}}. A variable with nobody behind it renders as nothing, and DFIRe still writes to the addresses beside it.
SubjectA single line. DFIRe refuses a subject that carries a line break.
BodyWritten in Markdown: headings, lists, tables, links, images, fenced code and task lists. DFIRe gives a table borders and padding that mail clients show, since they read no stylesheet. HTML written inside it is cleaned the same way the layout is. Leave it empty to send the subject alone.
Plain text onlyOff by default. On, the notifier sends the text part alone, with no header, footer or logo. Use it for a destination that parses the message rather than reads it, such as a pager gateway or a ticketing inbox.

Seven variables resolve to addresses, and every event carries all of them:

  • {{email.user}}, the address of whoever user.* names
  • {{email.account}}, the address of the account an account event is about
  • {{email.case_lead}}, the lead investigator on the case
  • {{email.case_team}}, the lead investigator and the investigators
  • {{email.message_recipient}}, the person a notification is addressed to
  • {{email.superusers}}, every active superuser
  • {{email.tenant_owner}}, the organization contact address

The editor offers these beside the Recipients field, and the full list is under EMAIL.*.

How a value renders

A variable renders as typed. An asterisk in a case title arrives as an asterisk, and a link typed into one stays text. Nobody puts markup into a message by naming a case after it.

Add |markdown to render a value that holds Markdown, as in {{case.description|markdown}}. Four fields hold Markdown: case.description, event.description, event.details and message.body. DFIRe cleans a rendered value the same way it cleans the rest of the message. The modifier applies to the body and changes nothing in the subject, the recipients or a webhook payload.

Who may receive

DFIRe writes to the address of an active user account, and to any address whose domain the Email Delivery page lists. It refuses every other address. A refusal goes on the delivery record with its reason, and nothing reaches that address. When DFIRe accepts nobody, the delivery fails and the record says why. The editor's preview marks each rendered address, so a refusal shows before you save the notifier.

A stored secret never reaches a mailbox. On the email channel, a {{secret.name}} reference renders as nothing.

Preview and test

Select Preview to render the recipients, the subject and the message against sample data. The addresses that belong to one person resolve to your own account, so a preview never shows somebody else's address. The superuser and organization contact addresses resolve for real. The preview marks each address accepted or refused, with the reason beside a refused one.

The preview shows the assembled message in a frame, with its plain text part on its own tab. Read what the recipient reads before you save the notifier. A notifier set to plain text only has no HTML part, so the preview shows the text alone.

Select Test to send one real message, with the same substitution the preview used. The result names the addresses it reached and the ones it refused.

What the delivery log shows

Open a notifier's delivery history for the recipients, the subject, and each refused address with its reason. A message waiting for the per-minute cap shows as retrying, with the cap named as the reason. An email delivery carries no HTTP status code, because no server answers it. DFIRe does not keep the message itself.

Trigger Events

Select one or more events that should trigger the webhook. The editor groups them into the same families this table uses:

Event Description
Cases and evidence
Incident Created A new incident case was created
Investigation Created A new investigation case was created
Case Closed A case was closed
Case Archived A case was archived
Case Reopened A closed case was reopened
Investigation Escalated to Incident An investigation was escalated to incident mode
Severity/Priority Escalated Case severity was increased (e.g., medium to high)
Severity/Priority Downgraded Case severity was decreased
Incident Phase Changed Incident moved to a different response phase
Timeline Event Created A new timeline event was added to a case
CAN Report Updated A new CAN (Conditions, Actions, Needs) report version was created
Case Team Changed A case gained or lost a lead investigator, an investigator or a viewer. Read meta.change for which of the five it was, and meta.usernames for the people it moved.
Evidence Added New evidence item was added to a case
Evidence Status Changed Evidence item's investigation step changed
Compliance timers
Timer at 50% (Half Time Warning) Compliance timer reached 50% of its duration
Timer at 25% (Quarter Time Warning) Compliance timer reached 75% elapsed (25% remaining)
Timer at 10% (Critical Warning) Compliance timer reached 90% elapsed (10% remaining)
Timer Breached (Deadline Passed) Compliance timer deadline has passed
Indicators
IOC Added to Case An indicator was associated with a case
IOC Classification Changed An indicator's classification was changed (e.g., unknown to malicious)
IOC Classified as Malicious An indicator was classified as malicious
IOC Classified as Suspicious An indicator was classified as suspicious
IOC Classified as Benign An indicator was classified as benign
IOC Published An indicator was published to TAXII/MISP feeds
IOC Unpublished A published indicator was unpublished
IOC Revoked An indicator was revoked (no longer considered valid)
IOC Unrevoked A revoked indicator was restored
IOC Cross-Case Correlation An indicator added to a case was already present in other cases
Playbooks and automation
Runbook Step Completed A runbook step was marked complete. Its trigger tag travels with the event, so a content filter can narrow delivery to the tagged steps. Filter by its trigger tag with the content filter.
Automation Rule Triggered An automation rule's "Fire a webhook" action matched. Filter by its trigger tag with the content filter.
Playbook Review Due A playbook's review deadline is close, or has passed. See Playbook review reminders.
Accounts and system
User Notification An in-app notification was sent to a user. High volume: this fires for every notification.
User Mentioned A user was mentioned with @. Fires only for mentions, so an external target can subscribe to it without the full notification volume.
User Logged In Somebody signed in. meta.login_method is password or sso, and meta.second_factor names the second factor when the sign-in needed one.
Login Failed DFIRe refused a sign-in, and meta.reason says why. The ACCOUNT.* variables name the account the attempt was for, even when no such account exists.
User Created An administrator created an account, or a first SSO sign-in did. meta.created_via says which.
User Deactivated or Roles Changed An administrator switched an account off or back on, or gave it a different set of roles. meta.change says which, and a role change also carries meta.roles_before and meta.roles_after.
API Key Created DFIRe issued an API key value for an account. The event names the key in meta.key_name and never carries its value.
Report Finalized An investigation report reached version 1.0 and is ready for the stakeholder. See REPORT.* variables.
Backup Finished A backup run ended, on both outcomes, whether someone started it or the schedule did. See BACKUP.* variables.
DFIRe Update Available The license server offers a newer DFIRe release. It fires once per version, so the daily check does not repeat a release you already know about. See UPDATE.* variables.
Test Event (Manual Testing) Used for testing webhook configuration

Trigger tags and the content filter

Some events carry a trigger tag. A short identifier that lets a single event type fan out to different webhooks. Three features in DFIRe emit tagged events:

  • IOC triggers. Custom response buttons on IOC Intelligence pages, defined under Settings → IOC Enrichment. Each one appears in the event list above as its own IOC Trigger: name entry; subscribe to the specific trigger you want. No content filter is needed. Each trigger is its own event. See Configuration. Webhook Triggers.
  • Runbook triggers. A tag on a runbook step. Marking the step complete fires the Runbook Step Completed event carrying that tag.
  • Automation triggers. The trigger tag on an automation rule's "Fire a webhook" action. The rule fires the Automation Rule Triggered event carrying that tag.

For the Runbook Step Completed and Automation Rule Triggered events, the content filter is a regex matched against the trigger tag. Leave it empty to fire on every tag, or set a specific tag. Or a pattern such as account_disabled|notify_soc. To choose which ones reach this webhook. Because both events filter on the same kind of tag, one webhook can serve several rules, or be shared by a runbook step and an automation rule that carry the same tag.

For Timeline Event Created, the content filter instead matches the event's title and description. For example, @page fires the webhook only for timeline entries containing "@page".

For the five account events, the content filter matches the username of the account the event is about. On a failed login that is the username somebody tried, which may belong to no account. Leave it empty to match every account.

A content filter is at most 255 characters. Matching ignores case. DFIRe reads the shape of the pattern and refuses one that can take unlimited time to match, because such a filter stalls webhook delivery. DFIRe refuses these shapes:

  • A repeated group whose contents repeat or offer alternatives, such as (a+)+, (a+){15} or (a|aa)+.
  • Two repeats written next to each other, such as a*a*b or (a*)(a*)b.
  • More than two open-ended repeats, such as ^a.*a.*a.*b$, or more than one in a pattern that does not start with ^, such as a.*a.*b.
  • An inline flag, such as (?i) or (?x).

Because the check reads the shape rather than trying the pattern, it also refuses some patterns that would match quickly. Write the filter as a keyword match. DFIRe accepts patterns such as ransom, ransom|extortion, (malware|phish)ing, ^CASE-\d{4}-\d{3}$ and \d{1,3}\.\d{1,3}.

Playbook review reminders

The Playbook Review Due event reports that a playbook needs reading through again. It does not report a review. Nothing about it says a person looked at the playbook, only that its deadline is close or has passed.

A daily job checks every playbook against its deadline. Each reminder day configured under Settings → Playbook Policy fires the event once, and the deadline itself fires it once more. A playbook with reminders at 30 and 7 days produces three events in a review cycle. One a month out, one a week out, one on the day.

Each threshold fires once per review cycle. Recording a review, or changing the review period, starts a new cycle and the reminders begin again. If DFIRe was down when a threshold passed, the next run sends one reminder for the most urgent threshold it has crossed. It marks the ones it skipped as sent. An overdue playbook produces no backlog of missed warnings.

A webhook subscribed after a threshold has fired does not receive that threshold. It receives the next one, in the same way as compliance timer subscriptions.

Delivery is at least once. The payload carries playbook.event_id, and it stays the same across every retry of one reminder. A receiver that may see a duplicate can drop it on that value. The PLAYBOOK.* variables list what a reminder carries.

Authentication

DFIRe supports four authentication methods for outgoing webhooks:

Method Description
None No authentication. Use when the endpoint doesn't require auth or when credentials are in the payload.
Basic Auth HTTP Basic Authentication. Provide username and password.
Bearer Token Sends an Authorization: Bearer <token> header. Provide the token value.
Custom Headers Add custom HTTP headers, for example X-API-Key. Header values are encrypted at rest, but they are returned when the webhook is opened, so anyone who can view the webhook can read them. Keep API keys and tokens in Webhook Secrets and put {{secret.name}} in the header value instead. A secret's value is never shown again after you save it.

Payload Templates

Customize the JSON payload sent to your endpoint using template variables. If you leave the payload template empty, DFIRe sends a default payload: the event type, the timestamp and the notifier name, then every variable category the event carries. A stored secret is never part of it.

Template Variable Syntax

Use double curly braces to insert variable values:

  • {{category.variable}} - Insert the raw value
  • {{category.variable|mapped}} - Apply value mappings before inserting

Available Variables

Variables are organized by category:

META.* (Request Metadata)

meta.event_typeThe event that triggered this webhook
meta.timestampWhen the event occurred (ISO 8601)
meta.webhook_nameName of this webhook configuration
meta.base_urlDFIRe instance base URL
meta.case_urlDirect URL to the case
meta.item_urlDirect URL to the evidence item (if applicable)
meta.ioc_urlDirect URL to the indicator (if applicable)
meta.tenant_nameOrganization name
meta.tenant_uuidTenant identifier
meta.environmentEnvironment (production, development)
meta.previous_severityPrevious severity (for severity change events)
meta.new_severityNew severity (for severity change events)
meta.old_classificationPrevious classification (for IOC classification change events)
meta.new_classificationNew classification (for IOC classification change events)
meta.indicator_idIndicator database ID (for IOC events)
meta.indicator_valueIndicator value (for IOC events)
meta.indicator_typeIndicator STIX type (for IOC events)

CASE.* (Case Information)

case.idCase UUID
case.case_numberCase number (e.g., CASE-2026-001)
case.titleCase title
case.descriptionCase description
case.statusCase status (open, closed, archived)
case.severitySeverity level (info, low, medium, high, critical)
case.case_modeCase mode (investigation, incident)
case.phase_nameCurrent incident phase name
case.phase_orderCurrent incident phase order
case.case_type_nameCase type name
case.lead_investigatorLead investigator username
case.created_atCase creation timestamp
case.updated_atLast update timestamp

EVENT.* (Timeline Event Information)

event.idEvent UUID
event.event_typeEvent type (MANUAL, AUTO, etc.)
event.titleEvent title/subject
event.descriptionEvent description
event.subjectEvent subject
event.detailsEvent details
event.is_manualWhether this is a manual entry
event.actor_usernameUser who created the event
event.event_datetimeWhen the event occurred
event.created_atWhen the event was recorded
event.metadataAdditional event metadata (JSON)

ITEM.* (Evidence Item Information)

item.uuidEvidence item UUID
item.nameEvidence item name
item.item_type_nameEvidence type name
item.status_nameCurrent investigation step
item.locationStorage location
item.created_atWhen the item was added

IOC.* (Indicator Information)

ioc.idIndicator database ID
ioc.valueIndicator value (for example an IP address, domain, or hash)
ioc.stix_typeSTIX type (for example ipv4-addr, domain-name, file)
ioc.classificationClassification (unknown, benign, suspicious, malicious)
ioc.confidenceConfidence level (low, medium, high)
ioc.tagsTags as a list
ioc.public_notesPublic notes on the indicator
ioc.first_seenFirst seen timestamp
ioc.last_seenLast seen timestamp
ioc.created_atWhen the indicator was created
ioc.stix_scoThe indicator as a STIX 2.1 Cyber Observable object
ioc.stix_sdoThe indicator as a STIX 2.1 Indicator object

For a classification change, the previous and new values are in meta.old_classification and meta.new_classification.

USER.* (The Person the Event Names)

On a case event this is the lead investigator. Four events name someone else:

  • a timeline event, its actor
  • a CAN report update, the author of the version
  • a runbook step completion, whoever ticked the step
  • a user notification or mention, the recipient

An event with no case, such as an IOC publication or the playbook review reminder, carries nothing here.

On an account event this is whoever acted. On a sign-in that is the person who signed in. On an account an administrator created or a key they issued, it is the administrator. A failed login carries nothing here, because nobody proved who they were. The account the event is about is ACCOUNT.*.

user.idUser ID
user.usernameUsername
user.emailEmail address
user.first_nameFirst name
user.last_nameLast name
user.phone_numberPhone number, when set
user.timezonePreferred timezone, when set
user.slack_user_idSlack member ID, when the account is linked
user.slack_usernameSlack username, when the account is linked

ACCOUNT.* (The Account an Account Event Is About)

Available on the five account events. These variables describe the account the event is about. That is not always the person who acted. When an administrator creates an account or issues a key, user.* names the administrator and account.* names the account.

account.idUser ID, empty on a failed login for an account that does not exist
account.usernameUsername. On a failed login, the username that was tried
account.emailEmail address
account.first_nameFirst name
account.last_nameLast name
account.phone_numberPhone number, when set
account.timezonePreferred timezone, when set
account.slack_user_idSlack member ID, when the account is linked
account.slack_usernameSlack username, when the account is linked
account.is_superuserTrue for a System Root account
account.is_activeFalse once the account is switched off
account.rolesThe account's roles, comma separated

A failed login for a username that belongs to no account fills account.username with what was typed and leaves the rest empty.

MESSAGE.* (Notification)

Present on the User Notification and User Mentioned events. The user.* category then describes the person being notified.

message.titleNotification title
message.bodyNotification body
message.typeNotification type (for example CASE_ASSIGNED, MENTION, TIMER_WARNING)
message.sender_nameWho or what raised the notification
message.target_modelWhat the notification points at (Case, Item, Attachment)
message.target_idID or UUID of that target
message.case_idCase ID, when the notification belongs to a case
message.created_atWhen the notification was raised

CAN.* (CAN Report)

can.conditionsConditions section
can.actionsActions section
can.needsNeeds section
can.versionVersion number of this CAN report
can.created_byUsername of the author
can.created_atWhen this version was created

RUNBOOK_STEP.* (Runbook Step Completed)

Runbooks attach to an evidence item or to a case action. A case action has no evidence item, so the item.* variables render as nothing for a step completed on one.

runbook_step.orderPosition of the step in the runbook
runbook_step.instructionThe step's instruction text
runbook_step.trigger_tagThe step's trigger tag
runbook_step.runbook_nameName of the runbook
runbook_step.runbook_slugSlug of the runbook

EMAIL.* (Addresses)

Available on every event, on both channels. An email notifier addresses its message with these. A webhook can carry them in its payload like any other variable. A variable with nobody behind it renders as nothing.

email.userThe address of whoever user.* names
email.accountThe address of the account an account event is about
email.case_leadThe lead investigator on the case
email.case_teamThe lead investigator and the investigators, comma separated
email.message_recipientThe person a notification is addressed to
email.superusersEvery active superuser, comma separated
email.tenant_ownerThe organization contact address

DFIRe skips an account that cannot receive: a deactivated one, one with no address, and a service account.

AUTOMATION.* (Automation Rule Triggered)

automation.rule_nameName of the rule that fired
automation.trigger_tagThe rule's trigger tag
automation.trigger_eventThe case event that started the rule

TIMER.* (Compliance Timer Information)

timer.idTimer ID
timer.nameTimer name (e.g., "GDPR 72h")
timer.frameworkCompliance framework
timer.duration_hoursTotal duration in hours
timer.authority_nameRegulatory authority
timer.threshold_triggeredWhich threshold was triggered (50, 25, 10, 0)
timer.time_remaining_secondsSeconds remaining until deadline
timer.deadlineDeadline timestamp

PLAYBOOK.* (Playbook Review Due)

Available on the Playbook Review Due event only. The reminder carries no case, so the case variables are empty for it.

playbook.idPlaybook ID
playbook.namePlaybook name
playbook.descriptionWhat the playbook covers
playbook.creatorThe author label, from the playbook's Author field
playbook.urlDirect URL to the playbook, empty when no base URL is configured
playbook.owner_namesList of the active users listed as owners. A role listed as an owner is reported as the role, not as the people in it
playbook.owner_group_namesList of the roles listed as owners. The reminder reaches their members too
playbook.owner_summaryBoth lists on one line, people first, comma separated. Empty when the playbook has no owner
playbook.owner_statusassigned when either owner list names anything, unassigned when both are empty, inactive when the playbook names users, names no role, and every listed user has been deactivated
playbook.created_atCreation date, null when the playbook has none
playbook.updated_atWhen the definition last changed
playbook.last_reviewed_atWhen the playbook was last reviewed, null when never
playbook.last_reviewed_by_nameWho recorded that review
playbook.revisionCurrent revision of the definition
playbook.last_reviewed_revisionRevision the last review certified
playbook.changed_since_reviewTrue when the definition changed after the last review
playbook.never_reviewedTrue when no review has ever been recorded
playbook.review_period_daysThe review period in force
playbook.review_due_atReview deadline
playbook.review_statuscurrent, due_soon or stale
playbook.days_until_staleWhole days to the deadline, rounded up. It reads 0 from the deadline until a day past it, then negative
playbook.warning_daysThe reminder day that fired. 0 is the deadline itself
playbook.event_idIdentifier of this reminder, stable across retries
playbook.triggered_atWhen the reminder fired

DFIRe decides the status on the exact deadline timestamp, not on the day count. A playbook that has just passed its deadline therefore reports days_until_stale of 0 and a status of stale.

owner_names and owner_group_names are lists. A list placed inside quotes in a template arrives as its JSON text. The receiver reads the string ["Ada Lovelace"] rather than a name. Use owner_summary where you want a readable line.

Select the event in the webhook editor. While the payload template is still empty, Insert example fills it with a template built from these variables:

{
  "event": "{{meta.event_type}}",
  "event_id": "{{playbook.event_id}}",
  "playbook": "{{playbook.name}}",
  "owners": "{{playbook.owner_summary}}",
  "status": "{{playbook.review_status}}",
  "due": "{{playbook.review_due_at}}",
  "url": "{{playbook.url}}"
}

REPORT.* (Report Finalized)

report.versionThe version the report reached. The first finalization sets it to 1.0
report.finalized_atWhen the report was finalized
report.finalized_byUsername of the person who finalized it
report.report_urlDirect URL to the report, empty when no base URL is configured

BACKUP.* (Backup Finished)

A backup covers the whole installation, so the event carries no case and the case variables are empty for it. The user variables name whoever asked for the backup, and stay empty on a scheduled run.

backup.statuscompleted or failed
backup.started_atWhen the run started
backup.finished_atWhen the run ended
backup.size_bytesSize of the backup file. Empty when the run produced no file
backup.errorWhy the run failed. Empty when it succeeded
backup.descriptionThe description recorded with the backup. A scheduled run records "Scheduled backup"

UPDATE.* (DFIRe Update Available)

The daily license check carries the update information, so the event has no case and no acting user.

update.current_versionThe version this installation runs
update.latest_versionThe version the license server offers
update.urgencyavailable, recommended or critical
update.release_notesWhat the release changes

SECRET.* (Stored Secrets)

Reference secrets stored in the Secrets tab:

  • {{secret.<name>}} - Replaced with the secret value at send time

For example, {{secret.pushover_api_token}} inserts the value of a secret named "pushover_api_token".

Value Mappings

Value mappings transform field values before inserting them into the payload. This is useful when the receiving system expects different values than DFIRe uses.

Configuration

Define mappings as a JSON object where keys are field names and values are mapping dictionaries:

{
    "severity": {
        "info": -2,
        "low": -1,
        "medium": 0,
        "high": 1,
        "critical": 2
    },
    "event_type": {
        "MANUAL": "Manual timeline event",
        "AUTO": "Automatic system event"
    }
}

Usage

Use the |mapped filter to apply mappings:

  • {{case.severity}} outputs: critical
  • {{case.severity|mapped}} outputs: 2 (using the mapping above)

This is especially useful for integrating with services like Pushover that use numeric priority levels, or for translating DFIRe field values to match your organization's terminology.

Payload Preview

Click "Preview Payload" to see how your template will render with sample data. The preview shows the actual JSON that would be sent, with variables replaced by example values. This helps verify your template syntax and mappings before saving.

Additional Outgoing Webhook Settings

Retry Configuration

  • Max Retries: Number of retry attempts for failed deliveries (default: 3)
  • Timeout (Seconds): How long to wait for a response (default: 30)

HMAC Signing

Optionally configure a signing secret to allow the receiving endpoint to verify that requests came from DFIRe:

  • If set. DFIRe includes an X-Webhook-Signature header with an HMAC-SHA256 signature
  • The signature is computed over the request body using your secret
  • Leave empty to skip signing

The header value carries a sha256= prefix ahead of the hex digest, for example X-Webhook-Signature: sha256=9f86d081884c7d65.... Strip the prefix before comparing, or compare against the prefixed form as the example below does.

Verifying Signatures

# Python example
import hmac
import hashlib

def verify_signature(payload_body, signature_header, secret):
    expected = hmac.new(
        secret.encode(),
        payload_body,
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(f"sha256={expected}", signature_header)

Webhook Secrets

Store sensitive values like API keys and tokens securely, then reference them in webhook payloads.

Creating a Secret

  1. Go to Settings > Webhooks & Email, Webhook secrets tab
  2. Click Add Secret
  3. Enter a name (used to reference the secret in templates)
  4. Enter an optional description
  5. Enter the secret value
  6. Click Save

Using Secrets in Payloads

Reference secrets using the syntax {{secret.secret_name}}. The actual value is substituted when the webhook is sent:

{
    "token": "{{secret.pushover_token}}",
    "user": "{{secret.pushover_user}}",
    "message": "Case {{case.case_number}} - {{case.title}}"
}

Security

  • Secret values are encrypted at rest using the CREDENTIAL_ENCRYPTION_KEY
  • Values are never exposed in API responses or delivery logs
  • Only the secret name and description are visible after creation
  • You can update or delete secrets, but cannot view the stored value

Example: Pushover Notifications

This example shows how to send mobile push notifications via Pushover when someone adds "@page" to a timeline event.

1. Create Secrets

Store your Pushover credentials in Webhook Secrets:

  • Create a secret named pushover_api_token with your Pushover application token
  • Create a secret named pushover_api_user with your Pushover user key

2. Create the Webhook

  • Name: Pushover on Timeline @page event
  • Endpoint URL: https://api.pushover.net/1/messages.json
  • Trigger Events: Timeline Event Created
  • Content Filter: @page
  • Authentication: None (credentials are in the payload)

3. Configure the Payload Template

{
    "token": "{{secret.pushover_api_token}}",
    "user": "{{secret.pushover_api_user}}",
    "title": "You have been paged for {{case.case_number}} {{case.title}}",
    "message": "You have been paged by {{event.actor_username}} on case {{case.case_number}}:\n\n{{event.event_type|mapped}}: {{event.title}}, {{event.description}}.\n\nYou can access the incident here: {{meta.case_url}}",
    "priority": "{{case.severity|mapped}}"
}

4. Configure Value Mappings

{
    "severity": {
        "info": -2,
        "low": -1,
        "medium": 0,
        "high": 1,
        "critical": 2
    },
    "event_type": {
        "MANUAL": "Manual timeline event"
    }
}

Now, when anyone adds a timeline event containing "@page", the on-call team receives a push notification with case details and a direct link.

Webhook Management

Testing Webhooks

Use the play button on a webhook card to send a test event. This fires the "Test Event (Manual Testing)" trigger with sample data.

Enabling/Disabling

Toggle the switch on a webhook card to enable or disable it without deleting the configuration. Disabled webhooks are not triggered.

Duplicating Webhooks

Use the copy button to duplicate a webhook configuration. This is useful for creating similar webhooks with minor variations.

Delivery History

Click on a webhook to view recent delivery attempts showing:

  • Success or failure status
  • HTTP response code
  • Response time
  • Timestamp

Retry Behavior

Failed deliveries are retried automatically, one minute after the first failure, then five minutes, then every thirty minutes. After the configured number of retries, the delivery is marked as failed but the webhook remains active for future events. A retried payload is rebuilt at retry time, so it reflects the current state of the case rather than its state when the event fired. The Playbook Review Due reminder is the exception. DFIRe captures its payload when the reminder fires and sends that same payload with every retry, even after the playbook has been edited, reviewed or deleted.

Security Best Practices

  • Use HTTPS: Always use HTTPS endpoints for webhooks
  • Use Secrets: Store API keys and tokens in Webhook Secrets rather than hardcoding in templates
  • Enable Signing: Configure a signing secret and verify signatures in your receiving application
  • Restrict Access: If possible, whitelist DFIRe's IP address in your receiving application
  • Monitor Failures: Review delivery history for failures that might indicate configuration issues
← Automation API access →