Skip to main content

Introduction to Webhooks

Webhooks allow you to receive real-time notifications about events in your Altur organization. When a specific event occurs (e.g., the end of a call), Altur sends an HTTP POST request with event-specific data to your configured endpoint. This enables seamless integration with your backend systems or CRM, ensuring they remain up-to-date.

How Webhooks Work

  1. Configure Your Endpoint
    You can configure your webhook URL in the Altur platform. This URL will receive POST requests when specific events are triggered.
  2. Receive Notifications
    When an event occurs, Altur sends a POST request with the event’s details in a structured JSON format to your endpoint.
  3. Acknowledge Delivery
    Your endpoint should respond with a 200 OK status code to confirm successful receipt. Altur waits up to 5 seconds for a response. Timeouts, connection errors, 5xx, 408 and 429 responses are retried with exponential backoff (up to 5 total attempts). Any other 4xx response fails immediately without retries, and redirects are not followed. See the Delivery Retry Policy.

Event Types

Webhooks can be triggered by the following event types:
  • on_call_end: Triggered at the end of a call, this webhook sends detailed information about the call along with basic information about the AI agent and the end user.
  • transfer_started: Triggered when a call transfer starts, so your human agents can prepare with real-time call context.
  • transfer_completed: Triggered when a call transfer connects to the human leg.
  • campaign.status_changed: Triggered when a Campaign transitions between lifecycle statuses. Includes the analytics snapshot when the campaign reaches finished.
  • campaign.cycle_completed: Triggered when a cycle iteration of a Campaign finishes, with the completed iteration number and the next scheduled iteration timestamp.
Campaign webhooks use a versioned envelope (event_id, event_type, occurred_at, api_version, project_id, data). Use event_id for idempotent processing on your side. The call events (on_call_end, transfer_started, transfer_completed) predate this envelope, keep their flat top-level shape and have no event_id: deduplicate them on id (the call ID) plus event_type.

Securing Your Webhooks

To ensure secure communication and verify the authenticity of webhook requests, Altur includes an HMAC signature in the X-Altur-Signature header for every request.

How It Works

  • Shared Secret: Each webhook integration is configured with a unique base64-encoded shared secret key.
  • HMAC Generation: Altur generates an HMAC SHA-256 hash using the base64-decoded shared secret and the payload serialized as compact JSON (no spaces after : or ,, non-ASCII characters escaped as \uXXXX, e.g. Sofía → Sof\u00eda). This hash is base64-encoded and included in the X-Altur-Signature header.
  • Validation: Your endpoint must parse the body and re-serialize it in that same compact form before computing the HMAC.
The request body Altur sends is not the exact string it signs: the body includes spaces after : and ,. Computing the HMAC over the raw request body will fail. Always parse the JSON and re-serialize it as described above.

Validation Function Example

Usage Example

Headers Sent with Webhook

  • Content-Type: application/json
  • X-Altur-Signature: Base64-encoded HMAC SHA-256 hash of the compact JSON payload (see above; this is not the raw body)

Why This Matters

This mechanism ensures:
  • The request originates from Altur.
  • The payload has not been tampered with during transmission.

Delivery Retry Policy

Any response other than 2xx counts as a failure. Whether Altur retries depends on the failure: Retries use:
  • Maximum attempts: 5 (initial delivery plus 4 retries).
  • Backoff: 60s after the first failure, doubling each attempt (60s, 2m, 4m, 8m).
If all attempts fail, or the failure is terminal, the event is marked as failed and will not be delivered again.
If your endpoint can’t process an event temporarily, respond with 5xx or 429 so Altur retries. A 4xx such as 400 tells Altur the event will never be accepted. Configure the final URL directly: a redirect (for example http → https, or a missing trailing slash) makes every delivery fail.

Example Workflow

