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 | Common Use Cases |
|---|---|---|
id.producer.updated | A producer identity record (person or firm) is created or updated | Keep producer master data in sync — names, NPN, demographics |
id.producer.deleted | A producer identity record is deleted | Remove the producer from downstream stores; reconcile deletions |
id.producer.address.updated | A single address record is created or updated | Update a single stored address record |
id.producer.address.deleted | A single address record is deleted | Remove a single stored address record |
id.producer.addresses.updated | A producer's address set changes — carries the full current set | Replace your whole stored address set in one write, with no follow-up calls |
id.producer.phone.updated | A single phone record is created or updated | Update a single stored phone record |
id.producer.phone.deleted | A single phone record is deleted | Remove a single stored phone record |
id.producer.phone_numbers.updated | A producer's phone set changes — carries the full current set | Replace your whole stored phone set in one write, with no follow-up calls |
id.producer.bank_account.updated | A bank account record is created or updated | Keep payment details current ahead of a commission run |
id.producer.bank_account.deleted | A bank account record is deleted | Stop routing payments to a removed account |
id.producer.errors_and_omissions.updated | An E&O policy record is created or updated | Track E&O coverage and expiry; gate appointments on active coverage |
id.producer.errors_and_omissions.deleted | An E&O policy record is deleted | Drop the policy from your coverage records; re-check whether any active coverage remains |
id.producer.pay_distribution.updated | A producer's pay distribution configuration changes | Update commission payout splits before the next pay cycle |
id.producer.firm.assigned | An individual producer is associated with a firm | Update firm rosters; apply firm-level entitlements |
id.producer.firm.unassigned | An individual producer is removed from a firm | Remove firm-level access and roster membership |
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.