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

# Webhooks overview

> Receive real-time notifications when events occur across Verify, Monitor, and Comply.

export const iconProps = (variant = "default") => {
  const iconVariants = {
    default: "palm-icon-default",
    horizontal: "palm-icon-horizontal",
    stack: "palm-icon-stack",
    navigation: "palm-icon-navigation",
    darkHorizontal: "palm-icon-dark-horizontal",
    dark_stack: "palm-icon-dark-stack",
    getStarted: "palm-icon-get-started"
  };
  return iconVariants[variant] ?? iconVariants.default;
};

export const PalmCard = ({title, description, icon, variant = "default", href, items}) => {
  if (variant === "getStarted") {
    return <div data-card className="pc-wrapper-get-started flex flex-col gap-4 border border-[rgba(4,44,47,0.1)] rounded-2xl p-6">
        <div className="pc-wrapper-inner-get-started">
          {icon !== undefined && <div className="pc-icon-container-get-started">{icon}</div>}
          {title !== undefined && <span className="pc-title-get-started">{title}</span>}
        </div>
        {items && items.length > 0 && <ul className="pc-items-get-started">
            {items.map((item, i) => <li key={i}>
                <a href={item.href} className="pc-item-link-get-started">{item.label}</a>
              </li>)}
          </ul>}
      </div>;
  }
  const variants = {
    default: {
      wrapper: "pc-wrapper-default",
      title: "pc-title",
      description: "pc-description"
    },
    horizontal: {
      wrapper: "pc-wrapper-card",
      title: "pc-title-horizontal",
      description: "pc-description"
    },
    stack: {
      wrapper: "pc-wrapper-stack",
      title: "pc-title-stack",
      description: "pc-description"
    },
    darkHorizontal: {
      wrapper: "pc-wrapper-dark-horizontal",
      title: "pc-title-dark-horizontal",
      description: "pc-description-dark-horizontal"
    },
    navigation: {
      wrapper: "pc-wrapper-navigation",
      title: "pc-title-navigation",
      description: "pc-description-navigation"
    },
    dark_stack: {
      icon: "pc-icon-card",
      title: "pc-title",
      description: "pc-description"
    }
  };
  const styles = variants[variant] ?? variants.default;
  const inner = <a data-card href={href ? href : '#'} className={`no-underline flex flex-col h-full items-start gap-4 p-6 rounded-2xl hover:opacity-80 transition-opacity ${styles.wrapper}`}>
      {icon !== undefined && <span className="icon-wrapper">{icon}</span>}
      {(title !== undefined || description !== undefined) && <div className="flex flex-col min-w-0">
          {title !== undefined && <span className={styles.title}>{title}</span>}
          {description !== undefined && <span className={styles.description}>{description}</span>}
        </div>}
    </a>;
  return inner;
};

Instead of polling the API for changes, register an endpoint and Palm pushes events to you. Webhooks deliver events from all Palm products through a single integration — verification results, monitoring alerts, and compliance updates all arrive at the same endpoint.

<div className="semitransparent-image-wrapper">
  <img src="https://mintcdn.com/palmfinance/1RPIbiD5PV2g0B_e/images/WebhooksOverviewEyeCatch.webp?fit=max&auto=format&n=1RPIbiD5PV2g0B_e&q=85&s=96656828002f75a3473a0d16c718ef2d" alt="Image showcasing a history page with information about webhooks." style={{maxWidth: '1117px', width: '100%', margin: '0' }} width="2234" height="928" data-path="images/WebhooksOverviewEyeCatch.webp" />
</div>

***

## Setting up a webhook

When you create a webhook in Palm Console, you specify:

* **URL** — The HTTPS endpoint that will receive events. HTTP is not supported.
* **Events** — The event types you want to subscribe to.

Palm generates a signing secret (format: `whsec_...`) at creation time. This secret is returned once — store it securely. You'll need it to verify that incoming requests are from Palm.

## Event format

All events follow a consistent naming pattern:

```
{resource}.{action}
{resource}.{sub_resource}.{action}
```

Every event payload contains:

| Field                                                       | Description                                                                                                                  |
| ----------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| <span className="initial-bold--success">`id`</span>         | Unique event identifier. Use for idempotency.                                                                                |
| <span className="initial-bold--success">`object`</span>     | Always `event`.                                                                                                              |
| <span className="initial-bold--success">`type`</span>       | The event type (e.g., `user.verification.completed`).                                                                        |
| <span className="initial-bold--success">`mode`</span>       | `test` or `live` — the mode of the action that produced the event. An event is delivered only to endpoints of the same mode. |
| <span className="initial-bold--success">`created_at`</span> | ISO 8601 timestamp.                                                                                                          |
| <span className="initial-bold--success">`data`</span>       | Event-specific payload. Structure depends on event type.                                                                     |

## Event catalog

<Note>
  **A note on naming:** Webhook event types use `user` (e.g., `user.verification.completed`); elsewhere the docs may refer to a "person." These are the same entity — the event names reflect the API resource name.
