Webhooks technical reference

This page provides an overview of technical information about Unit21 webhooks. For the corresponding Webhooks API reference, see here

Broadly, webhooks fall into two categories:

  • Agent-initiated webhooks, like a opening or closing an alert.
  • System-triggered webhooks, like when a rule triggers an alert.

Each webhook event sends a specific JSON request body to the URL you configured.

Webhooks send a maximum of three requests

When it sends webhooks requests, Unit21 sends a maximum of 3 requests for a single webhook. A retry is attempted when a status code between 400 and 600 is received or if an error occurred when attempting the request (ex. the server refusing a connection).

If the first attempt fails, the Unit21 system waits one second before attempting the webhook request a second time. If the second retry fails, the system waits 2 seconds before retrying a third time. On the dashboard page for the specific webhook, it displays the number of retries attempted, along with the request's unique callback_id.

Webhook types

The following tables describe the webhooks you can send for each resource.

Alerts

See corresponding request bodies for alerts and for alert components.

Alert eventdescription
ALERT_CREATEDWhen an alert is triggered
ALERT_REOPENEDWhen an agent re-opens a previously closed alert
ALERT_REOPENEDWhen an agent re-opens a previously closed alert
ALERT_CLOSEDWhen an alert is closed
ALERT_ACTION_TRIGGEREDWhen an agent clicks an alert’s action buttons
ALERT_COMPONENT_ACTION_TRIGGEREDWhen alert component action buttons are clicked via the alert detail pane

Cases

See corresponding request body.

Case eventdescription
CASE_CREATEDWhen a case is created
CASE_REOPENEDWhen a previously closed case is re-opened
CASE_CLOSEDWhen a case is closed
CASE_ACTION_TRIGGEREDWhen a case action runs

Entities

