Webhooks
The external webhooks HermesAI expects in production and what each one updates.
HermesAI currently depends on two external webhooks in production. Both are signed and validated server-side before any state mutation.
Production prerequisite
The deployed environment must contain both webhook secrets. Failures should never be quietly masked as auth or availability issues — surface them.
Endpoint
POST /api/billing/webhooks/polarRequired environment variable
POLAR_WEBHOOK_SECRETEvents handled
subscription.createdsubscription.updatedsubscription.activesubscription.canceledsubscription.uncanceledsubscription.revokedorder.createdorder.updatedorder.paidorder.refunded
What it updates
- Tenant subscription plan
- Tenant subscription status
- Billing invoice records
Endpoint
POST /api/webhooks/clerkRequired environment variable
CLERK_WEBHOOK_SIGNING_SECRETEvents handled
user.createduser.updateduser.deletedorganization.createdorganization.updatedorganization.deletedorganizationMembership.createdorganizationMembership.updatedorganizationMembership.deleted
What it updates
- Clerk user snapshots
- Organization snapshots
- Tenant membership snapshots
Verification checklist
Confirm both secrets are wired
Both POLAR_WEBHOOK_SECRET and CLERK_WEBHOOK_SIGNING_SECRET must be present in the deployed environment.
Polar deliveries return 200
Inspect the Polar dashboard's webhook delivery log. Repeated 4xx or 5xx responses indicate signature mismatch or runtime failure.
Clerk deliveries return 200
Inspect Clerk's webhook log. The signing secret must match exactly — re-roll if there's any doubt.
Failures surface, not hide
Both routes use signature verification + idempotency keys. Failed processing should be visible in billing_webhook_events / clerk_webhook_events audit tables, not swallowed.