</Note>

### Verification events

Fired when verification processing completes. Payloads include the verification ID, risk level, match results, and — for business verification — associate results.

| Event                                                                            | Description                                                       |
| -------------------------------------------------------------------------------- | ----------------------------------------------------------------- |
| <span className="initial-bold--success">`user.verification.completed`</span>     | User verification finished.                                       |
| <span className="initial-bold--success">`business.verification.completed`</span> | Business verification finished. Includes associate-level results. |

### Monitoring events

Fired when Palm detects a change in a monitored business's authoritative record. These events only fire for businesses enrolled in [Monitor](/monitor/overview).

| Event                                                                          | Description                                                                                                                       |
| ------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------- |
| <span className="initial-bold--success">`business.registration.updated`</span> | Registration data changed (status, name, address, officers, filings). Includes structured diffs with previous and current values. |
| <span className="initial-bold--success">`business.filing.due`</span>           | A compliance filing deadline is approaching.                                                                                      |
| <span className="initial-bold--success">`business.filing.overdue`</span>       | A compliance filing deadline has passed.                                                                                          |

### Filing events

Fired when a [Comply](/comply/overview) filing changes status. These events cover formations, EIN applications, and other filing types.

| Event                                                                 | Description                                                                                                  |
| --------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
| <span className="initial-bold--success">`filing.queued`</span>        | Filing received and validated. Preparing for submission.                                                     |
| <span className="initial-bold--success">`filing.ready_to_file`</span> | Filing is ready to be processed.                                                                             |
| <span className="initial-bold--success">`filing.processing`</span>    | Filing is being prepared for submission to the authority.                                                    |
| <span className="initial-bold--success">`filing.filed`</span>         | Filing has been submitted and is being processed.                                                            |
| <span className="initial-bold--success">`filing.completed`</span>     | Filing is done as the authority accepted the filing. Result available (registration number, EIN, documents). |
| <span className="initial-bold--success">`filing.canceled`</span>      | Filing was canceled. Includes `status_reason`.                                                               |

**Routing by filing type.** Every filing event payload includes `data.object.type`:

| `data.object.type`                                         | Filing                       |
| ---------------------------------------------------------- | ---------------------------- |
| <span className="initial-bold--success">`formation`</span> | LLC or corporation formation |
| <span className="initial-bold--success">`ein`</span>       | EIN application              |

