Webhooks

Real-time event notifications for resource changes

View as Markdown

Overview

AskElephant delivers real-time webhook notifications when resources change in your workspace. Events are emitted consistently regardless of how the change originated — the web app, API writes, background jobs, or imports.

Webhook delivery is managed by Svix, providing automatic retries with exponential backoff, delivery logging, and endpoint management through a self-service portal.

Setup

  1. Navigate to Settings > Webhooks in the AskElephant dashboard
  2. The embedded Svix App Portal lets you:
    • Add webhook endpoints (your receiving URL)
    • Select which event types to subscribe to
    • View delivery history and debug failed deliveries
    • Rotate endpoint signing secrets
    • Send test events

No API keys or engineering setup required — any workspace owner can configure webhooks directly.

Event types

All event types are versioned with a v1. prefix. Standard resources emit created, updated, and deleted events. One special event fires when a transcript finishes processing.

Event typeTrigger
v1.contact.createdA contact is created
v1.contact.updatedA contact is updated
v1.contact.deletedA contact is deleted
v1.company.createdA company is created
v1.company.updatedA company is updated
v1.company.deletedA company is deleted
v1.engagement.createdAn engagement is created
v1.engagement.updatedAn engagement is updated
v1.engagement.deletedAn engagement is deleted
v1.tag.createdA tag is created
v1.tag.updatedA tag is updated
v1.tag.deletedA tag is deleted
v1.engagement.transcript_timeline.completedAn engagement transcript is ready for retrieval

Payload envelope

Every webhook delivery uses a consistent envelope structure:

1{
2 "id": "evt_01JWAS...",
3 "type": "v1.contact.updated",
4 "api_version": "v1",
5 "created_at": "2026-03-09T12:00:00.000Z",
6 "workspace_id": "wrks_01JWAS...",
7 "data": {
8 "object": { },
9 "previous_attributes": { }
10 }
11}
FieldTypeDescription
idstringUnique event identifier
typestringThe event type (see table above)
api_versionstringAPI version, currently v1
created_atstringISO 8601 timestamp of when the event was emitted
workspace_idstringThe workspace that owns the resource
data.objectobjectFull current state of the resource, matching the REST API response shape
data.previous_attributesobjectOnly present on updated events. Contains the previous values of fields that changed.

Delivery headers

Every webhook request also includes Svix signature headers alongside the JSON body:

HeaderDescription
svix-idUnique identifier for the delivery attempt
svix-timestampUnix timestamp used when computing the signature
svix-signatureSignature for the raw request payload

HTTP header names are case-insensitive, but the examples in this guide use Svix’s canonical lowercase header names.

Resource payloads

The data.object field matches the corresponding REST API response for each resource type.

Contact

1{
2 "object": "contact",
3 "id": "cnt_01JWAS...",
4 "first_name": "Jane",
5 "last_name": "Doe",
6 "emails": [
7 { "email": "jane@example.com", "is_primary": true }
8 ],
9 "phone_numbers": [
10 { "phone_number": "+1234567890", "is_primary": true }
11 ],
12 "crm_association": {
13 "object_type": "contact",
14 "crm_object_id": "sf_003ABC...",
15 "source": "salesforce"
16 },
17 "created_at": "2026-03-01T10:00:00.000Z",
18 "updated_at": "2026-03-09T12:00:00.000Z"
19}

Optional fields (description, company, time_zone, crm_association) are included only when they have a value.

Company

1{
2 "object": "company",
3 "id": "cmp_01JWAS...",
4 "name": "Acme Corp",
5 "domains": [
6 { "domain": "acme.com" }
7 ],
8 "crm_association": {
9 "object_type": "account",
10 "crm_object_id": "sf_001ABC...",
11 "source": "salesforce"
12 },
13 "created_at": "2026-03-01T10:00:00.000Z",
14 "updated_at": "2026-03-09T12:00:00.000Z"
15}

Optional fields (description, industry, website, number_of_employees, logo_url, crm_association) are included only when they have a value.

Engagement

1{
2 "object": "engagement",
3 "id": "ngmt_01JWAS...",
4 "title": "Q1 Pipeline Review",
5 "engagement_type": "MEETING",
6 "data_source": "ZOOM",
7 "processing_status": "COMPLETED",
8 "is_internal": false,
9 "engagement_at": "2026-03-09T14:00:00.000Z",
10 "start_at": "2026-03-09T14:00:00.000Z",
11 "end_at": "2026-03-09T14:45:00.000Z",
12 "duration_seconds": 2700,
13 "owner_user_id": "usr_01JWAS...",
14 "created_at": "2026-03-09T14:00:00.000Z",
15 "updated_at": "2026-03-09T15:00:00.000Z"
16}

Optional fields (description, meeting_url, host_user_id) are included only when they have a value.

Tag

1{
2 "object": "tag",
3 "id": "tag_01JWAS...",
4 "name": "churn-risk",
5 "hex_color": "#FF5733",
6 "description": "Customer showing signs of churn",
7 "auto_tagging_enabled": false,
8 "created_at": "2026-03-01T10:00:00.000Z",
9 "updated_at": "2026-03-09T12:00:00.000Z"
10}

Behavior details

previous_attributes on update events

When a resource is updated, the data.previous_attributes object contains only the fields that changed, with their pre-update values. Fields that did not change are omitted.

1{
2 "type": "v1.contact.updated",
3 "data": {
4 "object": {
5 "object": "contact",
6 "id": "cnt_01JWAS...",
7 "first_name": "Jane",
8 "last_name": "Doe",
9 "updated_at": "2026-03-09T12:00:00.000Z"
10 },
11 "previous_attributes": {
12 "first_name": "Janet"
13 }
14 }
15}

Changes to relation fields (emails, phone_numbers, domains) that do not modify the parent resource will not emit a webhook event. To detect these changes, poll the REST API or listen for the parent resource’s next updated event.

Delete events

When a resource is deleted, the data.object contains the full resource state at the time of deletion, including relation fields (emails, phone_numbers, domains). No previous_attributes is included on delete events.

Transcript timeline completion

The v1.engagement.transcript_timeline.completed event fires once when the engagement transcript has been persisted and is available for retrieval. The data.object is the full engagement (not the transcript timeline). Note that additional processing (AI analysis, enrichment) may still be in progress after this event.

Use the engagement id from the payload to fetch the transcript via GET /v2/engagements/{id}/transcript_timeline.

Recommended pattern:

  1. Receive v1.engagement.transcript_timeline.completed event
  2. Extract data.object.id (the engagement ID)
  3. Call GET /v2/engagements/{id}/transcript_timeline to fetch the full transcript with speaker details, sentiment, and timing

Delivery guarantees

Webhook delivery is managed by Svix, which provides:

  • Automatic retries with exponential backoff on failed deliveries
  • Delivery logging visible in the Svix App Portal
  • Endpoint signing so you can verify webhook authenticity
  • At-least-once delivery — your endpoint should be idempotent
  • Non-blocking — webhook delivery failures never block the operation that triggered the event

Verifying webhook signatures

Each webhook delivery is signed by Svix. Verify the request before processing it to ensure the payload is authentic and has not been tampered with.

Recommended verification flow:

  1. Read the svix-id, svix-timestamp, and svix-signature headers from the incoming request.
  2. Use the exact raw request body bytes or string as received over HTTP. Do not reserialize the parsed JSON before verification.
  3. Verify the request with the endpoint secret shown in the Svix App Portal for that webhook endpoint.
  4. Only parse and process the event after signature verification succeeds.

See the Svix verification documentation for language-specific examples.