Identity API: Webhook Events
The Identity API publishes webhook events when producer identity, contact, financial, or E&O data changes. Use these events to keep downstream systems synchronized without polling.
For instructions on how to register an endpoint, verify delivery, and validate signatures, see the Webhooks Quick Start Guide.
Available Events
| Event Type | When It Fires |
|---|---|
id.producer.updated | A producer identity record (person or firm) is created or updated |
id.producer.deleted | A producer identity record is deleted |
id.producer.address.updated | A single address record is created or updated |
id.producer.address.deleted | A single address record is deleted |
id.producer.addresses.updated | A producer's address set changes — carries the full current set |
id.producer.phone.updated | A single phone record is created or updated |
id.producer.phone.deleted | A single phone record is deleted |
id.producer.phone_numbers.updated | A producer's phone set changes — carries the full current set |
id.producer.bank_account.updated | A bank account record is created or updated |
id.producer.bank_account.deleted | A bank account record is deleted |
id.producer.errors_and_omissions.updated | An E&O policy record is created or updated |
id.producer.errors_and_omissions.deleted | An E&O policy record is deleted |
id.producer.pay_distribution.updated | A producer's pay distribution configuration changes |
id.producer.firm.assigned | An individual producer is associated with a firm |
id.producer.firm.unassigned | An individual producer is removed from a firm |
Event Schema
All Identity API webhook events share the same envelope:
{
"id": "whe_01je7babqteg8v9p30k8zpg3ga",
"type": "id.producer.updated",
"timestamp": "2026-06-30T17:33:00Z",
"data": {}
}
| Field | Type | Description |
|---|---|---|
id | string | Unique identifier for this event. Uses the whe_ prefix. Repeated on retries — use for deduplication. |
type | string | The specific event type (see table above) |
timestamp | string (ISO 8601) | UTC time the event was generated |
data | object | Event-specific payload (see below) |
Field Names: Events vs. REST
Some early events were named independently of the REST API, so a handful of fields differ from their REST equivalents. These divergences are frozen — renaming them would break existing subscribers — and all newer events use the REST field names. Where an event field diverges, map it using this table:
| Resource | REST field | Event field (legacy) | Events affected |
|---|---|---|---|
| Address | id | addressId | id.producer.address.updated / .deleted |
| Address | type | addressType | id.producer.address.updated |
| Phone | id | phoneId | id.producer.phone.updated / .deleted |
| Phone | type | phoneType | id.producer.phone.updated |
| InsurancePolicy | id | policyId | id.producer.errors_and_omissions.updated / .deleted |
| InsurancePolicy | type | policyType | id.producer.errors_and_omissions.updated |
| InsurancePolicy | carrier | providerName | id.producer.errors_and_omissions.updated |
| InsurancePolicy | expiry | expirationDate | id.producer.errors_and_omissions.updated |
| Firm | name | businessName | id.producer.updated |
| Firm | type | businessType | id.producer.updated |
| Firm | email | primaryEmail | id.producer.updated |
| BankAccount | id | bankAccountId | id.producer.bank_account.updated / .deleted |
| BankAccount | name, number, routingNumber, type | bankAccountName, bankAccountNumber, bankAccountRoutingNumber, bankAccountType | id.producer.pay_distribution.updated (embedded bank account) |
| PayDistribution | id | payDistributionId | id.producer.pay_distribution.updated |
Events also carry context fields (producerId, npn) that have no REST-resource equivalent — these identify the owning producer and are not divergences.
Event Payloads
id.producer.updated
Fires when a producer identity record is created or updated. The shape of data differs between individual producers and firms.
| Field | Type | Applies to |
|---|---|---|
id | UUID | Both |
firmId | UUID | Individuals associated with a firm |
npn | String | Both |
type | String | Both (INDIVIDUAL or FIRM) |
firstName, middleName, lastName, suffix | String | Individual only |
preferredFirstName | String | Individual only |
gender | String | Individual only |
dateOfBirth | Date | Individual only |
ssn | String | Individual only |
primaryEmail, secondaryEmail | String | Individual only |
finraCrdNumber | String | Both |
businessName | String | Firm only (REST: name) |
businessType | String | Firm only (REST: type) |
fein | String | Firm only |
createdAt, updatedAt | Date-Time | Both |
Individual example:
{
"id": "whe_01je7babqteg8v9p30k8zpg3ga",
"type": "id.producer.updated",
"data": {
"id": "18de9286-2ad9-4b83-96c7-6d4d63a085b1",
"type": "INDIVIDUAL",
"npn": "444444",
"firstName": "Richard",
"middleName": "Person",
"lastName": "Rogers",
"suffix": "",
"preferredFirstName": "Rich",
"gender": "MALE",
"dateOfBirth": "1987-01-01",
"ssn": "123456788",
"primaryEmail": "richard@example.com",
"secondaryEmail": "",
"finraCrdNumber": "2523523",
"createdAt": "2026-01-15T10:30:00Z",
"updatedAt": "2026-06-30T17:33:00Z"
}
}
Firm example:
{
"id": "whe_01je7babqteg8v9p30k8zpg3ga",
"type": "id.producer.updated",
"data": {
"id": "18de9286-2ad9-4b83-96c7-6d4d63a085b0",
"type": "FIRM",
"npn": "222222",
"businessName": "RDRR LLC",
"businessType": "LLC",
"fein": "123456789",
"primaryEmail": "rdrr@example.com",
"finraCrdNumber": "",
"createdAt": "2026-01-15T10:30:00Z",
"updatedAt": "2026-06-30T17:33:00Z"
}
}
id.producer.deleted
| Field | Type | Description |
|---|---|---|
id | UUID | The producer's record ID |
npn | String | The producer's NPN |
{
"id": "whe_01je7babqteg8v9p30k8zpg3ga",
"type": "id.producer.deleted",
"data": {
"id": "18de9286-2ad9-4b83-96c7-6d4d63a085b0",
"npn": "222222"
}
}
id.producer.address.updated
Fires when a single address record is created or updated.
| Field | Type | Description |
|---|---|---|
producerId | UUID | The producer's record ID |
npn | String | The producer's NPN |
addressId | UUID | Unique identifier for the address record (REST: id) |
addressType | String | Type of address, e.g. MAILING (REST: type) |
addressLine1, addressLine2 | String | Street address |
city, county, state, zip, country | String | Location fields |
moveInDate | Date | Date the producer moved to this address |
preferred | Boolean | Whether this is the preferred address |
updatedAt | Date-Time | When the record was last updated |
{
"id": "whe_01je7babqteg8v9p30k8zpg3ga",
"type": "id.producer.address.updated",
"data": {
"producerId": "be941609-884a-466b-8a87-2f158d79ebec",
"npn": "1234",
"addressId": "5025c204-5c07-47c6-b9d3-11ad09c35f43",
"addressType": "MAILING",
"addressLine1": "123 Easy Street",
"addressLine2": "Suite 500",
"city": "Athens",
"county": "Clarke",
"state": "GA",
"zip": "30606",
"country": "USA",
"moveInDate": "2026-05-02",
"preferred": true,
"updatedAt": "2026-06-05T00:03:37Z"
}
}
id.producer.address.deleted
| Field | Type | Description |
|---|---|---|
producerId | UUID | The producer's record ID |
npn | String | The producer's NPN |
addressId | UUID | Unique identifier for the deleted address |
id.producer.addresses.updated
Fires when a producer's address set changes and carries the full current set of addresses, so you can replace your stored state without follow-up calls. producerId may be a person or firm ID.
| Field | Type | Description |
|---|---|---|
producerId | UUID | The producer's record ID (person or firm) |
npn | String | The producer's NPN |
addresses | Array | The producer's current addresses — each with id, type, addressLine1, addressLine2, city, state, zip, county, country, moveInDate, preferred |
updatedAt | Date-Time | When this snapshot was generated |
id.producer.phone.updated
| Field | Type | Description |
|---|---|---|
producerId | UUID | The producer's record ID |
npn | String | The producer's NPN |
phoneId | UUID | Unique identifier for the phone record (REST: id) |
number | String | The phone number |
phoneType | String | Type of phone number, e.g. CELL (REST: type) |
preferred | Boolean | Whether this is the preferred phone number |
updatedAt | Date-Time | When the record was last updated |
id.producer.phone.deleted
| Field | Type | Description |
|---|---|---|
producerId | UUID | The producer's record ID |
npn | String | The producer's NPN |
phoneId | UUID | Unique identifier for the deleted phone record |
id.producer.phone_numbers.updated
Fires when a producer's phone set changes and carries the full current set of phone numbers. producerId may be a person or firm ID.
| Field | Type | Description |
|---|---|---|
producerId | UUID | The producer's record ID (person or firm) |
npn | String | The producer's NPN |
phoneNumbers | Array | The producer's current phones — each with id, number, extension, type, preferred |
updatedAt | Date-Time | When this snapshot was generated |
id.producer.bank_account.updated
Fires when a bank account record is created or updated.
| Field | Type | Description |
|---|---|---|
producerId | UUID | The producer's record ID |
npn | String | The producer's NPN |
bankAccountId | UUID | Unique identifier for the bank account record (REST: id) |
type | String | Account type (e.g. CHECKING) |
number | String | The bank account number |
routingNumber | String | Bank routing number |
name | String | Display label for the bank account |
primaryAccount | Boolean | Whether this is the producer's primary account |
payDistributions | Array | Pay distribution configurations associated with the producer, if any |
updatedAt | Date-Time | When the record was last updated |
Handle with care: this payload contains bank account and routing numbers. Do not write it to general-purpose logs, and store it only in systems approved for financial data.
{
"id": "whe_01je7babqteg8v9p30k8zpg3ga",
"type": "id.producer.bank_account.updated",
"data": {
"producerId": "00283595-fc7b-4999-80ab-fb4a70c21b04",
"npn": "1234",
"bankAccountId": "5025c204-5c07-47c6-b9d3-11ad09c35f43",
"type": "CHECKING",
"number": "1234567890",
"routingNumber": "123456789",
"name": "Wells Fargo",
"primaryAccount": true,
"updatedAt": "2026-06-05T00:03:37Z"
}
}
id.producer.bank_account.deleted
| Field | Type | Description |
|---|---|---|
producerId | UUID | The producer's record ID |
npn | String | The producer's NPN |
bankAccountId | UUID | Unique identifier for the deleted bank account |
id.producer.errors_and_omissions.updated
Fires when an errors and omissions (E&O) policy record is created or updated.
| Field | Type | Description |
|---|---|---|
producerId | UUID | The producer's record ID |
npn | String | The producer's NPN |
policyId | UUID | Unique identifier for the E&O policy (REST: id) |
policyType | String | Type of policy, e.g. INDIVIDUAL (REST: type) |
policyNumber | String | Policy number |
carrier | String | Name of the E&O insurance provider |
providerName | String | Legacy duplicate of carrier — prefer carrier |
totalLimit | Decimal | Total coverage limit |
effectiveDate | Date | When the policy became effective |
expirationDate | Date | When the policy expires (REST: expiry) |
certificateNumber | String | Certificate number |
hasFile | Boolean | Whether a certificate document is uploaded for this policy |
updatedAt | Date-Time | When the record was last updated |
{
"id": "whe_01je7babqteg8v9p30k8zpg3ga",
"type": "id.producer.errors_and_omissions.updated",
"data": {
"producerId": "fcd7c256-2cdc-43ad-b4ce-6c52c0e1cf20",
"npn": "2523523",
"policyId": "c2e7c7ac-c994-4989-a703-7eec29a9038b",
"policyType": "INDIVIDUAL",
"policyNumber": "EO-458812",
"carrier": "EZLandC",
"providerName": "EZLandC",
"totalLimit": 1000000,
"effectiveDate": "2026-01-04",
"expirationDate": "2027-01-04",
"certificateNumber": "4524524",
"hasFile": true,
"updatedAt": "2026-06-05T00:03:37Z"
}
}
id.producer.errors_and_omissions.deleted
| Field | Type | Description |
|---|---|---|
producerId | UUID | The producer's record ID |
npn | String | The producer's NPN |
policyId | UUID | Unique identifier for the deleted E&O policy |
id.producer.pay_distribution.updated
Fires when a producer's pay distribution configuration changes. Each distribution splits commission payments across one or more bank accounts.
| Field | Type | Description |
|---|---|---|
payDistributionId | String | Unique identifier for the pay distribution (REST: id) |
producerId | UUID | The producer's record ID |
producerType | String | person or firm |
effectiveFrom | Date | Start of the distribution's effective window (inclusive) |
effectiveUntil | Date | End of the effective window (exclusive) |
details | Array | Distribution splits — each with id, bankAccountId, bankAccountName, bankAccountNumber, bankAccountRoutingNumber, bankAccountType, primaryAccount, percentage, amount, priority, remainder |
Handle with care: the embedded bank account details include account and routing numbers.
id.producer.firm.assigned
Fires when an individual producer is associated with a firm.
| Field | Type | Description |
|---|---|---|
producerId | UUID | The individual producer's record ID |
producerNpn | String | The individual producer's NPN |
firmId | UUID | The firm the producer was assigned to |
firmNpn | String | The firm's NPN |
id.producer.firm.unassigned
Fires when an individual producer is removed from a firm. Carries the same payload shape as id.producer.firm.assigned.
Subscribing to Events
When registering your endpoint in the webhook portal, subscribe to the id high-level event group to receive all Identity API events, or subscribe to specific event types if you only need a subset.
See the Webhooks Quick Start Guide for step-by-step registration instructions.
Processing Recommendations
- Use
idfor deduplication — if an event is retried, the envelopeidstays the same. Store processed event IDs to avoid duplicate processing. - Respond quickly — your endpoint must return
2xxwithin 5 seconds. Offload heavy processing to a queue or background job. - Validate signatures — verify the
webhook-signatureheader against your signing secret before processing. - Restrict logging of payloads — bank account and identity events carry sensitive data; log the envelope (
id,type,timestamp) rather than the fulldataobject. - Use
updatedAtfor ordering — if you receive multiple events for the same resource in quick succession, usedata.updatedAtto determine the most recent state. - Reconcile with REST — webhook delivery is at-least-once, not guaranteed-ordered. Periodically reconcile against
GET /v2/personsandGET /v2/bank-accountswithupdated_sinceas a safety net.