Skip to content

Commit

Permalink
Webhook Event Log (#3197)
Browse files Browse the repository at this point in the history
* add webhookEventLogConfiguration to system config
* document webhook_event_log_viewer role
* doc for retrieving webhook event log APIs
* document webhook event log admin UI
  • Loading branch information
spwitt authored Sep 4, 2024
1 parent fd717e5 commit 3dfb9e5
Show file tree
Hide file tree
Showing 24 changed files with 486 additions and 1 deletion.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,12 @@ import JSON from 'src/components/JSON.astro';

> Example: `FFFFFF` would set the menu font color to white.
</APIField>
<APIField name="systemConfiguration.webhookEventLogConfiguration.delete.enabled" type="Boolean" optional defaults="false" since="1.53.0">
Whether or not FusionAuth should delete Webhook Event Logs based upon this configuration. When `true` the <InlineField>webhookEventLogConfiguration.delete.numberOfDaysToRetain</InlineField> will be used to identify webhook event logs that are eligible for deletion. When this value is set to `false` webhook event logs will be preserved forever.
</APIField>
<APIField name="systemConfiguration.webhookEventLogConfiguration.delete.numberOfDaysToRetain" type="Integer" optional defaults="30" since="1.53.0">
The number of days to retain Webhook Event Logs. Required when <InlineField>webhookEventLogConfiguration.delete.enabled</InlineField> is set to `true`.
</APIField>
</APIBlock>

<JSON title="Example Request JSON" src="system-configuration/request.json" />
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,12 @@ import JSON from 'src/components/JSON.astro';
<APIField name="systemConfiguration.uiConfiguration.menuFontColor" type="String">
A hexadecimal color to override the default menu font color in the user interface.
</APIField>
<APIField name="systemConfiguration.webhookEventLogConfiguration.delete.enabled" type="Boolean" since="1.53.0">
Whether or not FusionAuth should delete Webhook Event Logs based upon this configuration. When `true` the <InlineField>webhookEventLogConfiguration.delete.numberOfDaysToRetain</InlineField> will be used to identify webhook event logs that are eligible for deletion. When this value is set to `false` webhook event logs will be preserved forever.
</APIField>
<APIField name="systemConfiguration.webhookEventLogConfiguration.delete.numberOfDaysToRetain" type="Integer" since="1.53.0">
The number of days to retain Webhook Event Logs.
</APIField>
</APIBlock>

<JSON title="Example Response JSON" src="system-configuration/response.json" />
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import APIBlock from 'src/components/api/APIBlock.astro';
import APIField from 'src/components/api/APIField.astro';
import EventTypes from 'src/content/docs/apis/_event-types.mdx';
import InlineField from 'src/components/InlineField.astro';

<APIBlock>
<APIField name={ props.base_field_name + ".data" } type="Object">
An object that can hold additional details of a webhook attempt log.
</APIField>
<APIField name={ props.base_field_name + ".endInstant" } type="Long">
The [instant](/docs/reference/data-types#instants) the attempt received a response or timed out.
</APIField>
<APIField name={ props.base_field_name + ".id" } type="UUID">
The webhook attempt log unique Id.
</APIField>
<APIField name={ props.base_field_name + ".startInstant" } type="Long">
The [instant](/docs/reference/data-types#instants) the attempt request was sent.
</APIField>
<APIField name={ props.base_field_name + ".webhookCallResponse.exception" } type="String">
The `exception` field from the event receiver if it was present on the response.
</APIField>
<APIField name={ props.base_field_name + ".webhookCallResponse.statusCode" } type="Integer">
The HTTP status code from the event response.
</APIField>
<APIField name={ props.base_field_name + ".webhookCallResponse.url" } type="String">
The fully qualified URL of the webhook endpoint the event was sent to or `null` if the attempt was sent to a Kafka topic.
</APIField>
<APIField name={ props.base_field_name + ".webhookEventLogId" } type="UUID" renderif={!props.no_event_id}>
The unique Id for the associated webhook event log.
</APIField>
<APIField name={ props.base_field_name + ".webhookId" } type="UUID">
The unique Id of the configured webhook or `null` for attempts sent to a Kafka topic.
</APIField>
</APIBlock>
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import JSON from 'src/components/JSON.astro';
import WebhookAttemptLogResponseBodyBase from 'src/content/docs/apis/_webhook-attempt-log-response-body-base.mdx';

#### Response Body

<WebhookAttemptLogResponseBodyBase base_field_name="webhookAttemptLog" />

<JSON title="Example JSON Response" src="webhook-event-logs/attempt-response.json" />
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import APIBlock from 'src/components/api/APIBlock.astro';
import APIField from 'src/components/api/APIField.astro';
import EventTypes from 'src/content/docs/apis/_event-types.mdx';
import InlineField from 'src/components/InlineField.astro';
import WebhookAttemptLogResponseBodyBase from 'src/content/docs/apis/_webhook-attempt-log-response-body-base.mdx';

<APIBlock>
<APIField name={ props.base_field_name + ".attempts" } type="Array">
An array of attempts for this event.
</APIField>
<WebhookAttemptLogResponseBodyBase base_field_name={props.base_field_name + ".attempts[x]"} no_event_id />
<APIField name={ props.base_field_name + ".data" } type="Object">
An object that can hold additional details of a webhook event log.
</APIField>
<APIField name={ props.base_field_name + ".event" } type="Object">
Contains the full event request payload. The contents vary by [event](/extend/events-and-webhooks/events) type.
</APIField>
<APIField name={ props.base_field_name + ".eventResult" } type="String">
The overall result of a [transactional](/docs/extend/events-and-webhooks/events#transaction-compatibility) event. Possible values are:
* `Running` - The default state after an event is fired.
* `Succeeded` - The transactional event was successful, and pending database changes were committed. Non-transactional events are transitioned to this state immediately after the event payload is sent to all recipients regardless of the response.
* `Failed` - The transactional event was unsuccessful, and pending database changes were rolled back.
</APIField>
<APIField name={ props.base_field_name + ".eventType" } type="String">
The event type. Possible values are:

<EventTypes />
</APIField>
<APIField name={ props.base_field_name + ".failedAttempts" } type="Integer">
The number of failed event send attempts. Aggregate based on failed <InlineField>attempts</InlineField>.
</APIField>
<APIField name={ props.base_field_name + ".id" } type="UUID">
The webhook event log unique Id.
</APIField>
<APIField name={ props.base_field_name + ".insertInstant" } type="Long">
The [instant](/docs/reference/data-types#instants) when the Webhook Event Log was created.
</APIField>
<APIField name={ props.base_field_name + ".lastAttemptInstant" } type="Long">
The [instant](/docs/reference/data-types#instants) the last attempt was made to send the event.
</APIField>
<APIField name={ props.base_field_name + ".lastUpdateInstant" } type="Long">
The [instant](/docs/reference/data-types#instants) when the Webhook Event Log was lasted updated.
</APIField>
<APIField name={ props.base_field_name + ".linkedObjectId" } type="UUID">
If present, contains the unique Id of the associated object. The object type the Id references varies based on <InlineField>{ props.base_field_name + ".eventType" }</InlineField>
</APIField>
<APIField name={ props.base_field_name + ".sequence" } type="Long">
An auto-incremented database field to maintain order of events.
</APIField>
<APIField name={ props.base_field_name + ".successfulAttempts" } type="Integer">
The number of successful event send attempts. Aggregate based on successful <InlineField>attempts</InlineField>.
</APIField>
<APIField name="total" type="Integer" renderif={!!props.include_total}>
The total number of Webhook Event Logs matching the search criteria. Use this value along with the <InlineField>numberOfResults</InlineField> and <InlineField>startRow</InlineField> in the Search request to perform pagination.
</APIField>
</APIBlock>
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import JSON from 'src/components/JSON.astro';
import WebhookEventLogResponseBodyBase from 'src/content/docs/apis/_webhook-event-log-response-body-base.mdx';

#### Response Body

<WebhookEventLogResponseBodyBase base_field_name="webhookEventLog" />

<JSON title="Example JSON Response" src="webhook-event-logs/response.json" />
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import WebhookEventLogResponseBodyBase from 'src/content/docs/apis/_webhook-event-log-response-body-base.mdx';

#### Response Body

<WebhookEventLogResponseBodyBase base_field_name="webhookEventLogs[x]" include_total />
179 changes: 179 additions & 0 deletions astro/src/content/docs/apis/webhook-event-logs.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
---
title: Webhook Event Logs
description: Learn about the APIs for searching and retrieving webhook event and attempt logs.
section: apis
---
import API from 'src/components/api/API.astro';
import APIBlock from 'src/components/api/APIBlock.astro';
import APIField from 'src/components/api/APIField.astro';
import Aside from 'src/components/Aside.astro';
import InlineField from 'src/components/InlineField.astro';
import JSON from 'src/components/JSON.astro';
import StandardGetResponseCodes from 'src/content/docs/apis/_standard-get-response-codes.astro';
import WebhookAttemptLogResponseBody from 'src/content/docs/apis/_webhook-attempt-log-response-body.mdx';
import WebhookEventLogResponseBody from 'src/content/docs/apis/_webhook-event-log-response-body.mdx';
import WebhookEventLogSearchResponseBody from 'src/content/docs/apis/_webhook-event-log-search-response-body.mdx';

## Overview

<Aside type="version">
This API has been available since 1.53.0
</Aside>

The Webhook Event Log contains a record of [Events](/docs/extend/events-and-webhooks/events) sent by FusionAuth, including request payloads. It also records attempts to send the event payload to [Webhook](/docs/extend/events-and-webhooks) and [Kafka](/docs/extend/events-and-webhooks/kafka) endpoints.

Test events sent through the FusionAuth admin UI are not recorded in the Webhook Event Log.

This page contains the APIs that are used to retrieve Webhook Event Logs and associated attempt details. Here are the APIs:

## Retrieve a Webhook Event Log

### Request

<API method="GET" uri="/api/system/webhook-event-log/{logId}" authentication={["api-key"]} title="Retrieve a Webhook Event Log by Id"/>

#### Request Parameters

<APIBlock>
<APIField name="logId" type="UUID" required>
The unique Id of the Webhook Event Log to retrieve.
</APIField>
</APIBlock>

### Response

<StandardGetResponseCodes never_search_error />

<WebhookEventLogResponseBody />

## Retrieve a Webhook Attempt Log

### Request

<API method="GET" uri="/api/system/webhook-attempt-log/{logId}" authentication={["api-key"]} title="Retrieve a Webhook Attempt Log by Id"/>

#### Request Parameters

<APIBlock>
<APIField name="logId" type="UUID" required>
The unique Id of the Webhook Attempt Log to retrieve.
</APIField>
</APIBlock>

### Response

<StandardGetResponseCodes never_search_error />

<WebhookAttemptLogResponseBody />

## Search Webhook Event Logs

### Request

<API method="GET" uri="/api/system/webhook-event-log/search?event={event}&start={start}&end={end}&eventType={eventType}" authentication={["api-key"]} title="Searches the Webhook Event Logs using the given search criteria"/>

When calling the API using a `GET` request you will send the search criteria on the URL using request parameters. In order to simplify the example URL above, not every possible parameter is shown, however using the provided pattern you may add any of the documented request parameters to the URL.

#### Request Parameters

<APIBlock>
<APIField name="end" type="Long" optional>
The end [instant](/docs/reference/data-types#instants) of the date/time range to search within.
</APIField>
<APIField name="event" type="String" optional>
The string to search in the Webhook Event Log request body for. This can contain wildcards using the asterisk character (`*`). If no wildcards are present, this parameter value will be interpreted as `*value*`.
</APIField>
<APIField name="eventResult" type="String" optional>
The overall result of a [transactional](/docs/extend/events-and-webhooks/events#transaction-compatibility) event. Possible values are:
* `Running` - The default state after an event is fired.
* `Succeeded` - The transactional event was successful, and pending database changes were committed. Non-transactional events are transitioned to this state immediately after the event payload is sent to all recipients regardless of the response.
* `Failed` - The transactional event was unsuccessful, and pending database changes were rolled back.
</APIField>
<APIField name="eventType" type="String" optional>
The event type.
</APIField>
<APIField name="numberOfResults" type="Integer" optional defaults="25">
The number of results to return from the search.
</APIField>
<APIField name="orderBy" type="String" optional defaults="sequence DESC">
The database column to order the search results on plus the order direction.

The possible values are:

* `eventResult` - the overall result of the event
* `eventType` - the event type
* `id` - the unique Id of the Webhook Event Log
* `insertInstant` - the [instant](/docs/reference/data-types#instants) when the Webhook Event Log was created
* `lastAttemptInstant` - the [instant](/docs/reference/data-types#instants) when the last attempt was made to deliver the event
* `linkedObjectId` - the unique Id of the object associated with this event
* `sequence` - the system-assigned event sequence

For example, to order the results by the insert instant in a descending order, the value would be provided as `insertInstant DESC`. The final string is optional can be set to `ASC` or `DESC`.
</APIField>
<APIField name="start" type="Long" optional>
The start [instant](/docs/reference/data-types#instants) of the date/time range to search within.
</APIField>
<APIField name="startRow" type="Integer" optional defaults="0">
The offset row to return results from. If the search has 200 records in it and this is 50, it starts with row 50.
</APIField>
</APIBlock>

<API method="POST" uri="/api/system/webhook-event-log/search" authentication={["api-key"]} title="Searches the Webhook Event Logs using the given search criteria"/>

When calling the API using a `POST` request you will send the search criteria in a JSON request body.

#### Request Body

<APIBlock>
<APIField name="search.end" type="Long" optional>
The end [instant](/docs/reference/data-types#instants) of the date/time range to search within.
</APIField>
<APIField name="search.event" type="String" optional>
The string to search in the Webhook Event Log request body for. This can contain wildcards using the asterisk character (`*`). If no wildcards are present, this parameter value will be interpreted as `*value*`.
</APIField>
<APIField name="search.eventResult" type="String" optional>
The overall result of a [transactional](/docs/extend/events-and-webhooks/events#transaction-compatibility) event. Possible values are:
* `Running` - The default state after an event is fired.
* `Succeeded` - The transactional event was successful, and pending database changes were committed. Non-transactional events are transitioned to this state immediately after the event payload is sent to all recipients regardless of the response.
* `Failed` - The transactional event was unsuccessful, and pending database changes were rolled back.
</APIField>
<APIField name="search.eventType" type="String" optional>
The event type.
</APIField>
<APIField name="search.numberOfResults" type="Integer" optional defaults="25">
The number of results to return from the search.
</APIField>
<APIField name="search.orderBy" type="String" optional defaults="sequence DESC">
The database column to order the search results on plus the order direction.

The possible values are:

* `eventResult` - the overall result of the event
* `eventType` - the event type
* `id` - the unique Id of the Webhook Event Log
* `insertInstant` - the [instant](/docs/reference/data-types#instants) when the Webhook Event Log was created
* `lastAttemptInstant` - the [instant](/docs/reference/data-types#instants) when the last attempt was made to deliver the event
* `linkedObjectId` - the unique Id of the object associated with this event
* `sequence` - the system-assigned event sequence

For example, to order the results by the insert instant in a descending order, the value would be provided as `insertInstant DESC`. The final string is optional can be set to `ASC` or `DESC`.
</APIField>
<APIField name="search.start" type="Long" optional>
The start [instant](/docs/reference/data-types#instants) of the date/time range to search within.
</APIField>
<APIField name="search.startRow" type="Integer" optional defaults="0">
The offset row to return results from. If the search has 200 records in it and this is 50, it starts with row 50.
</APIField>
</APIBlock>

<JSON title="Example JSON Request" src="webhook-event-logs/search-post-request.json" />

### Response

The response for this API contains the Webhook Event Logs matching the search criteria in paginated format.

<StandardGetResponseCodes never_search_error />

<WebhookEventLogSearchResponseBody />

<JSON title="Example JSON Response" src="webhook-event-logs/search-response.json" />
Original file line number Diff line number Diff line change
Expand Up @@ -94,4 +94,4 @@ Events can be either transactional or non-transactional. The final state of the

To learn more about writing webhooks, see [Writing a Webhook](../writing-a-webhook#calling-fusionauth-apis-in-webhooks).

For more information on event transaction configurations, see <InlineField>transaction setting</InlineField> under [Tenant Settings](../#tenant-settings).
For more information on event transaction configurations, see <InlineField>transaction setting</InlineField> under [Tenant Settings](/docs/extend/events-and-webhooks#tenant-settings).
Loading

0 comments on commit 3dfb9e5

Please sign in to comment.