Here’s a typical workflow for handling webhooks effectively:
  1. Set Up Your Endpoint Create an API endpoint in your backend, such as /webhooks/altur/on-call-end. Ensure the endpoint is publicly accessible and configured to accept POST requests with a Content-Type of application/json.
  2. Parse Incoming Data Extract and process the JSON payload sent by Altur. Ensure your code handles possible issues, such as malformed payloads or missing fields, to prevent runtime errors.
  3. Validate Request Authenticity Use the X-Altur-Signature header to verify the authenticity of the request. This involves:
    • Recomputing the HMAC signature using the shared secret and the parsed payload re-serialized as compact JSON.
    • Comparing it with the signature provided in the header.
  4. Respond Promptly Return a 200 OK status code to acknowledge successful receipt. Altur times out the request after 5 seconds, so respond well before that to avoid unnecessary retries.
  5. Log Events for Debugging Log the incoming request and processing steps to ensure traceability. This is particularly useful for debugging issues with payloads or retries.
  6. Handle Retries Gracefully Design your system to handle retries in case of temporary failures. Ensure your endpoint is idempotent so processing the same event multiple times does not create duplicate actions (e.g., duplicate database entries or API calls).

Best Practices

  1. Secure Your Endpoint
    • Authenticate Requests: Verify webhook authenticity using HMAC signatures. Always use a secure and unique shared secret for each integration.
    • Restrict Access: Use IP whitelisting or firewalls to allow requests only from Altur’s servers.
    • Encrypt Communication: Ensure your webhook endpoint uses HTTPS to encrypt data in transit.
  2. Log Events
    • Record Everything: Log all incoming webhook requests, including timestamps, headers, payloads, and responses.
    • Monitor Failures: Implement alerts for repeated failures or invalid requests to quickly address issues.
    • Enable Debugging: Retain logs for a reasonable period to aid in debugging or auditing as necessary.
  3. Test Thoroughly
    • Simulate Events: Use the Altur dashboard to simulate webhook events and confirm your endpoint handles them correctly.
    • Handle Edge Cases: Test scenarios like malformed payloads, large payloads, or missing fields to ensure robustness.
    • Use Staging Environments: Set up a dedicated staging endpoint for safe testing without affecting production systems.
  4. Optimize Performance
    • Respond Quickly: Altur times out after 5 seconds. If processing takes longer, acknowledge with 200 OK immediately and handle the work asynchronously.
    • Minimize Processing: Perform lightweight validation and queuing at the webhook level, offloading heavy processing to background workers.
    • Use Caching: Cache static responses for redundant requests when appropriate.
  5. Ensure Idempotency
    • Avoid Duplicate Actions: Design your system to handle retries without causing duplicate operations (e.g., database inserts or API calls). For campaign events, deduplicate on event_id. Call events (on_call_end, transfer_started, transfer_completed) have no event_id, so deduplicate on id plus event_type.
  6. Communicate Failures
    • Return Meaningful Status Codes: Respond with appropriate HTTP status codes to help diagnose issues (e.g., 400 for invalid requests or 500 for server errors). Remember that 4xx responses other than 408 and 429 are not retried.
    • Log and Notify: Log failures and consider notifying your team if critical retries are exhausted.

Troubleshooting Signature Validation

If you’re having trouble with signature validation, check these common issues:

1. JSON Serialization Format

Ensure you’re using the same JSON serialization format as Altur:
  • Parse, then re-serialize: Don’t compute the HMAC over the raw body. It contains spaces and won’t match.
  • Compact format: No spaces after colons or commas.
  • Escaped non-ASCII: Characters like í or ñ must be escaped as \uXXXX (Sofía → Sof\u00eda). JSON.stringify doesn’t do this; see the JavaScript example.
  • Consistent ordering: Keep keys in the order they were received.
  • PHP: Use json_decode($raw), not json_decode($raw, true). Associative arrays turn {} into [].

2. Secret Key Format

  • Ensure your secret key is base64-encoded
  • The secret should be the same one configured in your Altur webhook integration

3. Header Name

  • The signature header is X-Altur-Signature (case-sensitive in some frameworks)
  • Make sure you’re reading the correct header

4. Timing Attacks

Always use timing-safe comparison functions:
  • Python: hmac.compare_digest()
  • Node.js: crypto.timingSafeEqual()
  • PHP: hash_equals()

5. Testing Your Implementation

You can test your signature validation with this example: