All Docs
FeaturesCalmony PayUpdated March 15, 2026

Fixing the Silent confirm: true Bug in Payment Intent Creation

Fixing the Silent confirm: true Bug in Payment Intent Creation

Release: v1.0.100


Background

Calmony Pay's SDK is designed to be familiar to developers who have used Stripe. As part of that design, the original CreatePaymentIntentParams TypeScript interface included two Stripe-compatible fields:

confirm?: boolean
return_url?: string

In Stripe's API, passing confirm: true when creating a payment intent triggers automatic confirmation in a single request — the intent is created and immediately charged without a separate confirm call.

The Problem

While these fields were present in the SDK's TypeScript interface, the Calmony Pay server (POST /v1/payment_intents) did not implement the corresponding logic. The createPaymentIntentSchema on the server silently discarded both fields.

The result: a caller passing confirm: true would receive a 200 OK response and a valid payment intent object — but the intent would be in requires_confirmation status, not confirmed. No error was raised. No warning was returned. The flag was simply ignored.

This is a particularly dangerous class of bug. The SDK's type signature advertised a capability the server did not provide, and the failure mode was invisible at call time.

Example of affected code

// Before v1.0.100 — this looked valid but confirm was silently ignored
const intent = await calmonyPay.createPaymentIntent({
  amount: 4999,
  currency: 'gbp',
  confirm: true,           // ⚠️ silently stripped by server
  return_url: 'https://example.com/complete',  // ⚠️ silently stripped
});

// intent.status === 'requires_confirmation'
// — NOT confirmed, despite confirm: true being passed

The Fix

Rather than implement partial Stripe-compatibility that could mask further edge cases, the confirm and return_url fields have been removed from CreatePaymentIntentParams. The SDK interface now precisely matches what the server accepts and processes.

This is a deliberate contract-first correction: the SDK's type surface is the source of truth for what the API supports. Removing these fields makes the mismatch a compile-time error for any integration relying on them, rather than a silent runtime failure.

// After v1.0.100 — CreatePaymentIntentParams no longer includes confirm or return_url
const intent = await calmonyPay.createPaymentIntent({
  amount: 4999,
  currency: 'gbp',
  // confirm and return_url are not valid fields — TypeScript will surface this
});

// To confirm, use the dedicated confirm endpoint:
await calmonyPay.confirmPaymentIntent(intent.id);

Migration Guide

If your integration passed confirm: true or return_url during intent creation, update your code as follows:

Before

const intent = await calmonyPay.createPaymentIntent({
  amount: 4999,
  currency: 'gbp',
  confirm: true,
  return_url: 'https://example.com/complete',
});

After

// Step 1: Create the intent
const intent = await calmonyPay.createPaymentIntent({
  amount: 4999,
  currency: 'gbp',
});

// Step 2: Confirm it explicitly
const confirmed = await calmonyPay.confirmPaymentIntent(intent.id);

The two-step flow gives you the same result — a confirmed, charged intent — with explicit control at each stage.

Affected Files

FileChange
src/lib/calmony-pay/client.tsRemoved confirm and return_url from CreatePaymentIntentParams
src/app/api/v1/payment_intents/route.tsNo functional change; server already did not process these fields

Why This Matters

Silent parameter stripping is one of the hardest categories of API bug to detect in production. An integration test that checks for a 200 OK would pass; only a test asserting on the returned status field would catch it. By aligning the SDK interface with actual server behaviour, integrations that relied on confirm: true will now fail loudly at the TypeScript compilation stage rather than silently at runtime.