# Webhooks: Stripe, Polar, Clerk

Billing and auth events reach Mara through the webhooks you already have. Each connector gets a per-tenant URL, verifies the provider's signature, and dedupes on the provider's event id, so redeliveries are safe. Setup is two pasted values: Mara's URL into the provider, the provider's signing secret into Mara.

Your per-tenant URLs and the secret fields live in Settings under Integrations. The raw markdown version of this page is at [hiremara.com/docs/webhooks.md](https://hiremara.com/docs/webhooks.md). For product events from your own code, see the [Events API](/docs/events-api).

## What journeys can trigger on

Provider events are normalized into eight lifecycle moments. Journeys trigger on these, not on raw provider payloads:

| Mara event type         | Meaning                                          |
| ----------------------- | ------------------------------------------------ |
| `subscription-started`  | A new subscription begins.                       |
| `trial-converted`       | A trial becomes a paying subscription.           |
| `subscription-upgraded` | Plan or quantity changed upward.                 |
| `subscription-canceled` | Subscription canceled or revoked.                |
| `payment-failed`        | A renewal payment failed (dunning territory).    |
| `payment-recovered`     | A previously failing payment went through.       |
| `refund-issued`         | A charge was refunded.                           |
| `purchase`              | A one-time purchase, not tied to a subscription. |

Anything else the provider sends returns `200` with `"status": "ignored"`. It is fine, and simplest, to send everything.

Custom fields you attach as provider metadata (Stripe subscription or checkout metadata, Polar order or customer metadata, Clerk public metadata) are projected onto the contact as attributes, with the same sanitization as the Events API: flat scalars only, secret-looking keys dropped, capped at 50 keys.

## Stripe

Endpoint:

```
POST https://hiremara.com/api/webhooks/stripe/{tenantId}
```

Setup:

1. In the Stripe dashboard, open Developers, then Webhooks, and add a destination with your per-tenant URL from Mara's settings page.
2. Select these events (or send all): `customer.subscription.created`, `customer.subscription.updated`, `customer.subscription.deleted`, `invoice.payment_failed`, `invoice.payment_succeeded`, `charge.refunded`, `checkout.session.completed`.
3. Copy the signing secret (`whsec_...`) and paste it into Settings, Integrations, Billing, Stripe.

How Stripe events map:

| Stripe event                    | Becomes                                                                                                                           |
| ------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| `customer.subscription.created` | `subscription-started`                                                                                                            |
| `customer.subscription.updated` | `trial-converted` when status goes trialing to active; `subscription-upgraded` when the plan or items changed; otherwise ignored. |
| `customer.subscription.deleted` | `subscription-canceled`                                                                                                           |
| `invoice.payment_failed`        | `payment-failed`                                                                                                                  |
| `invoice.payment_succeeded`     | `payment-recovered`, only when it recovers a failing invoice. First-attempt successes are ignored.                                |
| `charge.refunded`               | `refund-issued`                                                                                                                   |
| `checkout.session.completed`    | `purchase`, only for `mode=payment` (one-time). Subscription checkouts are already covered above.                                 |

Requests are verified with the `stripe-signature` header against your pasted secret. Wrong or missing signature returns 401; a tenant with no secret configured returns 412.

## Polar

Endpoint:

```
POST https://hiremara.com/api/webhooks/polar/{tenantId}
```

Setup:

1. In Polar, open your organization settings, then Webhooks, and add an endpoint with your per-tenant URL.
2. Select the subscription and order events (or send all).
3. Copy the signing secret and paste it into Settings, Integrations, Billing, Polar.

How Polar events map:

| Polar event                                     | Becomes                                                                             |
| ----------------------------------------------- | ----------------------------------------------------------------------------------- |
| `subscription.created`                          | `subscription-started`                                                              |
| `subscription.active`                           | `trial-converted`                                                                   |
| `subscription.upgraded`                         | `subscription-upgraded`                                                             |
| `subscription.canceled`, `subscription.revoked` | `subscription-canceled`                                                             |
| `subscription.past_due`                         | `payment-failed`                                                                    |
| `subscription.recovered`                        | `payment-recovered`                                                                 |
| `order.refunded`                                | `refund-issued`                                                                     |
| `order.paid`                                    | `purchase`, only for orders not tied to a subscription. Renewal cycles are ignored. |

Signatures follow the Standard Webhooks spec (`webhook-id`, `webhook-timestamp`, `webhook-signature` headers).

## Clerk

Endpoint:

```
POST https://hiremara.com/api/webhooks/clerk/{tenantId}
```

Setup:

1. In the Clerk dashboard, open Webhooks and add an endpoint with your per-tenant URL.
2. Subscribe to `user.created`, `user.updated`, and `user.deleted`.
3. Copy the Svix signing secret and paste it into Settings, Integrations, Clerk.

What each event does: `user.created` creates the contact and records a `user.created` event, which can fire your welcome journey (map it as the signup event on the settings row). `user.updated` refreshes the contact's email and name. `user.deleted` records a deactivation signal. Mara projects the email, username, avatar URL, and public metadata; private and unsafe metadata are never read.

Optional backfill: paste a Clerk Backend API key on the same settings row and Mara imports your existing users as contacts, so journeys do not start from an empty list.

## Verify it is flowing

After setup, trigger a test event (most providers have a "send test event" button) and check the ingestion health strip in Settings, Integrations: it shows per-connector contact counts and last activity. Or ask Mara in chat.
