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

# Agency License Expired

> Webhook event triggered the day after an agency license passes its renewal date

## Overview

The `DOWNSTREAM_ENTITY_LICENSE_EXPIRED` webhook is triggered the day after one of your agencies' licenses passes its renewal date.

[Agency Compliance Status Change](/guides/webhooks/downstream-entity-compliance-status-change) fires per product and state and only on an actual status flip, so a lapse in a state you carry no requirement for never reached you. This event does.

**Webhook type:** `DOWNSTREAM_ENTITY_LICENSE_EXPIRED`

### Triggers

One delivery per license, on the day after its `nextRenewalDate`.

The day **after** is deliberate: a state treats the renewal date as the last valid day, so a license expiring today is still valid today. `daysUntilExpiration` is therefore `-1` on a normal delivery, not `0`.

<Info>
  Deliveries land on a daily sweep at **05:00 America/New\_York**, not in real time. This is a date crossing rather
  than a change to a record.
</Info>

## What does not fire this event

| Change                                      | Use instead                                                                                                                                                                                     |
| ------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| The license is 60 days from renewal         | [Agency License Expiring](/guides/webhooks/downstream-entity-license-expiring)                                                                                                                  |
| A license with **no** `nextRenewalDate`     | Nothing. Perpetual and non-expiring licenses never fire either event                                                                                                                            |
| A license whose `status` is `inactive`      | Nothing. NIPR has already flagged it                                                                                                                                                            |
| A license revoked or suspended for cause    | [Agency Regulatory Action Added](/guides/webhooks/downstream-entity-regulatory-action-added), or [Agency Compliance Status Change](/guides/webhooks/downstream-entity-compliance-status-change) |
| A producer license passing its renewal date | [Agent License Expired](/guides/webhooks/agent-license-expired)                                                                                                                                 |
| A license renewed before the date passed    | Nothing fires. The renewal moves the date and re-arms the expiring event                                                                                                                        |

### Licenses marked do-not-renew DO fire

If a license has been marked do-not-renew, this event **still fires**, which is the opposite of how Turris treats its own renewal reminders. For a carrier this is arguably the most useful case of all: the license you most want to hear about lapsing is the one someone let lapse on purpose.

### There is no "expired" license status, and this payload proves it

The most confusing thing about this event: `status` on the payload normally reads **`"active"`** even though the license has expired.

That is correct. `status` is copied verbatim from the NIPR PDB payload and nothing in Turris derives it from a date, so a license can sit at `active` with a renewal date years past. This event exists precisely because the status field cannot tell you what this tells you.

Key on `daysUntilExpiration` being negative, or on `nextRenewalDate` being in the past. Never on `status`.

### Perpetual licenses never fire

Both events are driven entirely by a range query on `nextRenewalDate`, so a license without one never produces a delivery. That is **roughly 11% of agency licenses** on the platform. Reconcile against [Get Downstream Entity Licenses](/api-reference/v2/licenses/downstream-entity-licenses) if you need the complete set.

## Payload Example

```json theme={null} theme={null}
{
  "webhookType": "DOWNSTREAM_ENTITY_LICENSE_EXPIRED",
  "upstreamEntityId": "507f1f77bcf86cd799439010",
  "payload": {
    "licenseId": "507f1f77bcf86cd799439021",
    "niprDataSubscriptionId": "507f1f77bcf86cd799439014",
    "npn": "7654321",
    "stateCode": "GA",
    "licenseNumber": "L098765",
    "licenseClassCode": "PC",
    "licenseClassName": "Property & Casualty",
    "status": "active",
    "residencyStatus": "Non-Resident",
    "issueDate": "2018-06-15T00:00:00.000Z",
    "nextRenewalDate": "2026-08-19T00:00:00.000Z",
    "linesOfAuthority": [{ "code": "PROP", "name": "Property", "status": "Active" }],
    "daysUntilExpiration": -1,
    "expiringWindowDays": 60,
    "downstreamEntityId": "507f1f77bcf86cd799439012",
    "downstreamEntityAssociationId": "507f1f77bcf86cd799439011",
    "legalName": "RT Specialty LLC",
    "branchName": "RT Specialty - Miami Beach, FL",
    "producerCode": "03-e55f06b3-618c-4bf2-b578-efae34a87a6e"
  }
}
```

