feat(cards): add PIN management APIs and status webhooks - #897
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
3 Skipped Deployments
|
|
Preview deployment for your docs. Learn more about Mintlify Previews.
|
✱ Stainless preview builds for gridThis PR will update the cli go kotlin openapi php python ruby typescript Edit this comment to update them. They will appear in their respective SDK's changelogs. ✅ grid-typescript studio · code · diff
✅ grid-openapi studio · code · diff
✅ grid-kotlin studio · code · diff
✅ grid-ruby studio · code · diff
✅ grid-go studio · code · diff
✅ grid-python studio · code · diff
✅ grid-php studio · code · diff
✅ grid-cli studio · code · diff
This comment is auto-generated by GitHub Actions and is automatically kept up to date as you push. |
2c2098d to
8a85f10
Compare
8a85f10 to
e64c7ef
Compare
|
e64c7ef to
b5d5e50
Compare
b5d5e50 to
dba77ee
Compare
dba77ee to
63e02dd
Compare
63e02dd to
d1d5ef9
Compare
d1d5ef9 to
b414afd
Compare
| @@ -0,0 +1,135 @@ | |||
| parameters: | |||
There was a problem hiding this comment.
do we need this? seems like get card already gives you the pin
There was a problem hiding this comment.
get card only gives you the pin status, like if the pin was configured, not configured, or blocked
There was a problem hiding this comment.
oh sry i meant the get below. seems like it only has the status
There was a problem hiding this comment.
Oh yea get pin here is redundant with the existing get card. I can remove it, i'm just curious if it is something where it would seem confusing to an integrator that they cant do GET /cards/{id}/pin when we have an existing POST /cards/{id}/pin?
There was a problem hiding this comment.
If i'm wrong about that, i can def remove GET /cards/{id}/pin
There was a problem hiding this comment.
i dont think we need it but maybe @pengying has some thoughts. should we also emit some webhooks on these status changes?
There was a problem hiding this comment.
For chaning a pin to OK or NOT_SET I don't think we need webhooks because the platform itself is making API calls to get the PIN to that state. For BLOCKED i can add follow up PRs for the webhook
|
🦣 Congratulations @shreyav - your substantive review earned a Argentavis! (rare)
View your Frost-dex: https://zeus.dev.dev.sparkinfra.net/#/dinodex/shreyav?section=ice-age |
| description: | | ||
| State of the card's PIN. On the Card resource, this is the last known status | ||
| and is present whenever PIN management is supported. An absent value means | ||
| PIN management is unavailable for this card; it does not mean `NOT_SET`. |
There was a problem hiding this comment.
should this be a card capability
There was a problem hiding this comment.
that sentence is just there because Striga cards operate differently with PINs so this is just an absent value / null for striga cards
There was a problem hiding this comment.
just wanted to clarify the difference between null and NOT_SET
| @@ -0,0 +1,15 @@ | |||
| type: object | |||
There was a problem hiding this comment.
what happens if you call create session twice? should the session resource have an id?
There was a problem hiding this comment.
wait one sec, turns out Ben implemented card reveal iframes using their old flow which doesnt use sessions
There was a problem hiding this comment.
but why do you think a session id would be necessary? sessions are short lived and not really like an object that would be used later on or need to be referred to
There was a problem hiding this comment.
the question underneath is what happens to session 1 when you create session 2. because the status, and the unblock api are scoped to the card and not the session
There was a problem hiding this comment.
that's a lithic thing but they aren't explicit in their docs about it, it does Look like either session can still update the card though
There was a problem hiding this comment.
so it shouldnt matter
There was a problem hiding this comment.
Yea highly confident either can update the PIN still
b414afd to
ea631b8
Compare
ea631b8 to
ef03da1
Compare
Adds three card PIN endpoints and a pinStatus field on the Card resource.
- POST /cards/{id}/pin takes a PIN block the client encrypted for the card
processor. Grid forwards it verbatim and never sees the PIN.
- POST /cards/{id}/pin/session mints a short-lived session token for the
processor's hosted PIN-entry iframe, for platforms without their own PIN
UI. The processor returns a token rather than a URL, so the response
carries the token and the client's embed SDK builds the iframe from it.
- POST /cards/{id}/pin/unblock clears a PIN blocked by three consecutive
incorrect entries, without changing it.
- Card.pinStatus reports NOT_SET / OK / BLOCKED, and is absent on cards whose
processor does not offer PIN management.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GsstRe1f8aoPXm1kYQw2Vm
ef03da1 to
6d7ba06
Compare
|
🦣 Congratulations @pengying - your substantive review earned a Metailurus! (common)
View your Frost-dex: https://zeus.dev.dev.sparkinfra.net/#/dinodex/pengying?section=ice-age |
| required: | ||
| - targetOrigin | ||
| properties: | ||
| targetOrigin: |
There was a problem hiding this comment.
can we make this on the platform config instead of each set pin request? And then we can make pin url a get.
There was a problem hiding this comment.
wdym by "make pin url a get." ?
There was a problem hiding this comment.
POST /cards/{id}/pin/session
{
"targetOrigin": "https://app.example.com"
}
becomes
GET /cards/{id}/set-pin-link
Merge activity
|

