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

# Webhooks

> Webhooks for the Lenders API

## Purpose

Webhooks allow you to receive real-time updates about events related to your loan
applications. This can help you keep your system in sync with Covered's platform
and provide a better experience for your users.

Webhooks events are sparse and for security reasons do not contain any PII or sensitive data.
This means you will need to make a separate request to the API to get the full details of the event.
For example, if you receive a `policy.bound` event, you will need to make a request to the
<Link href="/api-reference/endpoint/get_policy">`GET /v1/policies/{id}`</Link> endpoint to get the details of the policy.

## Registration

Reach out to Covered support to register for webhooks. You will need to provide
a URL to receive the webhook events and optionally provide basic auth
credentials to accompany the request to your endpoint.

## Handling

When you receive a webhook event, you should respond with a HTTP status code in the
range of 200-299(inclusive) to acknowledge receipt of the event.  Any other status code
will be treated as a failure and Covered will retry the request 6 times a day for the next
14 days.

## Authentication & Handling

### Headers

<ParamField header="Authorization" type="string">
  Optional.  The username and password registered with Covered support for your webhook
  endpoint, presented as Basic Authorization header.  You can use this to verify the
  request is coming from Covered.
</ParamField>

<ParamField header="X-Covered-Signature-1" type="string">
  Optional.  A signature of the request body using HMAC SHA-256 with a client secret provided
  by Covered support.  This can be used to verify the integrity of the request and ensure
  it has not been tampered with in transit.
  The signature is calculated as follows:
</ParamField>

<ParamField header="X-Covered-Partner-Id" type="string">
  The ID from Covered of the partner that shopped the loan
</ParamField>

<ParamField header="X-Covered-External-Id" type="string">
  Optional.  The ID provided as `externalId` when the loan application was created
</ParamField>

### HMAC Verification

<Steps>
  <Step title="Load your client secret">
    Load the client secret provided by Covered support. This is the same secret you use for
    authenticating API requests.
  </Step>

  <Step title="Create a signature">
    Create a HMAC SHA-256 signature of the request body using the client secret as the key.
    The signature should be in hexadecimal format.
  </Step>

  <Step title="Compare signatures">
    Compare the signature in the `X-Covered-Signature-1` header with the signature you created.
    To prevent timing attacks, use a constant-time comparison function like `timingSafeEqual` in Node.js.
    If they match, the request is valid and you can process the webhook event.
    If they do not match, reject the request as it may have been tampered with.
  </Step>
</Steps>

#### Example Code

<CodeGroup>
  ```js verifyRequest.js theme={null}
  import { createHmac, timingSafeEqual } from 'crypto';

  export const createSignature = (content) => {
  const coveredClientSecret = process.env.COVERED_CLIENT_SECRET;
  const signatureAlgorithm = 'sha256';
  const hmac = createHmac(signatureAlgorithm, coveredClientSecret);
  const signature = hmac.update(content).digest('hex');
  return signature;
  };

  export const verifyRequest = (req) => {
  const coveredSignature = req.headers['x-covered-signature-1'];
  const mySignature = createSignature(req.rawBody);
  const isMessageFromCovered = timingSafeEqual(
    Buffer.from(coveredSignature),
    Buffer.from(mySignature)
  );
  return isMessageFromCovered;
  };
  ```
</CodeGroup>

#### Example Signature

However you implement your signature function, when you run it with:

* content: `'Hello, from Covered!'`
* client secret: `'Open Sesame'`
  the resulting signature should be:

```
c5bd4c4eab749a037897b3df74f407e095bef784d65c5077252c31525af6d481
```

## Schema

All webhook events follow the same common schema at the top level. Differences between events
are in the `data` object.  The following fields are common to all events:

<ParamField body="id" type="string" required="true">
  The ID of the webhook event.  This can be used to deduplicate events.
</ParamField>

<ParamField body="type" type="string" required="true">
  The type of the webhook event, which describes what the type of change that happened.
</ParamField>

<ParamField body="objectType" type="string" required="true">
  The subject of the webhook event, which describes what object the change happened to.
</ParamField>

<ParamField body="occurredAt" type="string" required="true">
  The date and time the event occurred in ISO 8601 format.  This can be used to prevent
  replaying old events by rejecting events that are older than our maximum delivery window,
  which is currently 14 days.
</ParamField>

<ParamField body="data" type="object" required="true">
  The specific data needed to process and make followup calls for this event,
  usually consisting of the IDs needed to make the followup calls for additional
  details.
</ParamField>

<RequestExample>
  ```json loan.shopped theme={null}
  {
    "id": "1bfa8c6b-521c-4d62-b854-0f9776cad806",
    "type": "loan.shopped",
    "objectType": "loan",
    "occurredAt": "2025-07-07T12:36:43.339Z",
    "data": {
      "loanId": "07af98b6-ebc6-45e8-8e9e-64d2b40cf07a",
      "partnerId": "1088491058",
      "platformId": null,
      "externalId": "8920-5"
    }
  }
  ```

  ```json policy.bound theme={null}
  {
    "id": "2bfa8c6b-521c-4d62-b854-0f9776cad806",
    "type": "policy.bound",
    "objectType": "policy",
    "occurredAt": "2025-07-11T16:36:22.439Z",
    "data": {
      "policyId": "1ab62d94-8f1e-40e8-98e5-2e608213d0e9",
      "loanId": "07af98b6-ebc6-45e8-8e9e-64d2b40cf07a",
      "partnerId": "1088491058",
      "platformId": null,
      "externalId": "8920-5"
    }
  }
  ```

  ```json policy.retrieved theme={null}
  {
    "id": "2bfa8c6b-521c-4d62-b854-0f9776cad806",
    "type": "policy.retrieved",
    "objectType": "policy",
    "occurredAt": "2025-07-11T16:36:22.439Z",
    "data": {
      "policyId": "1ab62d94-8f1e-40e8-98e5-2e608213d0e9",
      "loanId": "07af98b6-ebc6-45e8-8e9e-64d2b40cf07a",
      "partnerId": "1088491058",
      "platformId": null,
      "externalId": "8920-5"
    }
  }
  ```
