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

# Eligibility Check Guide

> How to submit an insurance eligibility check, poll for results, and receive notifications via webhook when a check completes.

## Overview

The Shasta Health Eligibility API lets you verify a patient's insurance coverage programmatically. The flow is asynchronous: submit a check, then either poll the status endpoint or wait to receive a notification via webhook when the check completes.

## Requirements

Before making your first eligibility check, complete these two setup steps.

### 1. Generate an API key

All requests to the Shasta Health Eligibility API must include an API key in the `Authorization` header. Follow the [Authentication guide](/guides/api/authentication) to generate a key and learn how to include it in requests.

### 2. Configure your webhook URL

To receive notifications via webhook when a check completes, go to **Settings > API** at [app.shasta.health/provider/settings/api](https://app.shasta.health/provider/settings/api) in the Shasta provider portal and enter your webhook URL in the **Webhooks** section. If you prefer to poll for results instead, you can skip this step.

### 3. Set up a signing secret (recommended)

A signing secret lets you verify that webhook events are genuinely sent by Shasta Health.

1. In the **Webhooks** section of **Settings > API**, click **Edit** on your webhook.
2. Click the generate button next to the **Signing Secret** field to create a new secret, or enter your own.
3. Copy the secret and store it securely — you will need it to verify incoming webhooks. You can always view or roll this secret from the webhook settings page.

<Warning>
  Treat the signing secret like a password. Store it in an environment variable or secrets manager — never commit it to source control.
</Warning>

## Step 1 — Submit an eligibility check

Send a `POST` request to `/api/eligibility` with the provider, subscriber, and trading partner information.

### Request

<CodeGroup>
  ```bash curl theme={null}
  curl -X POST https://app.shasta.health/api/eligibility \
    -H "Authorization: Key $SHASTA_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "tradingPartnerServiceId": "60054",
      "provider": {
        "organizationName": "Shasta Medical Group",
        "npi": "1234567890"
      },
      "subscriber": {
        "firstName": "Jane",
        "lastName": "Doe",
        "dateOfBirth": "19800115",
        "memberId": "XYZ123456"
      },
      "encounter": {
        "serviceTypeCodes": ["30"],
        "dateOfService": "20260301"
      }
    }'
  ```

  ```typescript JavaScript / TypeScript theme={null}
  const SHASTA_API_KEY = process.env.SHASTA_API_KEY;

  const response = await fetch("https://app.shasta.health/api/eligibility", {
    method: "POST",
    headers: {
      "Authorization": `Key ${SHASTA_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      tradingPartnerServiceId: "60054",
      provider: {
        organizationName: "Shasta Medical Group",
        npi: "1234567890",
      },
      subscriber: {
        firstName: "Jane",
        lastName: "Doe",
        dateOfBirth: "19800115",
        memberId: "XYZ123456",
      },
      encounter: {
        serviceTypeCodes: ["30"],
        dateOfService: "20260301",
      },
    }),
  });

  const data = await response.json();
  console.log(data);
  ```

  ```python Python theme={null}
  import os
  import requests

  api_key = os.environ["SHASTA_API_KEY"]

  response = requests.post(
      "https://app.shasta.health/api/eligibility",
      headers={
          "Authorization": f"Key {api_key}",
          "Content-Type": "application/json",
      },
      json={
          "tradingPartnerServiceId": "60054",
          "provider": {
              "organizationName": "Shasta Medical Group",
              "npi": "1234567890",
          },
          "subscriber": {
              "firstName": "Jane",
              "lastName": "Doe",
              "dateOfBirth": "19800115",
              "memberId": "XYZ123456",
          },
          "encounter": {
              "serviceTypeCodes": ["30"],
              "dateOfService": "20260301",
          },
      },
  )

  print(response.json())
  ```
</CodeGroup>

### Response

```json theme={null}
{
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "status": "IN_PROGRESS"
}
```

Save the `id` — you can use it to GET the eligibility check status and results once complete.

## Step 2 — Webhook notification

<Tip>
  This is the recommended way to receive eligibility results.
</Tip>

When the eligibility check finishes processing, Shasta sends a single `POST` request to your configured webhook URL. The webhook fires exactly once per check, and the `status` in the payload will always be either `COMPLETED` or `FAILED` — it will never fire while the check is still in progress. The payload uses the same schema as the `GET /api/eligibility/{id}/status` response.

### Webhook configuration

The webhook URL and signing secret are configured during the Requirements step above. You do not pass a webhook URL in the API request.

### Webhook headers

Every webhook request includes the following headers:

| Header                | Description                                                                              |
| --------------------- | ---------------------------------------------------------------------------------------- |
| `X-Webhook-Timestamp` | Unix timestamp (seconds) of when the request was sent.                                   |
| `X-Webhook-Signature` | HMAC-SHA256 hex digest of the request. Only present when a signing secret is configured. |

### Verifying the webhook signature

If you configured a signing secret, each webhook request will include an `X-Webhook-Signature` header. To verify it, compute the expected signature and compare:

1. Read the `X-Webhook-Timestamp` header and the raw request body.
2. Concatenate them as `{timestamp}.{body}`.
3. Compute the HMAC-SHA256 hex digest using your signing secret.
4. Compare the result to the `X-Webhook-Signature` header value using a constant-time comparison.

<CodeGroup>
  ```typescript JavaScript / TypeScript theme={null}
  import { createHmac, timingSafeEqual } from "crypto";

  function verifyWebhookSignature(
    body: string,
    timestamp: string,
    signature: string,
    secret: string
  ): boolean {
    const expected = createHmac("sha256", secret)
      .update(`${timestamp}.${body}`)
      .digest("hex");
    return timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
  }
  ```

  ```python Python theme={null}
  import hashlib
  import hmac

  def verify_webhook_signature(
      body: str, timestamp: str, signature: str, secret: str
  ) -> bool:
      expected = hmac.new(
          secret.encode(), f"{timestamp}.{body}".encode(), hashlib.sha256
      ).hexdigest()
      return hmac.compare_digest(expected, signature)
  ```
</CodeGroup>

<Tip>
  To protect against replay attacks, also verify that the `X-Webhook-Timestamp` is within a reasonable window (e.g. 5 minutes) of the current time.
</Tip>

### Webhook payload

The webhook body is a JSON object with the same `EligibilityCheckResponse` schema:

```json theme={null}
{
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "status": "COMPLETED",
  "payer": {
    "payerName": "Aetna",
    "payerId": "60054",
    "entityIdentifier": "Payer",
    "entityType": "Non-Person Entity"
  },
  "subscriber": {
    "memberId": "XYZ123456",
    "firstName": "Jane",
    "lastName": "Doe",
    "dateOfBirth": "19800101",
    "groupNumber": "GRP001",
    "gender": "F",
    "address": {
      "address1": "123 Main St",
      "city": "Springfield",
      "state": "IL",
      "postalCode": "62701"
    }
  },
  "tradingPartnerServiceId": "60054",
  "planInformation": {
    "planName": "PPO Gold Plan",
    "insuranceType": "Preferred Provider Organization",
    "insuranceTypeCode": "PR"
  },
  "planDateInformation": {
    "eligibility": "20240101",
    "plan": "20240101-20241231"
  },
  "planActive": true,
  "providerNetwork": {
    "status": "In Network",
    "tier": "Tier 1",
    "specialty": "General Practice"
  },
  "benefits": [
    {
      "coverageStatus": "Active Coverage",
      "serviceType": "Medical Nutrition",
      "inNetwork": true,
      "copay": 30,
      "deductible": 500,
      "deductibleRemaining": 200,
      "deductibleApplies": true,
      "outOfPocketMax": 5000,
      "outOfPocketRemaining": 3000,
      "visitLimit": 20,
      "visitsUsed": 5,
      "authorizationRequired": false,
      "confidence": {
        "score": 0.9,
        "criteria": [
          "Copay confirmed on payer portal benefits page",
          "Visit limit matched across two portal sections"
        ]
      }
    }
  ]
}
```

Your endpoint should return a `200` status code to acknowledge receipt.

### Handling failures

If the check fails, the webhook payload will have `"status": "FAILED"` and an `errors` array:

```json theme={null}
{
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "status": "FAILED",
  "payer": {
    "payerName": "Aetna",
    "payerId": "60054"
  },
  "subscriber": {
    "memberId": "XYZ123456",
    "firstName": "Jane",
    "lastName": "Doe",
    "dateOfBirth": "19800101"
  },
  "tradingPartnerServiceId": "60054",
  "errors": [
    {
      "field": "AAA",
      "code": "67",
      "description": "Patient not found",
      "followupAction": "Please Correct and Resubmit"
    }
  ]
}
```

## Step 3 — Retrieve an eligibility result (optional)

Use `GET /api/eligibility/{id}/status` to check the processing status and get results once the check is complete.

### Request

<CodeGroup>
  ```bash curl theme={null}
  curl https://app.shasta.health/api/eligibility/a1b2c3d4-e5f6-7890-abcd-ef1234567890/status \
    -H "Authorization: Key $SHASTA_API_KEY"
  ```

  ```typescript JavaScript / TypeScript theme={null}
  const SHASTA_API_KEY = process.env.SHASTA_API_KEY;
  const id = "a1b2c3d4-e5f6-7890-abcd-ef1234567890";

  const response = await fetch(
    `https://app.shasta.health/api/eligibility/${id}/status`,
    {
      headers: {
        "Authorization": `Key ${SHASTA_API_KEY}`,
      },
    }
  );

  const data = await response.json();
  console.log(data);
  ```

  ```python Python theme={null}
  import os
  import requests

  api_key = os.environ["SHASTA_API_KEY"]
  id = "a1b2c3d4-e5f6-7890-abcd-ef1234567890"

  response = requests.get(
      f"https://app.shasta.health/api/eligibility/{id}/status",
      headers={
          "Authorization": f"Key {api_key}",
      },
  )

  print(response.json())
  ```
</CodeGroup>

### While processing

While the check is still running, the response contains only `id` and `status`:

```json theme={null}
{
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "status": "IN_PROGRESS"
}
```

### When complete

Once the check finishes, the full eligibility response is returned:

```json theme={null}
{
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "status": "COMPLETED",
  "payer": {
    "payerName": "Aetna",
    "payerId": "60054",
    "entityIdentifier": "Payer",
    "entityType": "Non-Person Entity"
  },
  "subscriber": {
    "memberId": "XYZ123456",
    "firstName": "Jane",
    "lastName": "Doe",
    "dateOfBirth": "19800101",
    "groupNumber": "GRP001",
    "gender": "F",
    "address": {
      "address1": "123 Main St",
      "city": "Springfield",
      "state": "IL",
      "postalCode": "62701"
    }
  },
  "tradingPartnerServiceId": "60054",
  "planInformation": {
    "planName": "PPO Gold Plan",
    "insuranceType": "Preferred Provider Organization",
    "insuranceTypeCode": "PR"
  },
  "planDateInformation": {
    "eligibility": "20240101",
    "plan": "20240101-20241231"
  },
  "planActive": true,
  "providerNetwork": {
    "status": "In Network",
    "tier": "Tier 1",
    "specialty": "General Practice"
  },
  "benefits": [
    {
      "coverageStatus": "Active Coverage",
      "serviceType": "Medical Nutrition",
      "inNetwork": true,
      "copay": 30,
      "deductible": 500,
      "deductibleRemaining": 200,
      "deductibleApplies": true,
      "outOfPocketMax": 5000,
      "outOfPocketRemaining": 3000,
      "visitLimit": 20,
      "visitsUsed": 5,
      "authorizationRequired": false,
      "confidence": {
        "score": 0.9,
        "criteria": [
          "Copay confirmed on payer portal benefits page",
          "Visit limit matched across two portal sections"
        ]
      }
    }
  ]
}
```

If the check failed, `status` will be `FAILED` and the `errors` array will contain details.

<Tip>
  Most checks complete within 10 minutes.
  If you have a webhook configured, you can skip polling entirely and wait for the webhook notification.
</Tip>

## Status values

| Status        | Description                                                         |
| ------------- | ------------------------------------------------------------------- |
| `IN_PROGRESS` | The eligibility check is still being processed.                     |
| `COMPLETED`   | The check finished successfully. Full results are available.        |
| `FAILED`      | The check encountered an error. See the `errors` array for details. |

## Coverage status

Each entry in the `benefits` array includes a `coverageStatus` field indicating the coverage determination for that service type:

| Value             | Description                                                                                                                    |
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| `Active Coverage` | The plan is active and the service is covered. Cost-sharing details (copay, coinsurance, deductibles, etc.) will be populated. |
| `Not Covered`     | The plan is active but the specific service is not a covered benefit. The benefits entry will not include cost-sharing fields. |

When coverage could not be determined, the `benefits` array will be empty.

### Not Covered example

```json theme={null}
{
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "status": "COMPLETED",
  "planActive": true,
  "benefits": [
    {
      "coverageStatus": "Not Covered",
      "serviceType": "Preventive Nutrition",
      "inNetwork": true
    }
  ]
}
```

## Confidence score

Each entry in the `benefits` array may include a `confidence` object with a `score` (0–1) indicating how reliable that specific benefit entry is. Different service types can have different confidence levels — for example, a medical benefit verified from multiple portal pages will score higher than a preventive benefit inferred from a single section.

The `confidence.criteria` field is an array of human-readable reason strings explaining the score:

```json theme={null}
{
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "status": "COMPLETED",
  "benefits": [
    {
      "coverageStatus": "Active Coverage",
      "serviceType": "Medical Nutrition",
      "copay": 30,
      "visitLimit": 20,
      "confidence": {
        "score": 0.9,
        "criteria": [
          "Copay confirmed on payer portal benefits page",
          "Visit limit matched across two portal sections",
          "Deductible cross-referenced with accumulator page"
        ]
      }
    },
    {
      "coverageStatus": "Active Coverage",
      "serviceType": "Preventive Nutrition",
      "copay": 0,
      "confidence": {
        "score": 0.6,
        "criteria": [
          "Preventive benefits section found on portal",
          "Visit limit not listed -- could not verify"
        ]
      }
    }
  ]
}
```

<Tip>
  Confidence scoring is optional. If no confidence data is available for a benefit entry, the `confidence` field will not be present on that entry.
</Tip>

## Next steps

See the [API Reference](/api-reference) for full schema details on all request and response fields.