Reason
Platforms need to let cardholders choose or replace a PIN, recover a blocked PIN, and receive status changes. Platforms configure the website hosting the PIN iframe once, then request a temporary URL without repeating that setting.
Overview
Add three online-PIN operations: encrypted set/change (
POST /cards/{id}/set-pin), hosted PIN-entry URL retrieval (GET /cards/{id}/set-pin-url), and unblock (POST /cards/{id}/pin/unblock). ReadpinStatusfromGET /cards/{id}. Offline PIN cards and PIN reveal are unsupported.Configure
cardConfigs.pinTargetOriginusingPATCH /platform/config. The value is a canonical HTTPS origin shared by all user-specific paths on that website. Omission preserves it; null clears it. GET URL requests take no body or origin parameter and return409 CONFLICTif the setting is absent. Changes to the setting apply to newly requested URLs.Each URL request creates a fresh temporary PIN-entry session and returns
CardPinUrlResponse:iframeUrl,sessionToken,expiresAt, andenvironment. The URL permits one successful PIN submission. Responses specifyCache-Control: no-store; the operation requires card-management permission and an attributable audit actor. Fetching the URL does not change the PIN. The obsolete POST session operation and its request schema are removed.The guide covers platform configuration, loading the iframe, submitting a PIN, and confirming the result. Custom PIN entry requires client-side encryption of the complete nonce/PIN payload with the downloadable public key. An
OKstatus alone cannot confirm replacement of an existing PIN.Card.pinStatusis the last observed status, present from issuance when PIN management is supported and absent when unsupported.CARD.PIN_STATUS_CHANGEcarries the updated Card after an observed status change. Initial issuance and replacements that leave the statusOKdo not emit an event. The webhook guide covers signature verification, event deduplication, and out-of-order handling. No PIN material or session credentials are included in notifications.The implementation stack is webdev #34392 (regeneration), #34393 (handlers), #34394 (Ops UI), and #36190 (platform notifications). This GET/platform-configuration revision updates only the Grid API contract and docs. Corresponding webdev regeneration, configuration persistence, handler, and caller changes are deferred; the webdev PRs have not been updated for this contract. Incoming PIN updates also depend on the Lithic webhook subscription.
Test Plan
make buildandmake lint: pass; Spectral reports 0 errors. Its broad pagination rule adds a warning for the single-object GET URL response, alongside existing warnings.mint openapi-check mintlify/openapi.yaml: pass.no-storeresponse header, and returns the renamed response schema; the old POST session operation and schemas are absent.git diff --checkpasses.