</RequestExample>

## Types

### Loan

Loan webhooks keep you informed about the status of loan applications that your users
shop through the Covered marketplace.

<Expandable title="Loan Shopped">
  #### Loan Application Shopped

  <ParamField body="id" type="string" required="true">
    The ID of the webhook event.  This can be used to deduplicate events.
  </ParamField>

  <ParamField body="type" type="string" required="true">
    The type of the webhook event.  Always `loan.shopped` for this event.
  </ParamField>

  <ParamField body="objectType" type="string" required="true">
    The subject of the webhook event.  Always `loan` for this event.
  </ParamField>

  <ParamField body="occurredAt" type="string" required="true">
    The date and time the event occurred in ISO 8601 format.  This can be used to prevent
    replaying old events by rejecting events that are older than our maximum delivery window,
    which is currently 14 days.
  </ParamField>

  <Expandable title="data">
    <ParamField body="loanId" type="string" required="true">
      The ID of the loan shopped.  Use this ID as the `id` parameter in the
      <Link href="/api-reference/endpoint/get_shopped_loan_application">`GET /v1/loans/{id}/shop`</Link> endpoint to get the details of the policy.
    </ParamField>

    <ParamField body="partnerId" type="string" required="true">
      The ID of the partner that shopped the loan.
    </ParamField>

    <ParamField body="platformId" type="string">
      The ID of the platform this loan was shopped on.
    </ParamField>

    <ParamField body="externalId" type="string">
      The ID provided as `externalId` when the loan application was created
    </ParamField>
  </Expandable>
</Expandable>

### Policy

Policy webhooks keep you informed about the status of policies that your users
buy through the Covered marketplace.

<Expandable title="Policy Bound">
  #### Policy Bound

  <ParamField body="id" type="string" required="true">
    The ID of the webhook event.  This can be used to deduplicate events.
  </ParamField>

  <ParamField body="type" type="string" required="true">
    The type of the webhook event.  Always `policy.bound` for this event.
  </ParamField>

  <ParamField body="objectType" type="string" required="true">
    The subject of the webhook event.  Always `policy` for this event.
  </ParamField>

  <ParamField body="occurredAt" type="string" required="true">
    The date and time the event occurred in ISO 8601 format.  This can be used to prevent
    replaying old events by rejecting events that are older than our maximum delivery window,
    which is currently 14 days.
  </ParamField>

  <ParamField body="data" type="object" required="true">
    The data object contains the details particular to this event type.

    <Expandable title="data">
      <ParamField body="policyId" type="string" required="true">
        The ID of the bound policy.  Use this ID as the `id` parameter in the
        <Link href="/api-reference/endpoint/get_policy">`GET /v1/policies/{id}`</Link> endpoint to get the details of the policy.
      </ParamField>

      <ParamField body="loanId" type="string">
        The ID of the loan application associated with the policy.  This ID
        may not be present if the policy was not one of the options of the initial
        shopping results.
      </ParamField>

      <ParamField body="partnerId" type="string" required="true">
        The ID of the partner this policy is attributed to.
      </ParamField>

      <ParamField body="platformId" type="string">
        The ID of platform this policy is attributed to.  This will be null if the
        partner is directly integrated with Covered and not a tenant of a platform.
      </ParamField>

      <ParamField body="externalId" type="string">
        The ID provided as `externalId` when the loan application was created
      </ParamField>
    </Expandable>
  </ParamField>
</Expandable>

<Expandable title="Policy Retrieved">
  #### Policy Retrieved

  <ParamField body="id" type="string" required="true">
    The ID of the webhook event.  This can be used to deduplicate events.
  </ParamField>

  <ParamField body="type" type="string" required="true">
    The type of the webhook event.  Always `policy.retrieved` for this event.
  </ParamField>

  <ParamField body="objectType" type="string" required="true">
    The subject of the webhook event.  Always `policy` for this event.
  </ParamField>

  <ParamField body="occurredAt" type="string" required="true">
    The date and time the event occurred in ISO 8601 format.  This can be used to prevent
    replaying old events by rejecting events that are older than our maximum delivery window,
    which is currently 14 days.
  </ParamField>

  <ParamField body="data" type="object" required="true">
    The data object contains the details particular to this event type.

    <Expandable title="data">
      <ParamField body="policyId" type="string" required="true">
        The ID of the bound policy.  Use this ID as the `id` parameter in the
        <Link href="/api-reference/endpoint/get_policy">`GET /v1/policies/{id}`</Link> endpoint to get the details of the policy.
      </ParamField>

      <ParamField body="loanId" type="string">
        The ID of the loan application associated with the policy.
      </ParamField>

      <ParamField body="partnerId" type="string" required="true">
        The ID of the partner this policy is attributed to.
      </ParamField>

      <ParamField body="platformId" type="string">
        The ID of platform this policy is attributed to.  This will be null if the
        partner is directly integrated with Covered and not a tenant of a platform.
      </ParamField>

      <ParamField body="externalId" type="string">
        The ID provided as `externalId` when the loan application was created
      </ParamField>
    </Expandable>
  </ParamField>
</Expandable>
