Spec Drift: Checkout Session Expiry Field Mismatch (v1.0.106)
Spec Drift: Checkout Session Expiry Field Mismatch
Version: v1.0.106
Severity: Medium
Status: Identified — fix in pipeline
Summary
A divergence was found between the Calmony Pay SDK contract and the REST API implementation for checkout session expiry. The SDK documents expires_at (a Unix timestamp), while the REST API silently accepts and processes only expires_in (a duration in seconds). Callers sending expires_at to the REST API receive no error — the parameter is simply ignored and a default 30-minute session TTL is applied.
Background
When creating a checkout session, integrators need control over how long a session remains valid. The pinned API contract specifies this via an expires_at field — an absolute Unix timestamp indicating when the session should expire.
The SDK client correctly exposes this field:
// src/lib/calmony-pay/client.ts
interface CreateCheckoutSessionParams {
// ...
expires_at?: number; // Unix timestamp
}
However, the REST API endpoint uses a different schema:
// src/app/api/v1/checkout/sessions/route.ts
const createCheckoutSessionSchema = z.object({
// ...
expires_in: z.number().int().min(300).max(86400).default(1800), // seconds
});
expires_in is an integer number of seconds (minimum 5 minutes, maximum 24 hours, defaulting to 30 minutes). The API never reads an expires_at parameter from the request body.
Impact
| Scenario | Expected behaviour | Actual behaviour |
|---|---|---|
Caller sends expires_at (Unix timestamp) to REST API | Session expires at the specified timestamp | expires_at silently ignored; session expires after 30 minutes |
Caller sends expires_in (seconds) to REST API | Session expires after the specified number of seconds | Works as intended |
Caller uses the SDK with expires_at | SDK sends expires_at to the REST API | expires_at silently ignored at the API boundary |
There is no error, warning, or validation failure returned to the caller when expires_at is supplied. This makes the drift invisible without careful inspection of session expiry times.
Affected Files
src/app/api/v1/checkout/sessions/route.ts— REST API schema usesexpires_ininstead ofexpires_atsrc/lib/calmony-pay/client.ts— SDK exposesexpires_atper the pinned spec
What to Do Now
Until this is resolved in a follow-up release, integrators should be aware of the following:
If you call the REST API directly
Use expires_in (seconds) rather than expires_at (Unix timestamp):
POST /api/v1/checkout/sessions
Content-Type: application/json
{
"expires_in": 3600
}
Valid values for expires_in:
| Value | Meaning |
|---|---|
300 | 5 minutes (minimum) |
1800 | 30 minutes (default) |
3600 | 1 hour |
86400 | 24 hours (maximum) |
If you use the SDK
Be aware that expires_at passed through the SDK will currently be silently dropped at the REST API layer. The session will use the default 30-minute TTL. This will be corrected in a follow-up release — check the Changelog for updates.
Resolution Plan
The REST API schema and the SDK contract will be aligned. The spec-pinned expires_at (Unix timestamp) is the authoritative field. The expires_in field will either be removed or mapped to expires_at at the API boundary. A migration note will be added to the changelog once the fix is released.
References
- Pinned Spec: Calmony Pay REST API Contract
- Changelog — v1.0.106
- Affected endpoints:
POST /api/v1/checkout/sessions