All Docs
FeaturesCalmony PayUpdated March 15, 2026

Fix: payment_intent.created Webhook Now Fires Correctly

Fix: payment_intent.created Webhook Now Fires Correctly

Version: 1.0.90

Overview

Prior to this release, the payment_intent.created webhook event type was advertised as subscribable but never actually emitted. This post explains what was broken, why it matters, and what you need to do (if anything).


Background: Webhook Event Subscriptions

Calmony Pay allows you to register webhook endpoints and filter them by event type. The set of valid event types is defined server-side in the KNOWN_EVENT_TYPES constant. Registering for an unknown type is rejected; registering for a known type is accepted and stored.

As of v1.0.90, the following lifecycle events are emitted for payment intents:

EventFired when
payment_intent.createdA new payment intent resource is created via POST /v1/payment_intents
payment_intent.succeededA payment intent is confirmed and the charge succeeds
payment_intent.failedA payment intent confirmation fails

What Was Broken

payment_intent.created was listed in KNOWN_EVENT_TYPES, so the API accepted subscriptions for it. However, the POST /v1/payment_intents handler never called emitPayEvent with this type. The event was never dispatched — to any subscriber, under any circumstances.

This created a silently broken subscription: no error was returned when registering, but no events were ever delivered. The same gap existed for payment intents created internally by the subscription billing engine.

This is a deviation from the Calmony Pay REST API Contract, which requires webhook events to fire on all resource lifecycle transitions.


What Changed in v1.0.90

  • POST /v1/payment_intents now emits payment_intent.created immediately after the payment intent resource is persisted.
  • Subscription billing (subscription-billing.ts) also emits payment_intent.created for any payment intent it creates internally, ensuring parity between manual and automated payment flows.

No changes were made to payment_intent.succeeded or payment_intent.failed — these were already firing correctly.


Migration Guide

If you were subscribed to payment_intent.created

Your endpoint will now start receiving events. No changes to your webhook registration are required.

Verify your handler can process a payload shaped like:

{
  "type": "payment_intent.created",
  "data": {
    "object": {
      "id": "pi_...",
      "amount": 2500,
      "currency": "gbp",
      "status": "requires_confirmation"
    }
  }
}

If you were working around the missing event

Some integrations may have inferred payment intent creation indirectly — for example, by listening to payment_intent.succeeded and treating it as a proxy for creation. Now that payment_intent.created fires reliably, you can subscribe to it directly for a more accurate signal.

If you were not subscribed to payment_intent.created

No action needed. This fix has no effect on endpoints that do not include payment_intent.created in their event filter.


Affected Files

  • src/app/api/v1/payment_intents/route.ts
  • src/app/api/v1/payment_intents/[id]/confirm/route.ts
  • src/inngest/functions/subscription-billing.ts