Note `status: "active"` on an expired license, and `daysUntilExpiration: -1`. Both are what a real delivery looks like.

### Payload Fields

| Field                           | Type                          | Description                                                                                  |
| ------------------------------- | ----------------------------- | -------------------------------------------------------------------------------------------- |
| `licenseId`                     | string                        | Turris's id for this license record.                                                         |
| `niprDataSubscriptionId`        | string                        | The NIPR data subscription this license was retrieved under.                                 |
| `npn`                           | string                        | The agency's National Producer Number.                                                       |
| `stateCode`                     | string                        | State that issued the license.                                                               |
| `licenseNumber`                 | string                        | The license number as filed with the state.                                                  |
| `licenseClassCode`              | string                        | License class code, e.g. `PC`.                                                               |
| `licenseClassName`              | string                        | Human-readable class.                                                                        |
| `status`                        | string                        | Verbatim NIPR status. **Normally `active` even here** — see above.                           |
| `residencyStatus`               | string                        | Resident or non-resident.                                                                    |
| `issueDate`                     | string \| null                | ISO-8601.                                                                                    |
| `nextRenewalDate`               | string                        | ISO-8601. Always present, and in the past on this event.                                     |
| `linesOfAuthority`              | array                         | `code`, `name` and `status` per line of authority.                                           |
| `daysUntilExpiration`           | number                        | Negative on this event, normally `-1`. Do not render it as "expires in -1 days".             |
| `expiringWindowDays`            | number                        | The expiring threshold, `60`. Carried here too so either delivery reconciles against the UI. |
| `downstreamEntityId`            | string, may be absent         | The agency record. Shared by every relationship you hold with it.                            |
| `downstreamEntityAssociationId` | string, may be absent         | The relationship you hold with that agency. **Match on this.**                               |
| `legalName`                     | string, may be absent         | The agency's legal name.                                                                     |
| `branchName`                    | string, may be absent         | Branch name of this relationship.                                                            |
| `producerCode`                  | string \| null, may be absent | Producer code assigned for this relationship.                                                |

<Note>
  **The entity fields are best-effort, and they all depend on one lookup.** `downstreamEntityId`, `legalName`,
  `downstreamEntityAssociationId`, `branchName` and `producerCode` are resolved from your association with the
  agency. If that lookup misses — an agency archived between our read and the delivery is the realistic case —
  **none of them arrive**. If it hits, `downstreamEntityId` and `downstreamEntityAssociationId` are always
  present and the rest are individually best-effort.

  One distinction worth reading carefully: an **absent** `producerCode` key means the lookup did not resolve,
  whereas `producerCode: null` means it resolved and no producer code is assigned.
</Note>

<Note>
  There is deliberately **no `expirationDate`** field. `nextRenewalDate` is the only expiry date the platform holds.
</Note>

## Deduplication and volume

Each license matches the expired boundary on exactly **one** calendar day, so you receive one delivery per license per renewal cycle. No debouncing, no batching.

<Warning>
  **Size your receiver for the spike, not for the median.** A typical sweep delivers **single digits** and the 95th
  percentile is under **50**, but the busiest measured sweep for a single carrier carries about **1,850 deliveries of
  this event alone**. Because renewal dates cluster on the last day of the month, this event's spikes land on the
  **1st or 2nd**. Return `2xx` quickly and queue.
</Warning>

<Warning>
  If the daily sweep does not run, that day's licenses are **not** announced later. There is no catch-up pass.
  Reconcile against [Get Downstream Entity Licenses](/api-reference/v2/licenses/downstream-entity-licenses) if you
  need a guarantee.
</Warning>

<Warning>
  Webhook subscriptions are per event type. Subscribing to Agency License Expired does **not** deliver
  [Agency License Expiring](/guides/webhooks/downstream-entity-license-expiring) — register a separate webhook for each.
</Warning>


## Related topics

- [Agent License Expired](/guides/webhooks/agent-license-expired.md)
- [Agency License Expiring](/guides/webhooks/downstream-entity-license-expiring.md)
- [Changelog](/changelog.md)
