> ## Documentation Index
> Fetch the complete documentation index at: https://docs.hana.health/llms.txt
> Use this file to discover all available pages before exploring further.

# Webhooks

> Receive real-time events from HANA — engagement outcomes, escalations, patient updates, and system status.

## Overview

Webhooks are how HANA pushes data to your system in real time. When a patient interaction completes, a risk flag is detected, or a clinical note is generated, HANA sends an HTTP POST to your configured endpoint.

This is the primary mechanism for the "closed loop" — HANA engages the patient, then sends structured results back to your EHR, care platform, or internal system.

***

## Event Types

### Engagement Events

| Event                  | Fired When                                  | Typical Use                      |
| ---------------------- | ------------------------------------------- | -------------------------------- |
| `engagement.scheduled` | Engagement queued for future delivery       | Update your scheduling UI        |
| `engagement.started`   | Patient answered (voice) or responded (SMS) | Log interaction start            |
| `engagement.completed` | Full interaction finished                   | Ingest clinical note, update EHR |
| `engagement.failed`    | Could not reach patient after retries       | Trigger manual follow-up         |
| `engagement.cancelled` | Engagement cancelled via API                | Clean up internal records        |

### Clinical Events

| Event                     | Fired When                               | Typical Use                 |
| ------------------------- | ---------------------------------------- | --------------------------- |
| `engagement.escalated`    | Risk signal detected during conversation | Alert care team immediately |
| `engagement.task_created` | Clinical task generated from interaction | Route to task queue         |
| `clinical_note.ready`     | Structured clinical note finalized       | Write to EHR                |

### Patient Events

| Event                      | Fired When                              | Typical Use               |
| -------------------------- | --------------------------------------- | ------------------------- |
| `patient.memory_updated`   | Patient preferences or patterns learned | Sync longitudinal profile |
| `patient.barrier_detected` | New adherence barrier identified        | Update care plan          |
| `patient.trend_change`     | Significant change in tracked metric    | Notify provider           |

### System Events

| Event             | Fired When                    | Typical Use           |
| ----------------- | ----------------------------- | --------------------- |
| `system.health`   | Periodic health check         | Monitoring dashboards |
| `batch.completed` | Batch engagement job finished | Process bulk results  |

***

## Payload Structure

Every webhook payload follows a consistent envelope:

```json theme={null}
{
  "id": "evt_abc123",
  "event": "engagement.completed",
  "timestamp": "2026-02-08T10:08:30Z",
  "api_version": "2026-01-01",
  "data": {
    // Event-specific payload
  }
}
```

### `engagement.completed` Payload

The most common event. Contains the full output of a patient interaction:

```json theme={null}
{
  "id": "evt_abc123",
  "event": "engagement.completed",
  "timestamp": "2026-02-08T10:08:30Z",
  "api_version": "2026-01-01",
  "data": {
    "engagement_id": "eng_abc123",
    "patient_id": "P-12345",
    "protocol": "medication-adherence-diabetes",
    "channel": "voice",
    "duration_seconds": 390,
    "clinical_note": {
      "summary": "Patient reports taking metformin ~4/7 days this week. Primary barrier is cost — insurance changed and copay increased. Reports mild nausea but considers it tolerable. No other side effects. Mood stable, sleep adequate.",
      "structured_data": {
        "medication_adherence": 0.57,
        "barriers": ["cost"],
        "side_effects": ["mild_nausea"],
        "mood": "stable",
        "sdoh_flags": ["insurance_change"]
      }
    },
    "tasks": [
      {
        "id": "task_xyz",
        "type": "review_medication_assistance",
        "priority": "medium",
        "reason": "Patient reports cost barrier to adherence due to insurance change",
        "suggested_action": "Review copay assistance programs or generic alternatives"
      }
    ],
    "risk_flags": [],
    "risk_level": "low",
    "metrics": {
      "engagement_score": 0.92,
      "completion_rate": 1.0,
      "interaction_count": 8,
      "sentiment": "neutral_positive"
    },
    "transcript_url": "https://api.hana.health/v1/engagements/eng_abc123/transcript"
  }
}
```

### `engagement.escalated` Payload

Sent immediately when a risk signal is detected. This is the highest-priority event:

