Skip to main content

Webhook Payloads

This page documents the payload schemas for each webhook event type. For webhook configuration, HMAC verification, and retry policies, see Webhooks.


Common envelope​

Every webhook delivery wraps the event-specific payload in a common envelope:

{
"id": "evt_abc123def456",
"type": "execution.completed",
"timestamp": "2025-03-10T19:00:05Z",
"team_id": "team_xyz",
"data": { ... }
}
FieldTypeDescription
idstringUnique event ID — use for deduplication
typestringEvent type (see table below)
timestampstringISO 8601 timestamp of when the event occurred
team_idstringThe team that owns the resource
dataobjectEvent-specific payload (documented per event below)

Event types​

Event typeTrigger
execution.startedAn Execution begins running
execution.completedAn Execution finishes successfully
execution.failedAn Execution fails
schedule.activatedA Schedule is activated (set to Active)
schedule.pausedA Schedule is paused (set to Inactive)
budget.threshold_breachedA budget threshold is crossed
budget.exceededSpend exceeds the budget amount
violation.createdA new Guard violation is detected
violation.resolvedA Guard violation is resolved
scan.completedA Guard scan finishes
finding.createdA new scan finding is detected
anomaly.detectedA cost anomaly is detected
connection.health_changedA Connection health status changes
access_request.submittedAn access request is submitted
access_request.approvedAn access request is approved
access_request.deniedAn access request is denied

Execution events​

execution.started​

{
"id": "evt_001",
"type": "execution.started",
"timestamp": "2025-03-10T19:00:00Z",
"team_id": "team_xyz",
"data": {
"execution_id": "exec_abc123",
"target_id": "target_def456",
"target_name": "Dev EC2 Instances",
"action": "stop",
"trigger": "schedule",
"schedule_id": "sched_ghi789",
"schedule_name": "Dev Weekday Stop",
"resource_count": 12,
"connection_id": "conn_jkl012"
}
}

execution.completed​

{
"data": {
"execution_id": "exec_abc123",
"target_id": "target_def456",
"target_name": "Dev EC2 Instances",
"action": "stop",
"trigger": "schedule",
"schedule_id": "sched_ghi789",
"resource_count": 12,
"resources_actioned": 10,
"resources_already_in_state": 2,
"resources_failed": 0,
"duration_seconds": 45,
"estimated_savings_usd": 28.50
}
}

execution.failed​

{
"data": {
"execution_id": "exec_abc123",
"target_id": "target_def456",
"target_name": "Dev EC2 Instances",
"action": "stop",
"trigger": "manual",
"triggered_by": "user_abc",
"error_code": "iam_permission_denied",
"error_message": "Unable to assume IAM role FrugallyAccessRole in account 123456789012.",
"resource_count": 12,
"resources_actioned": 0,
"resources_failed": 12
}
}

Schedule events​

schedule.activated​

{
"data": {
"schedule_id": "sched_ghi789",
"name": "Dev Weekday Stop",
"activated_by": "user_abc",
"next_run_at": "2025-03-11T19:00:00Z",
"timezone": "Europe/London"
}
}

schedule.paused​

{
"data": {
"schedule_id": "sched_ghi789",
"name": "Dev Weekday Stop",
"paused_by": "user_abc"
}
}

Budget events​

budget.threshold_breached​

{
"data": {
"budget_id": "budget_def456",
"project_id": "proj_abc123",
"project_name": "Production Infrastructure",
"budget_name": "Monthly EC2 spend",
"amount": 5000.00,
"current_spend": 4005.00,
"percentage_used": 80.1,
"threshold_percentage": 80,
"currency": "USD",
"period": "monthly"
}
}

budget.exceeded​

{
"data": {
"budget_id": "budget_def456",
"project_id": "proj_abc123",
"project_name": "Production Infrastructure",
"budget_name": "Monthly EC2 spend",
"amount": 5000.00,
"current_spend": 5120.00,
"overspend": 120.00,
"percentage_used": 102.4,
"currency": "USD",
"period": "monthly"
}
}

Violation events​

violation.created​

{
"data": {
"violation_id": "viol_ghi789",
"project_id": "proj_abc123",
"project_name": "Production Infrastructure",
"type": "budget_threshold_breach",
"severity": "warning",
"message": "Monthly EC2 spend has reached 80% of the $5,000 budget.",
"budget_id": "budget_def456"
}
}

violation.resolved​

{
"data": {
"violation_id": "viol_ghi789",
"project_id": "proj_abc123",
"resolved_by": "user_abc",
"resolution_note": "Budget increased to $7,000 for Q2."
}
}

Scan events​

scan.completed​

{
"data": {
"scan_id": "scan_mno345",
"project_id": "proj_abc123",
"project_name": "Production Infrastructure",
"status": "completed",
"findings_count": 5,
"findings_by_severity": {
"critical": 0,
"high": 2,
"medium": 2,
"low": 1
},
"duration_seconds": 30
}
}

finding.created​

{
"data": {
"finding_id": "find_jkl012",
"scan_id": "scan_mno345",
"project_id": "proj_abc123",
"resource_id": "i-0abc123def456",
"resource_type": "ec2:instance",
"severity": "high",
"title": "Untagged EC2 instance running in production",
"recommendation": "Add the required tags: Environment, Owner, CostCentre."
}
}

Anomaly events​

anomaly.detected​

{
"data": {
"anomaly_id": "anom_pqr678",
"connection_id": "conn_jkl012",
"service": "Amazon EC2",
"metric": "daily_cost",
"expected_value": 150.00,
"actual_value": 420.00,
"deviation_percentage": 180.0,
"severity": "critical",
"period_start": "2025-03-10",
"period_end": "2025-03-10"
}
}

Connection events​

connection.health_changed​

{
"data": {
"connection_id": "conn_jkl012",
"account_id": "123456789012",
"previous_status": "connected",
"new_status": "degraded",
"reason": "Cost Explorer verification failed — ce:GetCostAndUsage permission denied."
}
}

Access request events​

access_request.submitted​

{
"data": {
"request_id": "req_stu901",
"requested_by": "user_ghi",
"requested_by_email": "charlie@example.com",
"resource_type": "project",
"resource_id": "proj_abc123",
"resource_name": "Production Infrastructure",
"role_requested": "contributor",
"reason": "Need to review Q2 budget compliance."
}
}

access_request.approved / access_request.denied​

{
"data": {
"request_id": "req_stu901",
"decided_by": "user_abc",
"decision": "approved",
"note": "Approved for Q2."
}
}

Verifying webhook signatures​

Each webhook delivery includes an X-Frugally-Signature header containing an HMAC-SHA256 signature. Verify it against the raw request body using your webhook signing secret:

import hmac
import hashlib

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

For full details, see Webhooks — HMAC signing.