<Note>
  Registered agent is **not** a filing. It is a standalone resource with its own status lifecycle and its own `registered_agent.*` events — see [Registered agent events](#registered-agent-events). On a formation it appears in the `related_items` bundle as a `registered_agent` item, never as a filing.
</Note>

### Case events

Fired when Palm opens or updates a case requesting information to complete a filing. See [Cases](/comply/cases).

| Event                                                          | Description                                                                                    |
| -------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
| <span className="initial-bold--success">`case.opened`</span>   | Palm opened a case and needs your response.                                                    |
| <span className="initial-bold--success">`case.updated`</span>  | An open case changed — for example, your response was received and it moved to `under_review`. |
| <span className="initial-bold--success">`case.resolved`</span> | The case closed (`resolved` or `superseded`).                                                  |

### Platform events

Fired when entities are created or removed through the API.

| Event                                                             | Description             |
| ----------------------------------------------------------------- | ----------------------- |
| <span className="initial-bold--success">`user.created`</span>     | A person was created.   |
| <span className="initial-bold--success">`user.removed`</span>     | A person was removed.   |
| <span className="initial-bold--success">`business.created`</span> | A business was created. |
| <span className="initial-bold--success">`business.removed`</span> | A business was removed. |

### Document events

Fired when Palm attaches a document to one of your resources on its own initiative — a filing artifact or forwarded registered-agent mail. Does not fire for documents you upload yourself.

| Event                                                             | Description                                                                                                                                                                    |
| ----------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| <span className="initial-bold--success">`document.created`</span> | Palm attached a new document to one of your businesses. `data.object` is the document; route on its `type` (e.g., `certificate_of_formation`, `ein_letter`, `notice`, `mail`). |

### Registered agent events

Registered agent is a standalone resource, not a filing. It carries the registered-agent record on `data.object` and moves through its own status lifecycle (`pending` → `active` → `termination_requested` → `terminated`, plus `failed`). It never emits `filing.*` events.

| Event                                                                                   | Description                                                                                                                                           |
| --------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| <span className="initial-bold--success">`registered_agent.activated`</span>             | Palm became the registered agent for a business (formation provisioning completed, or a change into Palm). Status is `active`.                        |
| <span className="initial-bold--success">`registered_agent.failed`</span>                | Provisioning (or a required state submission) failed on the assignment path; status moved to `failed`. `data.object.rejection_reason` explains why.   |
| <span className="initial-bold--success">`registered_agent.changed`</span>               | The registered agent moved to another provider; status is `terminated`, `provider` is `external`.                                                     |
| <span className="initial-bold--success">`registered_agent.change_failed`</span>         | A partner-requested change could not be completed; status reverts to `active` (Palm remains the RA). `data.object.rejection_reason` explains why.     |
| <span className="initial-bold--success">`registered_agent.termination_requested`</span> | You requested that Palm stop serving as the registered agent; status moved to `termination_requested`. Palm keeps forwarding mail until it completes. |
| <span className="initial-bold--success">`registered_agent.terminated`</span>            | Palm is no longer the registered agent on file; status moved to `terminated`.                                                                         |
| <span className="initial-bold--success">`registered_agent.termination_failed`</span>    | A termination could not be completed; status reverts to `active`. `data.object.rejection_reason` explains why.                                        |

## Example payloads

Every event type has a complete, realistic example payload — including each variant (formation vs. EIN filings, each registered-agent state, `case.resolved`, `*.removed`, `business.filing.overdue`) — in the dedicated [Webhook example payloads](/developer-guide/webhook-example-payloads) reference.

## Verifying signatures

All webhook payloads are signed using HMAC-SHA256. Always verify signatures before processing events.

Palm sends three headers with every delivery:

| Header                                                           | Description                               |
| ---------------------------------------------------------------- | ----------------------------------------- |
| <span className="initial-bold--success">`Palm-Signature`</span>  | Format: `t={timestamp},v1={signature}`.   |
| <span className="initial-bold--success">`Palm-Webhook-Id`</span> | The webhook endpoint receiving the event. |
| <span className="initial-bold--success">`Palm-Event-Type`</span> | The event type being delivered.           |

To verify:

1. Extract the timestamp (`t`) and signature (`v1`) from the `Palm-Signature` header.
2. Check the timestamp is within 5 minutes of current time. Reject stale timestamps to prevent replay attacks.
3. Construct the signed payload: `{timestamp}.{raw_request_body}`.
4. Compute HMAC-SHA256 using your webhook secret (`whsec_...`).
5. Compare your computed signature with the `v1` value using constant-time comparison.

<Warning>
  Do not skip signature verification, even in development. Unsigned requests could come from anywhere.
</Warning>

## Retries and delivery

**Timeout** — Your endpoint must respond within 10 seconds. Return a 2xx immediately, then process the event asynchronously.

**Retry schedule** — If your endpoint returns a non-2xx status or times out, Palm retries:

| Attempt   | Delay      |
| --------- | ---------- |
| 1st retry | 1 minute   |
| 2nd retry | 5 minutes  |
| 3rd retry | 30 minutes |
| 4th retry | 2 hours    |

After 5 total attempts (1 original + 4 retries), Palm marks the delivery as `failed`.

**Auto-disable** — If a webhook accumulates 10 consecutive failed deliveries across any events, Palm automatically disables it. Check webhook execution logs in Palm Console to monitor delivery health.

## Idempotency

Palm may deliver events more than once. Use the event `id` field to deduplicate. If your processing is not naturally idempotent, store processed event IDs and skip duplicates.

## Best practices

* **Respond fast, process later.** Return a 2xx immediately and handle the event asynchronously. Heavy processing that exceeds the 10-second timeout will trigger retries and eventually disable your webhook.
* **Always verify signatures.** Validate the `Palm-Signature` header on every request. This is your only guarantee the event came from Palm.
* **Deduplicate with event IDs.** Network issues can cause duplicate deliveries. Store the `id` from each processed event to avoid processing it twice.
* **Subscribe selectively.** Only subscribe to events you act on. If you don't need `user.created` events, don't subscribe — it reduces noise and load on your endpoint.
* **Monitor delivery health.** Check webhook execution logs in Palm Console regularly. A pattern of failures usually means your endpoint is slow or returning errors.

## Next steps

<div className="grid lg:grid-cols-2 gap-6 mt-6">
  <PalmCard variant="navigation" title="Comply overview" description="Filings, registered agent services, and reinstatement." icon={<Icon className={iconProps("navigation")} icon="arrow-right" />} href="/comply/overview" />

  <PalmCard variant="navigation" title="Monitor overview" description="Track changes to verified businesses in real time." icon={<Icon className={iconProps("navigation")} icon="arrow-right" />} href="/monitor/overview" />

  <PalmCard variant="navigation" title="Verify a business" description="Confirm a business entity exists and is in good standing." icon={<Icon className={iconProps("navigation")} icon="arrow-right" />} href="/verify/verify-a-business" />

  <PalmCard variant="navigation" title="Verify a person" description="Identity checks, synthetic identity detection, and watchlist screening." icon={<Icon className={iconProps("navigation")} icon="arrow-right" />} href="/verify/verify-a-person" />

  <PalmCard variant="navigation" title="API Reference" description="Endpoint reference for all Palm APIs." icon={<Icon className={iconProps("navigation")} icon="arrow-right" />} href="/api-reference/introduction" />
</div>
