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. For product events from your own code, see the 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:
- In the Stripe dashboard, open Developers, then Webhooks, and add a destination with your per-tenant URL from Mara's settings page.
- 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. - 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:
- In Polar, open your organization settings, then Webhooks, and add an endpoint with your per-tenant URL.
- Select the subscription and order events (or send all).
- 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:
- In the Clerk dashboard, open Webhooks and add an endpoint with your per-tenant URL.
- Subscribe to
user.created,user.updated, anduser.deleted. - 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.