Webhook Logs
Tags: integrations, logging, webhooks
Webhook request history and debugging
Resources
Request and response models used by the endpoints on this page.
DataRecordResponse
| Field | Type | Required | Description |
|---|---|---|---|
accessMode | Integer | ||
createdAt | DateTime | ✓ | |
dataTypeId | Integer | ✓ | |
externalId | String | ||
fieldValues | Dict[str, Any] | ✓ | |
id | Integer | ✓ | |
memberId | Integer | ✓ | |
memberName | String | ||
retirement | DataRecordRetirementResponse | null | ||
updatedAt | DateTime | ✓ | |
uuid | UUID | ✓ |
Example:
{
"id": 0,
"uuid": "00000000-0000-0000-0000-000000000000",
"dataTypeId": 0,
"memberId": 0,
"fieldValues": {},
"createdAt": "2024-01-01T00:00:00Z",
"updatedAt": "2024-01-01T00:00:00Z"
}
DataRecordRetirementResponse
| Field | Type | Required | Description |
|---|---|---|---|
reason | Literal['monday_item_archived', 'monday_item_deleted'] | ✓ | |
source | Literal['monday'] | Default: monday | |
status | Literal['retired'] | Default: retired |
Example:
{
"status": "retired",
"reason": "monday_item_archived",
"source": "monday"
}
EventRuleResponse
| Field | Type | Required | Description |
|---|---|---|---|
actionParams | Dict[str, Any] | ✓ | |
actionSetLocked | Boolean | Default: False | |
actionType | <enum EventRuleActionType | ✓ | |
active | Boolean | ✓ | |
appConnectionId | Integer | ||
calendarEventTypeId | Integer | ✓ | |
calendarId | Integer | ✓ | |
celBlockedAt | DateTime | ||
conditions | String | ✓ | |
createdAt | DateTime | ✓ | |
dataTypeId | Integer | ✓ | |
dataTypeName | String | ||
delay | Integer | ✓ | |
error | String | ✓ | |
errorMessage | String | ✓ | |
eventType | <enum EventRuleEventType | ✓ | |
failedAt | DateTime | ✓ | |
id | Integer | ✓ | |
journeyId | Integer | ||
journeyStepId | Integer | ✓ | |
name | String | ✓ | |
objectType | <enum EventRuleObjectType | ✓ | |
order | Integer | ✓ | |
routineId | Integer | ✓ | |
taskId | Integer | ✓ | |
taskName | String | ||
taskWorkflowId | Integer | ||
triggerParams | Dict[str, Any] | ✓ | |
updatedAt | DateTime | ✓ | |
uuid | String | ✓ | |
workflowRevisionId | Integer | ✓ |
Example:
{
"id": 0,
"uuid": "string",
"objectType": null,
"name": "string",
"eventType": null,
"conditions": "string",
"actionType": null,
"actionParams": {},
"triggerParams": {},
"active": false,
"createdAt": "2024-01-01T00:00:00Z",
"updatedAt": "2024-01-01T00:00:00Z",
"taskId": 0,
"dataTypeId": 0,
"routineId": 0,
"workflowRevisionId": 0,
"calendarId": 0,
"calendarEventTypeId": 0,
"journeyStepId": 0,
"error": "string",
"errorMessage": "string",
"failedAt": "2024-01-01T00:00:00Z",
"delay": 0,
"order": 0,
"actionSetLocked": false
}
PaginatedResponse[WebhookLogResponse]
| Field | Type | Required | Description |
|---|---|---|---|
items | Array<WebhookLogResponse> | ✓ | |
page | Integer | ✓ | |
pageSize | Integer | ✓ | |
total | Integer | ✓ | |
totalPages | Integer | ✓ |
Example:
{
"items": [],
"total": 0,
"page": 0,
"pageSize": 0,
"totalPages": 0
}
WebhookLogReplayResponse
| Field | Type | Required | Description |
|---|---|---|---|
eventId | String | ✓ | |
replayOfId | Integer | ✓ | |
ruleId | Integer | ✓ | |
status | Literal['queued'] | ✓ | |
workflowId | String | ✓ |
Example:
{
"status": "queued",
"replayOfId": 0,
"ruleId": 0,
"eventId": "string",
"workflowId": "string"
}
WebhookLogResponse
| Field | Type | Required | Description |
|---|---|---|---|
createdAt | DateTime | ✓ | |
dispatchKey | String | ||
errorMessage | String | ||
eventType | String | ✓ | |
id | Integer | ✓ | |
memberId | Integer | ||
record | DataRecordResponse | null | ||
recordId | Integer | ||
replayOfId | Integer | ||
replayable | Boolean | Default: False | |
rule | EventRuleResponse | null | ||
ruleId | Integer | ||
statusCode | Integer | ||
success | Boolean | ✓ | |
url | String | ✓ |
Example:
{
"id": 0,
"url": "string",
"eventType": "string",
"success": false,
"createdAt": "2024-01-01T00:00:00Z",
"replayable": false
}
WorkspaceOrgEndpointResponse
| Field | Type | Required | Description |
|---|---|---|---|
destinationDigest | String | ✓ | First 12 hex characters of SHA-256 over the full URL |
destinationHost | String | ✓ | scheme://host[:port] of the endpoint URL — never the path or query |
eventTypes | Array | ✓ | |
limitedToWorkspaces | Boolean | ✓ | |
name | String | ✓ | |
organizationId | Integer | ✓ | |
status | String | ✓ | |
uuid | String | ✓ | Endpoint uuid (org-side identifier) |
Example:
{
"uuid": "string",
"name": "string",
"destinationHost": "string",
"destinationDigest": "string",
"status": "string",
"eventTypes": [],
"limitedToWorkspaces": false,
"organizationId": 0
}
Endpoints
GET /api/v2/w/{workspace_uuid}/webhook-logs- ListGET /api/v2/w/{workspace_uuid}/webhook-logs/org-endpoints- Org EndpointsPOST /api/v2/w/{workspace_uuid}/webhook-logs/{log_id}/replay- Replay
List
GET /api/v2/w/{workspace_uuid}/webhook-logs
Description:
List all webhook logs for the workspace with pagination.
PHI-classified despite returning no payload body: errorMessage carries
the receiver's response text, which routinely echoes the delivered
payload back (see _send_webhook_request — the body is kept here for
the operator precisely because it is too sensitive for application logs).
A page of failed deliveries is therefore a PHI read, and a paged scrape of
it is bulk access.
Authorization: Requires webhooks:read scope
Parameters:
page(Integer) — min: 1pageSize(Integer) — min: 1, max: 100sortBy(WebhookLogSortField)sortOrder(SortOrder)eventType(EventRuleEventType)success(Boolean)
Response: See PaginatedResponse[WebhookLogResponse]
Org Endpoints
GET /api/v2/w/{workspace_uuid}/webhook-logs/org-endpoints
Description:
Workspace-side visibility for org webhooks (GRA-8314 §5).
The org webhook's inclusion rule is decided at configuration time by an
org admin (audited there); this read is (b)'s visibility half — any
member holding webhooks:read (the workspace's webhook-read scope, which
workspace admins hold) can see that their workspace feeds an org
endpoint, with IDs and the endpoint's public shape only. Never a secret,
never delivery contents, never the full URL. An endpoint that does not
cover this workspace is deliberately absent: listing it would disclose
org configuration this workspace is not party to.
One indexed query: an endpoint covers this workspace when the operator explicitly selected the whole organization or linked this workspace — the same rule the fan-out applies, expressed in SQL over the link table.
Authorization: Requires webhooks:read scope
Response: List of WorkspaceOrgEndpointResponse
Replay
POST /api/v2/w/{workspace_uuid}/webhook-logs/{log_id}/replay
Description:
Re-send a previously delivered webhook payload.
The stored body is re-sent verbatim — same eventId, so a receiver
that deduplicates on it sees the same event rather than a new one — signed
with the rule's CURRENT secret and a FRESH timestamp, and posted to the
destination the payload was originally delivered to (WebhookLog.url),
which the rule must still point at. See replay_eligibility for why the
destination is pinned to the log rather than resolved from the rule: read
at replay time it would let anyone who can edit a rule redirect a thousand
stored PHI bodies to a new endpoint, correctly signed.
Replay is therefore useful after a receiver outage or a secret rotation, and deliberately NOT after a URL correction — that case is indistinguishable from the attack, and its recovery is to re-drive the event from the source records.
WEBHOOKS_WRITE rather than WEBHOOKS_READ: replay causes an outbound
delivery to a third party. It is a write in the only sense that matters
here, even though it changes nothing in the workspace.
Audit: this emits BOTH a config-change event (an operator acted on
automation configuration) and PHI_RECORD_EXPORTED (PHI was disclosed to
an external party — the §164.312(b) "record export ... destination" row).
The disclosure event is emitted here, at authorization, because this is
where the actor is known; the transmission outcome is the WebhookLog
row the delivery activity writes, correlated by dispatchKey. A replay
that is queued and never delivered therefore still records as an authorized
disclosure — over-recording, which is the correct direction for a
disclosure trail.
Responses:
- 404 — no such log in this workspace.
- 409 — the log has no stored payload (written before this feature, or the attempt failed before a payload was built), or the originating EventRule is gone, inactive, has no webhook URL, or now points somewhere other than where this delivery went. None of those become true by retrying.
- 422 — no JSON body. An empty
{}is required; seeWebhookLogReplayRequest. - 429 — replay budget exhausted.
Authorization: Requires webhooks:write scope
Parameters:
log_id(Integer)_body(WebhookLogReplayRequest)
Response: See WebhookLogReplayResponse