Skip to content

Card contract: Idempotency-Key + 409s, DECLINED status, CARD_TRANSACTION.DECLINED, threeDSecurePassword#686

Draft
kphurley7 wants to merge 4 commits into
mainfrom
kph/cards-idempotency-txn-webhook
Draft

Card contract: Idempotency-Key + 409s, DECLINED status, CARD_TRANSACTION.DECLINED, threeDSecurePassword#686
kphurley7 wants to merge 4 commits into
mainfrom
kph/cards-idempotency-txn-webhook

Conversation

@kphurley7

@kphurley7 kphurley7 commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Contract prerequisite (C1) for the Striga-under-Grid card work (design: lightsparkdev/webdev#30261; server-side stack lightsparkdev/webdev#30314 → #30403).

Changes

  • POST /cards: declares the Idempotency-Key header, mirroring the money-movement operations' shape. The server now requires it for card programs on EUR-funded (EU) platforms, where card creation is a non-idempotent fee-bearing provider call.
  • POST /cards + PATCH /cards/{id}: declare the 409 responses the server actually emits (key replayed with a different body / same key still processing; provider-reported state conflicts), reusing the existing Error409 component. No new error codes invented.
  • DECLINED terminal status on CardTransactionStatus: declined authorizations are first-class transactions (no funds moved, terminal), needed for read parity with the EU provider's decline stream.
  • CARD_TRANSACTION.DECLINED webhook type: extends the CARD_TRANSACTION.* family merged in feat(webhooks): add CARD_TRANSACTION webhook contract #690 (this branch originally proposed a single CARD.TRANSACTION_UPDATE type; rebased onto the merged family and dropped the competing type). Includes a declined delivery example and doc-snippet rework to the per-status family semantics.
  • threeDSecurePassword (write-only, optional, 8-36 chars) on card create: static 3-D Secure challenge password pass-through for EU card programs; Grid generates when omitted; rejected on programs without a static-password factor.

Bundles regenerated with make build (Redocly).

Known conformance note (not changed here)

The existing PATCH 409 prose says state: CLOSED on an already-CLOSED card returns CARD_ALREADY_CLOSED — the server implementation (both providers) actually treats CLOSED→CLOSED as an idempotent 200. Reconciling contract-vs-implementation is part of the card contract-conformance workstream (design §10 Phase 0a).

@vercel

vercel Bot commented Jul 14, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

2 Skipped Deployments
Project Deployment Actions Updated (UTC)
grid-flow-builder Ignored Ignored Preview Jul 16, 2026 3:03pm
grid-wallet-demo Ignored Ignored Preview Jul 16, 2026 3:03pm

Request Review

@mintlify

mintlify Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
Grid 🟢 Ready View Preview Jul 14, 2026, 4:04 PM

@github-actions

github-actions Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

✱ Stainless preview builds for grid

This PR will update the grid SDKs with the following commit messages.

cli

feat(api): add idempotency-key parameter to cards issue method

go

feat(api): add card_transaction_update webhook, idempotency_key param to cards.issue

kotlin

feat(api): add idempotency_key to cards.issue, CardTransactionUpdate webhook

openapi

feat(api): add idempotency to card creation, card transaction update webhook

php

feat(api): add idempotencyKey to cards.issue, CardTransactionUpdate webhook

python

feat(api): add idempotency_key to cards.issue, CardTransactionUpdateWebhookEvent

ruby

feat(api): add CardTransactionUpdateWebhookEvent, idempotency_key to cards.issue

typescript

feat(api): add CardTransactionUpdate webhook, Idempotency-Key to cards issue

Edit this comment to update them. They will appear in their respective SDK's changelogs.

grid-typescript studio · code · diff

Your SDK build had at least one "note" diagnostic, but this did not represent a regression.
generate ✅build ✅lint ❗test ✅

npm install https://pkg.stainless.com/s/grid-typescript/151b63c12d1fa05549bcaa3f7a55fbd2c5db18e7/dist.tar.gz
grid-openapi studio · code · diff

Your SDK build had at least one "warning" diagnostic, but this did not represent a regression.
generate ⚠️

grid-ruby studio · code · diff

Your SDK build had at least one "note" diagnostic, but this did not represent a regression.
generate ✅build ✅lint ✅test ✅

grid-go studio · code · diff

Your SDK build had at least one "note" diagnostic, but this did not represent a regression.
generate ✅build ✅lint ❗test ❗

go get github.com/stainless-sdks/grid-go@e62bc8ee30328443f6b4d08e088f2dbe48831add
grid-kotlin studio · code · diff

Your SDK build had at least one "warning" diagnostic, but this did not represent a regression.
generate ⚠️build ✅lint ✅test ❗

grid-python studio · code · diff

Your SDK build had at least one "note" diagnostic, but this did not represent a regression.
generate ✅build ✅lint ❗test ❗

pip install https://pkg.stainless.com/s/grid-python/96caf12d5ed9e9753bd08cead1ba18b5982e2d43/grid-0.0.1-py3-none-any.whl
grid-php studio · code · diff

Your SDK build had at least one "note" diagnostic, but this did not represent a regression.
generate ✅lint ✅test ✅

grid-cli studio · code · diff

Your SDK build had at least one "warning" diagnostic, but this did not represent a regression.
generate ⚠️build ❗lint ❗test ❗


This comment is auto-generated by GitHub Actions and is automatically kept up to date as you push.
If you push custom code to the preview branch, re-run this workflow to update the comment.
Last updated: 2026-07-16 15:09:17 UTC

@mintlify

mintlify Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
Grid 🟡 Building Jul 14, 2026, 4:02 PM

kphurley7 and others added 4 commits July 16, 2026 09:56
…webhook

- POST /cards declares the Idempotency-Key header (same shape as the
  money-movement operations); required for EU card programs.
- POST /cards and PATCH /cards/{id} declare 409 conflict responses via
  the existing Error409 component (idempotency replay conflicts;
  provider state conflicts).
- New CARD.TRANSACTION_UPDATE webhook type + CardTransactionUpdateWebhook
  payload (mirrors CardStateChangeWebhook; data = CardTransaction),
  registered in the webhook operations and card docs snippets.

Bundles regenerated with make build; lint clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018kzvhCS9mZrkHaH7E5EQ94
Upstream #690 merged a canonical per-status card-transaction webhook
contract (CARD_TRANSACTION.AUTHORIZED/PARTIALLY_SETTLED/SETTLED/
REFUNDED/EXCEPTION) that supersedes this branch's single
CARD.TRANSACTION_UPDATE type. Drop CardTransactionUpdateWebhook and its
operation/registration/enum value, rewrite the card doc snippets to the
family semantics, and extend the family with CARD_TRANSACTION.DECLINED
(webhook enum, operation description, and a declined example) to match
the DECLINED terminal status this branch adds to CardTransactionStatus.
Bundles regenerated with make build.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018kzvhCS9mZrkHaH7E5EQ94
@kphurley7
kphurley7 force-pushed the kph/cards-idempotency-txn-webhook branch from 4e82188 to 2edd585 Compare July 16, 2026 15:03
@kphurley7 kphurley7 changed the title Add card Idempotency-Key, 409 responses, and CARD.TRANSACTION_UPDATE webhook Card contract: Idempotency-Key + 409s, DECLINED status, CARD_TRANSACTION.DECLINED, threeDSecurePassword Jul 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant