Webhook best practices and troubleshooting

Review these best practices and troubleshooting tips to make sure your webhooks remain secure and function well with your integration.

Verify events are sent from AGILITY

To confirm that the received events are sent from AGILITY, verify the webhook signatures.

AGILITY signs webhook events it sends to your endpoints by including a signature in each event’s X-Agility-Signature header.

This allows you to verify that the events were sent by AGILITY, not from a third party.

You can verify signatures using the example below:

from fastapi import FastAPI, Request, Header, HTTPException import hmac import hashlib app = FastAPI() @app.post("/mywebhook/") async def receive_webhook(request: Request, x_agility_signature: Optional[str] = Header(None)): secret = "known_secret" # The secret should be known to the receiver payload = await request.body() signature = create_signature(payload.decode(), secret) if not hmac.compare_digest(f"sha256={signature}", x_agility_signature): raise HTTPException(status_code=400, detail="Invalid signature") # Process the payload # ... def create_signature(payload: str, secret: str) -> str: """ Create a HMAC SHA256 signature of the payload with the secret. """ return hmac.new(secret.encode(), payload.encode(), hashlib.sha256).hexdigest()

Roll endpoint signing secrets periodically

The secret used to verify the origin of events from AGILITY is modifiable in the Webhooks section of the UI. For each endpoint, click roll secret. It will immediately render the current secret inactive.

To ensure security, we recommend that you roll secrets periodically, or when you suspect a compromised secret.

Preventing replay attacks

A replay attack occurs when a malicious actor intercepts a valid payload and its signature, then re-transmits them. To mitigate such attacks, AGILITY includes a timestamp created field within the signed payload. Because this timestamp is part of the signed payload, it’s also verified by the signature, so an attacker can’t change the timestamp without invalidating the signature.

If the signature is valid but the timestamp is too old, you can have your application reject the payload. For example you can define a default tolerance of 2 minutes between the timestamp and the current time.

AGILITY generates the timestamp and signature each time we send an event to your endpoint.

Troubleshooting

Best practices for troubleshooting:

  • Regular monitoring: Regularly check the latest successful call details and failure logs to monitor the health of your webhooks.

  • Correlate with your system: Use timestamps to correlate webhook activities with changes or events in your system.

  • Review payloads: Check the last_successful_body and failed webhook payloads to ensure they contain the expected data.

Track the latest successful webhook call

AGILITY keeps a record of the most successful webhook call for each of your webhook subscriptions. This record includes details such as the URL, request body, headers, and the timestamp of the call.

How to access this information

  • Using AGILITY UI: navigate into your webhook subscription detail page

  • Using AGILITY APIs

    • Use GET /cv/api/v1/webhooks/subscriptions/{subscription_id} endpoint to retrieve the details of your subscription.

    • Look for fields last_successful_url, last_successful_body, last_successful_headers, and last_successful_timestamp in the response.

Example:

{
"id": "5290d258-1e91-4b5a-9a78-2f455effd3d1",
"user_id": "test",
"url": "http://localhost:8580/mywebhook",
"events": ["*"],
"description": "My webhook",
"enabled": true,
"subscribe_to_all_users": true,
"secret": "4f44b726798276c4f6d059bc42a48db8",
"created_on": "2023-11-14T18:42:46.294071",
"updated_on": "2023-11-21T13:10:28.417816",
"last_successful_url": "http://localhost:8580/mywebhook",
"last_successful_body": {
"id": "5a91645b-3146-4405-8950-41bc7c2c3bb4",
"event_name": "analysis_done",
"created": "2023-11-21T13:10:28.301969",
"data": {
"analysis_id": "2f6c063b-0b58-4a62-af40-4a47f2affbb4",
….
}
},
"last_successful_headers": {
"Content-Type": "application/json",
"X-Agility-Signature": "sha256=0f0f22227578711ac20bd41c624c7010466c600e412d3ef9dd5539989f50090a"
},
"last_successful_timestamp": "2023-11-21T13:10:28.490617"
}

 

Troubleshooting with webhook failure logs

If you encounter issues with your webhook, you can use the Webhook Failure Logs to identify problems.

Accessing failure logs

  • Use AGILITY UI

    • Visit your webhook subscription detail page.

    • Navigate to the section listing recent call failures related to your webhook subscription.

  • Use AGILITY APIs

    • Use the GET /cv/api/v1/webhooks/subscriptions/{subscription_id}/failures endpoint to fetch logs for your subscription.

The logs present essential information, including the event name, failure reason, and timestamp. This comprehensive data assists in pinpointing the root cause of webhook failures, streamlining your troubleshooting efforts.

Analyzing failure logs

  • Review the failure_reason field to understand why a webhook call failed.

  • Check the event_name and timestamp to correlate failures with your system's activities.

Example failure log

{ "items": [ { "id": "89282473-f0d7-4d15-967f-5b2589b19490", "subscription_id": "975986b6-94d3-4d0b-8c6d-121ac532a465", "event_name": "analysis_done", "failure_reason": "HTTPSConnectionPool(host='localhost', port=8580): Max retries exceeded with url: /mywebhook (Caused by SSLError(SSLError(1, '[SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:1129)')))", "timestamp": "2023-11-21T13:10:28.332061", "event_id": "5a91645b-3146-4405-8950-41bc7c2c3bb4" }, ], "total": 16, "page": 1, "size": 50, "pages": 1 }

Â