```json theme={null}
{
  "id": "evt_esc456",
  "event": "engagement.escalated",
  "timestamp": "2026-02-08T10:05:12Z",
  "api_version": "2026-01-01",
  "data": {
    "engagement_id": "eng_abc123",
    "patient_id": "P-12345",
    "escalation_type": "clinical_risk",
    "severity": "high",
    "reason": "Patient expressed passive suicidal ideation during medication discussion",
    "action_taken": "AI conversation paused. Patient informed of crisis resources.",
    "requires_human_review": true,
    "contact_info": {
      "phone": "+15550123456",
      "last_channel": "voice"
    }
  }
}
```

<Warning>
  **Escalation events should trigger immediate action in your system.** Configure alerts, page on-call staff, or route to a human operator. HANA pauses the AI conversation and follows the clinic's defined escalation protocol, but your system must acknowledge and act.
</Warning>

***

## Configuring Webhooks

### Via API

```bash theme={null}
POST /v1/webhooks
```

```json theme={null}
{
  "url": "https://your-app.com/webhooks/hana",
  "events": [
    "engagement.completed",
    "engagement.escalated",
    "clinical_note.ready"
  ],
  "secret": "whsec_your_secret_here"
}
```

### Via SDK

<CodeGroup>
  ```javascript Node.js theme={null}
  await hana.webhooks.create({
    url: 'https://your-app.com/webhooks/hana',
    events: ['engagement.completed', 'engagement.escalated'],
    secret: process.env.HANA_WEBHOOK_SECRET
  });
  ```

  ```python Python theme={null}
  hana.webhooks.create(
      url="https://your-app.com/webhooks/hana",
      events=["engagement.completed", "engagement.escalated"],
      secret=os.environ["HANA_WEBHOOK_SECRET"]
  )
  ```
</CodeGroup>

### Filtering Events

Subscribe only to the events you need. Less noise, fewer wasted requests:

```json theme={null}
{
  "url": "https://your-ehr.com/hana-notes",
  "events": ["clinical_note.ready"],
  "filters": {
    "protocol": ["medication-adherence-*", "intake-*"],
    "risk_level": ["medium", "high", "critical"]
  }
}
```

***

## Delivery & Retry

HANA guarantees at-least-once delivery for all webhook events.

### Retry Schedule

If your endpoint returns a non-2xx status code or times out (30 seconds), HANA retries with exponential backoff:

| Attempt   | Delay      |
| --------- | ---------- |
| 1st retry | 30 seconds |
| 2nd retry | 2 minutes  |
| 3rd retry | 10 minutes |
| 4th retry | 1 hour     |
| 5th retry | 4 hours    |

After 5 failed attempts, the event is moved to the dead letter queue. You can replay failed events via the API:

```bash theme={null}
POST /v1/webhooks/{webhook_id}/replay
```

```json theme={null}
{
  "event_ids": ["evt_abc123", "evt_def456"]
}
```

### Idempotency

Every event has a unique `id`. Your system should deduplicate based on this ID, since retries may deliver the same event more than once.

```javascript theme={null}
// Example: Check if event was already processed
const processed = await db.webhookEvents.findOne({ eventId: event.id });
if (processed) return res.status(200).send('already processed');
```

***

## Testing Webhooks

### Sandbox Events

In sandbox mode, all engagements produce simulated webhook events. Test your integration end-to-end without real patient calls:

```javascript theme={null}
const hana = new HanaClient({
  apiKey: process.env.HANA_API_KEY,
  environment: 'sandbox'
});

// This triggers a simulated engagement + webhook delivery
const engagement = await hana.engagements.create({
  patient: { id: 'TEST-001', phone: '+15550000000' },
  protocol: 'medication-adherence-diabetes',
  triggerType: 'immediate'
});
```

### Manual Event Trigger

Send a test event to your endpoint:

```bash theme={null}
POST /v1/webhooks/{webhook_id}/test
```

```json theme={null}
{
  "event": "engagement.completed"
}
```

This sends a synthetic payload to your URL so you can verify connectivity, parsing, and signature verification.

<Card title="Next: EHR Integration" icon="database" href="/developers/ehr-integration">
  Connect HANA to your Electronic Health Record system.
</Card>
