AI Engagement Photos Docs

Webhooks

How Creem webhooks are processed.

Endpoint

POST /api/payments/creem/webhook

Security

Signature Verification

Every webhook is verified using HMAC-SHA256:

const isValid = verifyCreemWebhookSignature(body, signature, CREEM_TEST_WEBHOOK_SECRET);

The signature is in the creem-signature header. Timing-safe comparison is used to prevent timing attacks.

Idempotency

Credit-granting webhooks are handled by checking providerPaymentId and the credit ledger in one transaction. If a succeeded payment is delivered again, the webhook is acknowledged without another credit grant. Refund and dispute events only update the existing payment status; they never create a negative credit ledger entry or claw back consumed credits.

Supported Events

EventAction
checkout.completedCreate payment, grant credits, send email
subscription.activeMark the subscription active and restore the plan entitlement
subscription.trialingStore the trialing subscription state and plan entitlement
subscription.paidGrant monthly credits, update subscription
subscription.updateStore the provider subscription status and period end
subscription.scheduled_cancelStop future scheduled grants while retaining access until cancellation
subscription.canceledMark canceled, stop scheduled grants, and clear the plan entitlement
subscription.unpaidMark unpaid, stop scheduled grants, and clear the plan entitlement
subscription.past_dueMark past due, stop scheduled grants, and clear the plan entitlement
subscription.expiredMark expired, stop scheduled grants, and clear the plan entitlement
subscription.pausedMark paused, stop scheduled grants, and clear the plan entitlement
refund.createdUpdate the matching payment status without changing credits
dispute.createdMark the matching payment as disputed without changing credits

The dashboard's currently available event strings are the exact strings above. There is no separate payment.failed event in this Creem webhook list; failed subscription payments are represented by subscription.unpaid or subscription.past_due.

Setup

In your Creem Dashboard, set the webhook URL to:

https://your-domain.com/api/payments/creem/webhook

For Test Mode, configure PAYMENT_PROVIDER="creem", CREEM_ENVIRONMENT="test", and the test webhook secret in the Preview environment:

PAYMENT_PROVIDER="creem"
CREEM_ENVIRONMENT="test"
CREEM_TEST_WEBHOOK_SECRET="whsec_your_test_secret"

The Preview deployment must use a separate Neon branch or other non-Production DATABASE_URL, and BILLING_DATA_ENVIRONMENT="preview". Test webhooks are rejected when the data environment is Production.

Debugging

If webhooks aren't working:

  1. Check Creem Dashboard webhook logs for delivery status
  2. Verify CREEM_TEST_WEBHOOK_SECRET matches the Creem Test webhook settings
  3. Ensure the endpoint is publicly accessible (not behind auth)
  4. Check server logs for signature verification errors

On this page