> ## 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 Updated

> Webhook event triggered when an agency name, identity, or contact details change

<Note>
  **Webhooks belong to the Carrier & MGA API.** This event fires about an agency you appoint, and only a credential on that surface
  (carrier, MGA or wholesaler) can subscribe to it.
</Note>

## Overview

The `DOWNSTREAM_ENTITY_UPDATED` webhook is triggered when an agency's identity or profile changes after it was created.

It exists because agency names change on their own. A name filed with NIPR propagates into Turris on the daily sync, and an agency invited under a working name is renamed to its legal name the moment it submits its NPN. Neither is something you can anticipate, and neither previously produced any signal. If your reporting keys on agency name, the copy in your system drifts and the same agency starts appearing twice.

This event tells you the record changed, which fields changed, and what they were before.

**Webhook type:** `DOWNSTREAM_ENTITY_UPDATED`

### Triggers

This webhook fires when a published field on the agency relationship changes:

* the daily NIPR sync propagates a filed name change
* an agency you invited submits its NPN and is renamed to its legal name
* you edit the agency from the Entity Details tab
* you change the agency's NPN, or its EIN is corrected
* an agency record updates through the HubSpot sync

Only the fields listed under [What fires this event](#what-fires-this-event) trigger a delivery. An edit to anything else is silent.

<Info>
  This webhook is sent **immediately**, with no debouncing. Three consequences worth designing for, all covered
  below: a single edit can produce more than one delivery, a change to the agency record produces one delivery per
  relationship you hold with that agency, and a bulk operation can produce a burst.
</Info>

<Warning>
  **Size your receiver for bursts.** Because there is no debouncing, and because a change to an agency record fans
  out across every relationship you hold with that agency, one operation on our side can produce many deliveries.
  The daily NIPR sync is the case to plan for: it can rewrite the legal name of many agencies in one pass, and each
  rewritten agency then delivers once per relationship. Return 2xx quickly and queue the work rather than processing
  inline.
</Warning>

## What fires this event

Each field is published from exactly one record. That matters because an agency has two: the **relationship** you hold with it, which carries the details you see and edit, and the **agency record** itself, which carries its legal identity.

**From the relationship** — `branchName`, `doingBusinessAs`, `producerCode`, `externalId`, `website`, `phoneNumber`, `faxNumber`, `legalAddress`, `mailingAddress`, `entityType`

**From the agency record** — `legalName`, `npn`, `ein`

### What does not fire it

| Change                                              | Use instead                                                                                    |
| --------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
| An agency is added to your account                  | [Agency Created](/guides/webhooks/downstream-entity-created)                                   |
| An agency is archived or removed                    | [Agency Deleted](/guides/webhooks/downstream-entity-deleted)                                   |
| An archived agency is restored                      | Not currently signalled                                                                        |
| A producer agreement is executed                    | [Producer Agreement Executed](/guides/webhooks/producer-agreement-executed)                    |
| Licenses, appointments, or compliance status change | [Agency Compliance Status Change](/guides/webhooks/downstream-entity-compliance-status-change) |
| NIPR data finishes synchronizing                    | [Compliance Data Synchronized](/guides/webhooks/compliance-data-synchronized)                  |
| An agency is moved to a different parent            | Not currently signalled                                                                        |

## Payload Example

A legal name change, the case this event was built for:

```json theme={null}
{
  "webhookType": "DOWNSTREAM_ENTITY_UPDATED",
  "upstreamEntityId": "507f1f77bcf86cd799439010",
  "payload": {
    "downstreamEntityAssociationId": "507f1f77bcf86cd799439011",
    "downstreamEntityId": "507f1f77bcf86cd799439012",
    "branchName": "RT Specialty - Miami Beach, FL",
    "legalName": "RT Specialty LLC",
    "npn": "1234567",
    "ein": "123456789",
    "doingBusinessAs": "RT Miami",
    "producerCode": "03-e55f06b3-618c-4bf2-b578-efae34a87a6e",
    "externalId": "CRM-40912",
    "website": "https://example.com",
    "phoneNumber": "+13055550100",
    "faxNumber": null,
    "legalAddress": {
      "line1": "1000 Collins Ave",
      "city": "Miami Beach",
      "state": "FL",
      "zip": "33139",
      "country": "US"
    },
    "mailingAddress": null,
    "entityType": "LLC",
    "path": "/507f1f77bcf86cd799439009/507f1f77bcf86cd799439011",
    "level": 1,
    "parentAssociationId": "507f1f77bcf86cd799439009",
    "ultimateParentAssociationId": "507f1f77bcf86cd799439009",
    "changedFields": ["legalName"],
    "previousValues": {
      "legalName": "RT Specialty"
    }
  }
}
```

A branch name change on the relationship, with the pre-change value unavailable:

```json theme={null}
{
  "webhookType": "DOWNSTREAM_ENTITY_UPDATED",
  "upstreamEntityId": "507f1f77bcf86cd799439010",
  "payload": {
    "downstreamEntityAssociationId": "507f1f77bcf86cd799439011",
    "downstreamEntityId": "507f1f77bcf86cd799439012",
    "branchName": "RT Specialty - Miami Beach, FL",
    "legalName": "RT Specialty LLC",
    "npn": "1234567",
    "ein": "123456789",
    "doingBusinessAs": "RT Miami",
    "producerCode": "03-e55f06b3-618c-4bf2-b578-efae34a87a6e",
    "externalId": null,
    "website": null,
    "phoneNumber": null,
    "faxNumber": null,
    "legalAddress": null,
    "mailingAddress": null,
    "entityType": "LLC",
    "path": "/507f1f77bcf86cd799439009/507f1f77bcf86cd799439011",
    "level": 1,
    "parentAssociationId": "507f1f77bcf86cd799439009",
    "ultimateParentAssociationId": "507f1f77bcf86cd799439009",
    "changedFields": ["branchName"],
    "previousValues": null
  }
}
```

## Keeping your copy in sync

Match on `downstreamEntityAssociationId`. It is the same identifier carried by [Agency Created](/guides/webhooks/downstream-entity-created) and [Producer Agreement Executed](/guides/webhooks/producer-agreement-executed), so the record you created from one of those events is the record to update from this one.

Do not match on name. That is the failure this event exists to prevent.

The payload carries the **full current record** for this relationship, not just the delta, so a straight overwrite is enough for most integrations. Read `changedFields` when you only care about some fields:

```js theme={null}
if (payload.changedFields.includes('legalName')) {
  // the agency's legal name moved
}
```

Two qualifications on that overwrite. The first matters if you store the agency EIN; the second matters if you rely on arrival order.

### The three identity fields travel as a group

`legalName`, `npn` and `ein` all come from one read of the agency record, so they
share one rule: either **all three are present** — each a string or `null` — or
**all three are absent**.

| What you see                     | What it means                                                                                   |
| -------------------------------- | ----------------------------------------------------------------------------------------------- |
| the key is present with a string | that is the current value                                                                       |
| the key is present and `null`    | the field is genuinely empty (an invited agency has no NPN until it submits one)                |
| all three keys absent            | the agency record could not be read for this delivery; this payload says nothing about identity |

So absent means *unknown*, and `null` means *empty*. If you overwrite wholesale,
skip the identity fields when they are absent rather than writing `null` over
what you already hold — otherwise a transient failure on our side clears a good
EIN on yours. Every other field on the payload is always present.

### One edit can produce more than one delivery

Some fields live on the relationship and some on the agency record, so an edit
touching both produces a delivery for each write, with different `changedFields`.
Every one is correct and every one carries the full current record.

For an agency you hold one relationship with, that is two deliveries. For an
agency you hold several relationships with it is one plus one per relationship,
because the agency-record half fans out (see below).

Apply each delivery idempotently. Do **not** simply let the last one you receive
win — see below.

### Arrival order is not change order

A delivery that fails is retried with exponential backoff, so it can arrive
**after** a delivery describing a newer state. Nothing on the wire lets you order
two deliveries: the payload carries no sequence number, and `X-Turris-Timestamp`
is regenerated on every attempt, so it is the time we sent that attempt and not
the time the change happened.

For most fields this does not matter — the next change re-delivers the current
value. Where it does matter, use `previousValues` as a precondition instead of
applying blindly:

```js theme={null}
const previous = payload.previousValues?.legalName;

// Only accept the change if the value we hold is the one it claims to replace.
if (previous === undefined || previous === stored.legalName) {
  stored.legalName = payload.legalName;
} else {
  // Out-of-order or a change we already applied. Re-read the agency from the
  // API, which is always the source of truth.
}
```

If you need a strict audit trail rather than a current-state mirror, reconcile
against [List Associations](/api-reference/v1/downstream-entity-associations/list-associations)
on a schedule and treat webhooks purely as a signal to re-read.

### A change to the agency record reaches every relationship

If you hold more than one relationship with the same agency, for example under different producer codes, a change to `legalName`, `npn`, or `ein` delivers **once per relationship**. Each delivery carries its own `downstreamEntityAssociationId` and its own hierarchy fields, and they share a `downstreamEntityId`.

Archived relationships are excluded.

## Field Reference

### Payload Fields

| Field                           | Type                          | Description                                                                                                                                                                     |
| ------------------------------- | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `downstreamEntityAssociationId` | string                        | The ID of the association between the agency and your upstream entity. The same identifier used throughout the API and in every other webhook. Match on this.                   |
| `downstreamEntityId`            | string                        | The ID of the agency record itself. Shared by every relationship you hold with that agency.                                                                                     |
| `branchName`                    | string                        | The branch or office name of this association.                                                                                                                                  |
| `legalName`                     | string \| null, may be absent | The agency's legal name. Part of the identity group — see the note below the table.                                                                                             |
| `npn`                           | string \| null, may be absent | The agency's National Producer Number. Part of the identity group.                                                                                                              |
| `ein`                           | string \| null, may be absent | The agency's Employer Identification Number, digits only. Part of the identity group.                                                                                           |
| `doingBusinessAs`               | string \| null                | The trading name for this association.                                                                                                                                          |
| `producerCode`                  | string \| null                | The producer code assigned for this association.                                                                                                                                |
| `externalId`                    | string \| null                | Your own identifier for this association, if you supplied one.                                                                                                                  |
| `website`                       | string \| null                | The agency's website for this association.                                                                                                                                      |
| `phoneNumber`                   | string \| null                | Contact phone number for this association.                                                                                                                                      |
| `faxNumber`                     | string \| null                | Contact fax number for this association.                                                                                                                                        |
| `legalAddress`                  | object \| null                | Legal address: `line1`, `line2`, `city`, `state`, `zip`, `country`.                                                                                                             |
| `mailingAddress`                | object \| null                | Mailing address, same shape as `legalAddress`.                                                                                                                                  |
| `entityType`                    | string \| null                | One of `C-Corp`, `LLC`, `Partnership`, `S-Corp`, `Sole Proprietor`, `Non-profit`, or `null`. A stored value outside that list is reported as `null` rather than passed through. |
| `path`                          | string                        | Materialized ancestor chain, `/rootId/parentId/currentId`. Segments are association ids.                                                                                        |
| `level`                         | number                        | Depth in the hierarchy. `0` is a top-level agency, `1` is its child, and so on.                                                                                                 |
| `parentAssociationId`           | string \| null                | The immediate parent's association id. `null` for a top-level agency.                                                                                                           |
| `ultimateParentAssociationId`   | string                        | The first segment of `path`. A top-level agency is its own ultimate parent.                                                                                                     |
| `changedFields`                 | string\[]                     | Which published fields this change touched. Never empty: a change touching no published field produces no delivery.                                                             |
| `previousValues`                | object \| null                | The prior value of each field named in `changedFields`, and nothing else. `null` when the prior state was not available.                                                        |

<Note>
  `previousValues` is best effort. When the prior state cannot be recovered it is `null` and the event is still delivered, because a change announced without its old value is more useful than no event at all. Do not make it a required input: read the current values, and treat `previousValues` as a convenience for reconciling a record you keyed on the old name.

  When it is present it contains exactly the fields named in `changedFields`, and nothing else. Read it as the state **before** this change:

  * a field **absent** from `previousValues` was not part of this change
  * a field present with a **string** held that value before the change
  * a field present with **`null`** had no value before the change, so this change **populated** it

  A field that was **cleared** therefore shows its old value in `previousValues` and `null` at the top level of the payload — not the other way round.
</Note>

<Note>
  `path` is a snapshot as of this event. Moving an agency to a different parent rewrites it, and that change is not currently signalled by a webhook. If you cache the hierarchy, re-read it from [List Associations](/api-reference/v1/downstream-entity-associations/list-associations) rather than assuming it is stable.
</Note>

<Warning>
  Webhook subscriptions are per event type. Subscribing to Agency Created does **not** deliver Agency Updated —
  register a separate webhook for each event you want to receive.
</Warning>


## Related topics

- [Agency Regulatory Action Updated](/guides/webhooks/downstream-entity-regulatory-action-updated.md)
- [Changelog](/changelog.md)
- [Agency Regulatory Action Added](/guides/webhooks/downstream-entity-regulatory-action-added.md)
