Incident Report: Subscription Interval Mismatch Between SDK and REST API
Incident Report: Subscription Interval Mismatch Between SDK and REST API
Version affected: v1.0.75 and earlier
Resolved in: v1.0.76
Severity: High — silently broken API integration path
What Happened
A specification drift was identified between the Calmony Pay SDK client interface and the POST /v1/subscriptions REST API endpoint.
The SDK's CreateSubscriptionParams type defined the interval field as:
interval: 'month' | 'year'
This mirrors Stripe's own API conventions and would feel natural to any developer with prior Stripe experience.
However, the REST API validated the same field using:
z.enum(['monthly', 'annual'])
As a result, any call made through the SDK using interval: 'month' or interval: 'year' would be rejected by the API with a 400 invalid_request_error, even though the TypeScript types gave no indication that anything was wrong.
Impact
- Developers using the SDK to create subscriptions would always receive a
400error when passing either supported interval value. - The failure was silent from a type-safety perspective — TypeScript would not flag
interval: 'month'as incorrect given the SDK's type definitions. - Any application relying on
pay.subscriptions.create()for recurring billing would have been unable to successfully create subscriptions.
Affected Files
| File | Issue |
|---|---|
src/lib/calmony-pay/client.ts | CreateSubscriptionParams.interval typed as 'month' | 'year' |
src/app/api/v1/subscriptions/route.ts | Zod schema validates interval as 'monthly' | 'annual' |
Resolution
The interval field vocabulary has been aligned across both the SDK and the REST API in v1.0.76. The two sources now use consistent terminology.
If you were working around this bug by calling the REST API directly with 'monthly' or 'annual', no changes to your REST API calls are required.
If you were using the SDK and wondering why subscription creation was failing, upgrade to v1.0.76 and ensure your interval values match the now-consistent vocabulary.
Lessons & Follow-Up
This drift highlights the risk of maintaining parallel type definitions in an SDK client and a server-side validation schema without a shared source of truth. Going forward, the pinned Calmony Pay SDK Client Interface spec will be used as the authoritative contract for both layers.