All Docs
FeaturesCalmony PayUpdated March 15, 2026

Breaking Type Fix: CreatePaymentMethodParams Now Matches the API Contract

Breaking Type Fix: CreatePaymentMethodParams Now Matches the API Contract

Version: v1.0.74
Affected API: POST /v1/payment_methods
Affected SDK type: CreatePaymentMethodParams


Background

The Calmony Pay SDK ships a typed client interface so you can call the payment API from TypeScript without writing raw fetch calls. One of those typed methods is paymentMethods.create(), which maps to the POST /v1/payment_methods REST endpoint.

A spec drift was identified between the SDK's TypeScript types and what the API actually accepts. If you were relying on the SDK types — and following them faithfully — your requests would silently fail at runtime with a 400 Bad Request.


The Problem

The SDK previously typed the card parameter like this:

export interface CreatePaymentMethodParams {
  type: 'card'
  card: {
    token: string  // ← Cardstream hosted-page token
  }
}

This suggested that a tokenised card reference from a Cardstream hosted payment page was the expected input. It wasn't.

The REST API at POST /v1/payment_methods has always required raw card fields:

{
  "type": "card",
  "card": {
    "number": "4242424242424242",
    "exp_month": 12,
    "exp_year": 2027,
    "cvc": "123"
  }
}

Passing token causes the API's request body validator to reject the payload and return:

{
  "error": {
    "code": "validation_error",
    "message": "card.number is required"
  }
}

The Fix

The CreatePaymentMethodParams type in src/lib/calmony-pay/client.ts has been updated to reflect the true API contract:

export interface CreatePaymentMethodParams {
  type: 'card'
  card: {
    number: string
    exp_month: number
    exp_year: number
    cvc: string
  }
}

The REST route (src/app/api/v1/payment_methods/route.ts) is unchanged — it was already correct. The SDK type is now aligned with it.


Migration Guide

If your codebase calls paymentMethods.create() via the SDK, find any usages that pass a token field and replace them with the full card object:

// ❌ Old — TypeScript accepted this but the API rejected it
const method = await pay.paymentMethods.create({
  type: 'card',
  card: {
    token: 'cs_tok_abc123'
  }
})

// ✅ New — matches the API contract
const method = await pay.paymentMethods.create({
  type: 'card',
  card: {
    number: '4242424242424242',
    exp_month: 12,
    exp_year: 2027,
    cvc: '123'
  }
})

Note: Raw card numbers should only ever be transmitted over HTTPS. Never log, store, or pass card fields through untrusted intermediaries. If your integration previously collected card details via a Cardstream hosted page and only held a token, you will need to adjust your card collection flow to collect and forward raw fields instead.


Why This Matters

Type drift between an SDK and its underlying API is one of the hardest classes of bug to diagnose — the compiler gives you a green light while the server returns an error. This fix restores the guarantee that code which compiles against the SDK types will also pass API validation at runtime.


Affected Files

FileChange
src/lib/calmony-pay/client.tsCreatePaymentMethodParams.card type updated from { token } to { number, exp_month, exp_year, cvc }
src/app/api/v1/payment_methods/route.tsNo change — confirmed as the source of truth