Entities eventdescription
ENTITY_ACTION_TRIGGEREDWhen an entity action runs (executed from an entity’s details pane
ENTITY_FLAGGEDWhen an entity is flagged

Rules

See corresponding request body.

Rules eventdescription
RULE_TRIGGEREDWhen a rule is executed
RULE_CREATEDWhen an agent deploys a rule
RULE_ACTION_TRIGGEREDwhen an agent runs a rule action

Verifications and events

See corresponding request body.

Eventdescription
EVENT_ACTION_TRIGGEREDWhen an agent selects an event action button
VERIFICATION_MANUAL_REVIEW_NEEDEDWhen verification returns the state "manual review needed"
VERIFICATION_WORKFLOW_EXECUTEDWhen a verification workflow is executed
VERIFICATION_ENTITY_STEP_COMPLETEDWhen entity verification is completed
VERIFICATION_ENTITY_INITIATEDWhen verification initiations for an entity
VERIFICATION_AUTO_APPROVEDWhen verification is approved
VERIFICATION_AUTO_REJECTEDWhen verification is rejected
VERIFICATION_RFI_RESPONSE_RECEIVEDcurrently unavailable

Webhooks request bodies

Each webhook type has a corresponding request body.

Alert request bodies

Sample webhook request body of a change-triggered or action-triggered webhook for an Alert:

{
  "unit21_id": 123,
  "object_type": "ALERT",
  "alert_id": null,
  "alert_type": "tm",
  "change": "CLOSED",
  "change_time": 1570062682,
  "disposition": "TRUE_POSITIVE",
  "subdisposition": "Suspected ATO",
  "disposition_notes": "User confirmed that she did not initiate transaction",
  "status": "CLOSED",
  "changed_by": "[email protected]",
  "title": "Sample alert title",
  "description": "Sample alert description",
  "start_date": 1570052582,
  "end_date": 1570062582,
  "entities": [
    {
      "entity_id": "entity-886313e1",
      "entity_type": "user",
      "unit21_id": 46,
      "resolution": null
    },
    {
      "entity_id": "entity-91a31re2",
      "entity_type": "user",
      "unit21_id": 72,
      "resolution": "false_positive"
    }
  ],
  "events": [
    {
      "event_id": "event-1063e4e3e1",
      "event_type": "transaction",
      "unit21_id": 111,
      "resolution": null
    }
  ],
  "instruments": [
    {
      "instrument_id": "instrument-4112950a",
      "instrument_type": "wallet",
      "unit21_id": 401,
      "resolution": null
    }
  ],
  "triggered_by_rules": [{ "unit21_id": 6, "rule_id": null }],
  "assigned_to": "[email protected]",
  "tags": ["rule_type:layering"],
  "custom_data": { "bank_notes": "Previously flagged" }
}

For alerts that are CREATED, REOPENED, CLOSED or ACTION_TRIGGERED, the following fields are sent:

Field NameValue TypeDetails
action_trigger_external_idStringA unique identifier for the action trigger that triggered this webhook - configurable in the webhook configuration page
unit21_idNumberA Unit21 internally-assigned unique identifier for the alert within our system
object_typeStringAlways takes on the value ALERT for alert webhooks
alert_idStringA non-Unit21 identifier for the alert
alert_typeStringA string representing the type of alert
changeStringA Unit21-defined value describing the nature of the change to this alert. For more details on this, see above section Change trigger types
change_timeNumberTime the change was triggered in Epoch time format (number of seconds elapsed since 1 Jan 1970 00:00:00 UTC)
dispositionStringA state that represents either the alert's resolution or a designation for further actions. This field can be defined by an action trigger button, where each action trigger corresponds to one disposition.
subdispositionStringA sub-state that represents either the alert's resolution or a designation for further actions. This field can be be defined by an action trigger button, where each action trigger allows for agents to dynamically select a subdisposition during alert investigation from a list of predefined values in the action trigger configuration process.
disposition_notesStringA free text field that contains agent-entered elaborations on the alert's disposition. A non-empty value may be required by the action trigger depending on the action trigger configuration.
statusStringOne of OPEN or CLOSED
changed_byStringEmail address of the agent that triggered the status change (if applicable)
titleStringTitle assigned to the alert
descriptionStringA high level descriptive phrase about the alert
start_dateNumberStart datetime of the events or entities encapsulated by this alert in Epoch time format (number of seconds elapsed since 1 Jan 1970 00:00:00 UTC)
end_dateNumberEnd datetime of the events or entities encapsulated by this alert in Epoch time format (number of seconds elapsed since 1 Jan 1970 00:00:00 UTC)
entitiesObject[]An object list of entities flagged by the rule. Each object contains a Unit21 ID, the entity type (user or business), a non-Unit21 identifier, and a resolution
eventsObject[]An object list of events flagged by the rule. Each object contains a Unit21 ID, the event type (transaction or action), a non-Unit21 identifier, and a resolution
instrumentsObject[]An object list of instruments flagged by the rule. Each object contains a Unit21 ID, the instrument type, a non-Unit21 identifier, and a resolution
triggered_by_rulesObject[]A list of rule object(s) that triggered this alert, each consisting of a Unit21 ID and a non-Unit21 identifier for the rule
assigned_toStringEmail address of the agent that the alert was assigned to at the time of the status change
tagsString[]A list of tags that are associated with this alert, always of the format key:value
custom_dataObjectAny custom information that you wish our system to associate with this alert (accepts any valid JSON object)

Any fields that are not populated take on a null value.

Alert Component request bodies

Sample webhook request body of a change-triggered or action-triggered webhook for an Alert Component Action:

{
  "action_trigger_external_id": "CUSTOM-UNIQUE_ID",
  "object_type": "ALERT",
  "alert_id": null,
  "unit21_id": 332,
  "alert_type": "TM",
  "change": "ALERT_COMPONENT_ACTION",
  "change_time": 1596688934,
  "changed_by": "[email protected]",
  "changed_events": [],
  "changed_entities": [
    {
      "entity_id": "userA-4962d5a7-cb12-4fc5-8f72-eb8c203701ca",
      "entity_type": "user",
      "unit21_id": 599,
      "resolution": "FALSE_POSITIVE"
    },
    {
      "entity_id": "userB-4962d5a7-cb12-4fc5-8f72-eb8c203701ca",
      "entity_type": "user",
      "unit21_id": 600,
      "resolution": "FALSE_POSITIVE"
    }
  ],
  "changed_instruments": [],
  "tags": []
}

In addition to the alert level status/disposition, actions/dispositions can be defined on the entities/events/instruments that comprise an alert. For the alert components ACTION_TRIGGERED, the following fields are sent:

Field NameValue TypeDetails
action_trigger_external_idStringA unique identifier defined at button create time
object_typeStringAlways takes on the value ALERT for alert component webhooks
alert_idStringA non-Unit21 identifier for the alert, this will be null unless the alert was created by you through Unit21's api
unit21_idNumberA Unit21 internally-assigned unique identifier for the alert within our system
alert_typeStringA string representing the type of alert
tagsString[]A list of tags that are associated with this alert, always of the format key:value
changeStringA Unit21-defined value describing the nature of the change to this alert. This will be ALERT_COMPONENT_ACTION for any action on alerts' componentes
change_timeNumberTime the change was triggered in Epoch time format (number of seconds elapsed since 1 Jan 1970 00:00:00 UTC)
changed_byStringEmail address of the agent that triggered the status change (if applicable)
changed_eventsObject[]An object list of events changed by the current action. This does not include all events in the alert, only the events that were actively changed. Each object contains a Unit21 ID, the event type (transaction or action), a non-Unit21 identifier, and a resolution well. The resolution is configured on a per button/action basis
entitiesObject[]An object list of entities changed by the current action. This does not include all entities in the alert, only the entities that were actively changed. Each object contains a Unit21 ID, the entity type (user or business), a non-Unit21 identifier, and a resolution. The resolution is configured on a per button/action basis
instrumentsObject[]An object list of instruments changed by the current action. This does not include all instruments in the alert, only the instruments that were actively changed. Each object contains a Unit21 ID, the instrument type, a non-Unit21 identifier, and a resolution. The resolution is configured on a per button/action basis

Case request bodies

Sample webhook request body of a webhook for a case:

{
  "unit21_id": 123,
  "object_type": "CASE",
  "case_id": "case-tt1ops03mns",
  "change": "CLOSED",
  "change_time": 1570062682,
  "changed_by": "[email protected]",
  "disposition": "RESOLVED",
  "subdisposition": "Suspected ATO",
  "disposition_notes": "User confirmed that she did not initiate transaction",
  "title": "Sample case title",
  "description": "Sample case description",
  "start_date": 1570052582,
  "end_date": 1570062582,
  "entities": [
    {
      "entity_id": "entity-886313e1",
      "entity_type": "user",
      "unit21_id": 46,
      "resolution": null
    },
    {
      "entity_id": "entity-91a31re2",
      "entity_type": "user",
      "unit21_id": 72,
      "resolution": "false_positive"
    }
  ],
  "events": [
    {
      "event_id": "event-1063e4e3e1",
      "event_type": "transaction",
      "unit21_id": 111,
      "resolution": null
    }
  ],
  "instruments": [
    {
      "instrument_id": "instrument-4112950a",
      "instrument_type": "wallet",
      "unit21_id": 401,
      "resolution": null
    }
  ],
  "created_by": "[email protected]",
  "watchers": ["[email protected]", "[email protected]", "[email protected]"],
  "tags": ["product_line:lending", "agency:irs"]
}

For cases that are CREATED, REOPENED, CLOSED, or triggered by an action-button, the following fields are sent:

Field NameValue TypeDetails
unit21_idNumberA Unit21 internally-assigned unique identifier for the case within our system
object_typeStringAlways takes on the value CASE for case webhooks
case_idStringA non-Unit21 identifier for the case
changeStringA Unit21-defined value describing the nature of the change to this case. For more details on this, see above section Change trigger types
change_timeNumberTime the change was triggered in Epoch time format (number of seconds elapsed since 1 Jan 1970 00:00:00 UTC)
changed_byStringEmail address of the agent that triggered the status change (if applicable)
dispositionStringA state that represents either the case's resolution or a designation for further actions. This field can be defined by an action trigger button, where each action trigger corresponds to one disposition.
subdispositionStringA sub-state that represents either the case's resolution or a designation for further actions. This field can be be defined by an action trigger button, where each action trigger allows for agents to dynamically select a subdisposition during case investigation from a list of predefined values in the action trigger configuration process.
disposition_notesStringA free text field that contains agent-entered elaborations on the case's disposition. A non-empty value may be required by the action trigger depending on the action trigger configuration.
titleStringTitle assigned to the case
descriptionStringA high level descriptive phrase about the case
start_dateNumberStart datetime of the events or entities encapsulated by this case in Epoch time format (number of seconds elapsed since 1 Jan 1970 00:00:00 UTC)
end_dateNumberEnd datetime of the events or entities encapsulated by this case in Epoch time format (number of seconds elapsed since 1 Jan 1970 00:00:00 UTC)
entitiesObject[]An object list of entities flagged by the rule. Each object contains a Unit21 ID, the entity type (user or business), a non-Unit21 identifier, and a resolution
eventsObject[]An object list of events flagged by the rule. Each object contains a Unit21 ID, the event type (transaction or action), a non-Unit21 identifier, and a resolution well
instrumentsObject[]An object list of instruments flagged by the rule. Each object contains a Unit21 ID, the instrument type, a non-Unit21 identifier, and a resolution
created_byStringEmail address of the agent that created this case initially
watchersString[]A list of email addresses of the agents are listed as watchers on this case
tagsString[]A list of tags that are associated with this case, always of the format key:value

Rule request bodies

Sample webhook request body of a webhook for a Rule:

{
  "unit21_id": 123,
  "object_type": "RULE",
  "rule_id": null,
  "change": "TRIGGERED",
  "change_time": 1570062682,
  "changed_by": "[email protected]",
  "title": "Sample rule title",
  "description": "Sample rule description",
  "deploy_start_date": 1570052582,
  "deploy_end_date": 1570062582,
  "flagged_entities": [
    {
      "entity_id": "entity-886313e1",
      "entity_type": "user",
      "unit21_id": 46,
      "resolution": null
    },
    {
      "entity_id": "entity-91a31re2",
      "entity_type": "user",
      "unit21_id": 72,
      "resolution": "false_positive"
    }
  ],
  "flagged_events": [
    {
      "event_id": "event-1063e4e3e1",
      "event_type": "transaction",
      "unit21_id": 111,
      "resolution": null
    }
  ],
  "flagged_instruments": [
    {
      "instrument_id": "instrument-4112950a",
      "instrument_type": "wallet",
      "unit21_id": 401,
      "resolution": null
    }
  ],
  "created_by": "[email protected]",
  "tags": ["product_line:lending", "type:trial"]
}

For rules that are CREATED, TRIGGERED, or triggered by an action-button, the following fields are sent:

Field NameValue TypeDetails
unit21_idNumberA Unit21 internally-assigned unique identifier for the rule within our system
object_typeStringAlways takes on the value RULE for rule webhooks
rule_idStringA non-Unit21 identifier for the rule
changeStringA Unit21-defined value describing the nature of the change to this rule. For more details on this, see above section Change trigger types
change_timeNumberTime the change was triggered in Epoch time format (number of seconds elapsed since 1 Jan 1970 00:00:00 UTC)
changed_byStringEmail address of the agent that triggered the status change (if applicable)
titleStringTitle assigned to the rule
descriptionStringA high level descriptive phrase about the rule
deploy_start_dateNumberTime this rule was first deployed in Epoch time format (number of seconds elapsed since 1 Jan 1970 00:00:00 UTC) (included only on triggered)
deploy_end_dateNumberTime this rule was taken out of production in Epoch time format (number of seconds elapsed since 1 Jan 1970 00:00:00 UTC) (included only on triggered)
flagged_entitiesObject[]An object list of entities flagged by the rule. Each object contains a Unit21 ID, the entity type (user or business), a non-Unit21 identifier, and a resolution
flagged_eventsObject[]An object list of events flagged by the rule. Each object contains a Unit21 ID, the event type (transaction or action), a non-Unit21 identifier, and a resolution well
flagged_instrumentsObject[]An object list of instruments flagged by the rule. Each object contains a Unit21 ID, the instrument type, a non-Unit21 identifier, and a resolution well
created_byStringEmail address of the agent that created this rule initially
tagsString[]A list of tags that are associated with this rule, always of the format key:value

Entities (Users or Businesses)

Sample webhook request body of a change-triggered or action-triggered webhook for an Entity:

{
  "unit21_id": 123,
  "entity_id": "J8OkZOrZ35TL6zoMdFX4zrxZE60UbevYNL",
  "object_type": "ENTITY",
  "change": "FLAGGED",
  "change_time": 1570062682,
  "changed_by": "[email protected]",
  "disposition": "SUSPENDED",
  "subdisposition": "Suspected ATO",
  "disposition_notes": "User confirmed that she did not initiate transaction",
  "tags": ["risk:mid_high", "watchlist:recently_flagged"],
  "custom_data": {}
}

For entities that are CREATED, FLAGGED, or triggered by an action-button, the following fields are sent:

Field NameValue TypeDetails
unit21_idNumberA Unit21 internally-assigned unique identifier for the entity within our system
entity_idStringThe ID of the matching entity within your system
object_typeStringAlways takes on the value ENTITY for entity webhooks
changeStringA Unit21-defined value describing the nature of the change to this entity. For more details on this, see above section Change trigger types
change_timeNumberTime the change was triggered in Epoch time format (number of seconds elapsed since 1 Jan 1970 00:00:00 UTC)
changed_byStringEmail address of the agent that triggered the status change (if applicable)
dispositionStringA state that represents either the entity's resolution or a designation for further actions. This field can be defined by an action trigger button, where each action trigger corresponds to one disposition.
subdispositionStringA sub-state that represents either the entity's resolution or a designation for further actions. This field can be be defined by an action trigger button, where each action trigger allows for agents to dynamically select a subdisposition during the investigation of an entity from a list of predefined values in the action trigger configuration process.
disposition_notesStringA free text field that contains agent-entered elaborations on the entity's disposition. A non-empty value may be required by the action trigger depending on the action trigger configuration.
tagsString[]A list of tags that are associated with this entity, always of the format key:value
custom_dataObjectAny custom information that you wish our system to associate with this rule (accepts any valid JSON object)

Verification request bodies

Default fields for all webhooks:

Field NameValue TypeDetails
unit21_idNumberA Unit21 internally-assigned unique identifier for the entity within our system
entity_idStringThe ID of the matching entity within your system
object_typeStringAlways takes on the value ENTITY for entity webhooks
changeStringA Unit21-defined value describing the nature of the change to this entity. For more details on this, see above section Change trigger types
change_timeNumberTime the change was triggered in Epoch time format (number of seconds elapsed since 1 Jan 1970 00:00:00 UTC)

Additional fields for VERIFICATION_WORKFLOW_EXECUTED:**

Sample JSON response:

{
  "unit21_id": 1,
  "entity_id": "external_id",
  "object_type": "ENTITY",
  "change": "VERIFICATION_WORKFLOW_EXECUTED",
  "verification_workflow_id": "test-workflow",
  "result": "$ACCEPT",
  "change_time": 123123123,
  "is_success": true,
  "generated_alert": 123,
  "tags": []
}
Field NameValue TypeDetails
verification_workflow_idStringIdentifier for the verification workflow executed for the entity
resultStringTerminal state for the workflow E.g: $ACCEPT, $REJECT, etc.
is_successBooleanBoolean for whether or not the workflow executed without errors
generated_alertNumberID for the alert generated by this workflow if the execution finished in a terminal state marked with Generate Alert
tagsString[]A list of tags that are associated with this entity, always of the format key:value

Additional fields for VERIFICATION_ENTITY_INITIATED:

Sample JSON response

{
  "unit21_id": 1,
  "entity_id": "external_id",
  "object_type": "ENTITY",
  "change": "VERIFICATION_ENTITY_INITIATED",
  "verification_workflow_id": "test-workflow"
}
Field NameValue TypeDetails
verification_workflow_idStringIdentifier for the verification workflow executed for the entity

Additional fields for VERIFICATION_ENTITY_STEP_COMPLETED:

Sample JSON response:

{
  "unit21_id": 1,
  "entity_id": "external_id",
  "object_type": "ENTITY",
  "change": "VERIFICATION_ENTITY_STEP_COMPLETED",
  "verification_workflow_id": "test-workflow",
  "content": { "some_field": "some_value" },
  "step": "PROVIDER:TYPE",
  "change_time": 123123123
}
Field NameValue TypeDetails
verification_workflow_idStringIdentifier for the verification workflow executed for the entity
contentObjectRaw JSON response from the provider. Shape depends on the provider executed in this step
stepStringName of the step completed. Represented as PROVIDER:TYPE. E.G. IDOLOGY:ID_VERIFICATION

Validating webhook request signatures

All Unit21's webhook requests are HTTP API calls that come with a HTTP request header unit21-signature. This header contains a keyed-hash message authentication code (HMAC) with SHA256 for security.

Sample webhook request headers

{
  "content-length": "452",
  "content-type": "application/json",
  "unit21-signature": "t=1582702424,s0=cbe7c96a57abff5e43e1b4b394f85ff6100d062f5bf551142d0527ae3213cfcc"
}
{
  "unit21_id": 123,
  "object_type": "ALERT",
  "alert_id": null,
  "alert_type": "kyc",
  "change": "CLOSED",
  "change_time": 1570062682,
  "disposition": "FALSE_POSITIVE",
  "status": "CLOSED",
  "changed_by": "[email protected]",
  "title": "Sample alert title",
  "description": "Sample alert description",
  "start_date": 1570052582,
  "end_date": 1570062582,
  "entities": [{"entity_id": "entity-886313e1", "entity_type": "user", "unit21_id": 46, "resolution": null}, {"entity_id": "entity-91a31re2", "entity_type": "user", "unit21_id": 72, "resolution": "false_positive"}],
  "events": [{"event_id": "event-1063e4e3e1", "event_type": "transaction", "unit21_id": 111, "resolution": null}],
  "instruments": [{"instrument_id": "instrument-4112950a", "instrument_type": "wallet", "unit21_id": 401, "resolution": null}],
  "triggered_by_rules": [{"unit21_id": 6, "rule_id": null}],
  "assigned_to": "[email protected]",
  "tags": ["rule_type:layering"],
  "custom_data": {"internal_priority": 3}
}

The unit21-signature header contains a timestamp and a signature. The signature (s0) is a hex code generated by using a per-endpoint secret key found on your unit21 webhooks dashboard as a hash key and a message created by concatenating the following in order:

  • timestamp (t) seen in the signature as a string
  • The . character
  • and the actual request body as an un-prettified JSON string

The sample on the right would be represented by this pre-hashed string:

1582702424.{"unit21_id": 123, "object_type": "ALERT", "alert_id": null, "alert_type": "kyc", "change": "CLOSED", "change_time": 1570062682, "disposition": "FALSE_POSITIVE", "status": "CLOSED", "changed_by": "[email protected]", "title": "Sample alert title", "description": "Sample alert description", "start_date": 1570052582, "end_date": 1570062582, "entities": [{"entity_id": "entity-886313e1", "entity_type": "user", "unit21_id": 46}, {"entity_id": "entity-91a31re2", "entity_type": "user", "unit21_id": 72, "resolution": "false_positive"}], "events": [{"event_id": "event-1063e4e3e1", "event_type": "transaction", "unit21_id": 111}], "instruments": [{"instrument_id": "instrument-4112950a", "instrument_type": "wallet", "unit21_id": 401}], "triggered_by_rules": [{"unit21_id": 6, "rule_id": null}], "assigned_to": "[email protected]", "tags": ["rule_type:layering"], "custom_data": {"internal_priority": 3}}

Using secret key 4acff285d1de621a4077 outputs the s0 signature:

c2c035b8759cb142441e7c3a40a7571adbdbb03a63d84c117c6772432e7c1bd9

Note that the secret key and concatenated body are used as UTF-8 encoded strings when generating the HMAC and the digest algorithm is SHA256


Did this page help you?