feat: document SCA_SESSION_REQUIRED (409) and ACCOUNT_LOCKED (423) on quote authorize - #759
feat: document SCA_SESSION_REQUIRED (409) and ACCOUNT_LOCKED (423) on quote authorize#759ls-bolt[bot] wants to merge 1 commit into
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub. 2 Skipped Deployments
|
This stack of pull requests is managed by Graphite. Learn more about stacking. |
✱ 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-ruby studio · code · diff
✅ grid-go studio · code · diff
✅ grid-kotlin 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. |
|
Preview deployment for your docs. Learn more about Mintlify Previews.
|
ba24c0c to
065e823
Compare
… quote authorize (#761) ## Summary Two error codes the API already returns were missing from the spec, so a generated client rejected the response instead of surfacing the code. - **`SCA_SESSION_REQUIRED` added to the `Error409` `code` enum.** The API returns this with HTTP 409 when the customer's Strong Customer Authentication login session is missing or expired. Because it was absent from the enum, a generated client raised a validation error while deserializing the response — so an integrator got an opaque failure rather than a code they could act on. It is deliberately distinct from a `401`, which means the *platform's* API credentials were rejected: a `401` is not customer-recoverable, whereas `SCA_SESSION_REQUIRED` means "re-authenticate the customer, then retry". - **`POST /quotes/{quoteId}/authorize` now documents `409 SCA_SESSION_REQUIRED` and `423 ACCOUNT_LOCKED`.** This is the endpoint that surfaces both. Its `409` description previously covered only the "SCA not required / no pending challenge" cases, and it declared no `423` at all — even though the endpoint returns `ACCOUNT_LOCKED` when the customer's login is temporarily locked after too many failed authorization attempts. `Error423` already existed and needed no change; this just references it. Both changes are additive and non-breaking, so `info.version` stays `2025-10-13`. ## Known limitation this does not fix While verifying the above against the running implementation, I found that the error **envelope** does not match what the `ErrorNNN` schemas declare. The API sends: ```json {"code": "SCA_SESSION_REQUIRED", "reason": "..."} ``` but every `ErrorNNN` schema requires `status`, `code`, and `message`. So a generated Python client rejects a real error body on `status` (`int_type`) and `message` (`string_type`) regardless of this change: ``` ('status',) | int_type | Input should be a valid integer ('message',) | string_type | Input should be a valid string ``` This is pre-existing and applies to **every** documented error response across the spec, not just the two codes here — it is not introduced by this PR, and this PR is still a strict improvement (the enum is the published contract, and integrators reading the raw JSON body now have the code documented). But it does mean the typed-model path is not yet usable for error handling, so reconciling the envelope is worth its own change. Two options, both spec-wide decisions I did not want to make unilaterally: make the server emit `status`/`message`, or change the schemas to match reality (`reason`, and `status` not required). Relatedly, `Error423`'s own description points readers at `details.lockedUntil` / `details.failedAttempts`, but no error path populates them — those fields appear only on the `200` body of `POST /sca/record-event`. I left that description alone rather than expand this PR's scope, and worded the new `423` on the authorize endpoint to promise only what is actually sent. ## Test plan - `make lint` exits 0 (Redocly + Spectral, `--fail-severity=error`); the 630 remaining findings are pre-existing warnings/infos, 0 errors. - `make build` rebundled `openapi.yaml` and `mintlify/openapi.yaml`; re-running it is a no-op, so the committed bundles byte-match the build output. - Confirmed against the running implementation that both codes are genuinely emitted on this endpoint, each covered by a test asserting the status/code pair at the HTTP boundary — the `423` case is newly covered by a test added alongside this change. The `423` body was captured directly to confirm the wording matches what is sent. - Diff is 4 files: 2 spec sources + the 2 generated bundles. ## Public Documents two error codes the Grid API already returns: `SCA_SESSION_REQUIRED` (409) is added to the shared `Error409` enum, and `POST /quotes/{quoteId}/authorize` now documents both it and `423 ACCOUNT_LOCKED`. Original PR: #759

Summary
Two error codes the API already returns were missing from the spec, so a generated client rejected the response instead of surfacing the code.
SCA_SESSION_REQUIREDadded to theError409codeenum. The API returns this with HTTP 409 when the customer's Strong Customer Authentication login session is missing or expired. Because it was absent from the enum, a generated client raised a validation error while deserializing the response — so an integrator got an opaque failure rather than a code they could act on. It is deliberately distinct from a401, which means the platform's API credentials were rejected: a401is not customer-recoverable, whereasSCA_SESSION_REQUIREDmeans "re-authenticate the customer, then retry".POST /quotes/{quoteId}/authorizenow documents409 SCA_SESSION_REQUIREDand423 ACCOUNT_LOCKED. This is the endpoint that surfaces both. Its409description previously covered only the "SCA not required / no pending challenge" cases, and it declared no423at all — even though the endpoint returnsACCOUNT_LOCKEDwhen the customer's login is temporarily locked after too many failed authorization attempts.Error423already existed and needed no change; this just references it.Both changes are additive and non-breaking, so
info.versionstays2025-10-13.Known limitation this does not fix
While verifying the above against the running implementation, I found that the error envelope does not match what the
ErrorNNNschemas declare. The API sends:{"code": "SCA_SESSION_REQUIRED", "reason": "..."}but every
ErrorNNNschema requiresstatus,code, andmessage. So a generated Python client rejects a real error body onstatus(int_type) andmessage(string_type) regardless of this change:This is pre-existing and applies to every documented error response across the spec, not just the two codes here — it is not introduced by this PR, and this PR is still a strict improvement (the enum is the published contract, and integrators reading the raw JSON body now have the code documented). But it does mean the typed-model path is not yet usable for error handling, so reconciling the envelope is worth its own change. Two options, both spec-wide decisions I did not want to make unilaterally: make the server emit
status/message, or change the schemas to match reality (reason, andstatusnot required).Relatedly,
Error423's own description points readers atdetails.lockedUntil/details.failedAttempts, but no error path populates them — those fields appear only on the200body ofPOST /sca/record-event. I left that description alone rather than expand this PR's scope, and worded the new423on the authorize endpoint to promise only what is actually sent.Test plan
make lintexits 0 (Redocly + Spectral,--fail-severity=error); the 630 remaining findings are pre-existing warnings/infos, 0 errors.make buildrebundledopenapi.yamlandmintlify/openapi.yaml; re-running it is a no-op, so the committed bundles byte-match the build output.423case is newly covered by a test added alongside this change. The423body was captured directly to confirm the wording matches what is sent.Public
Documents two error codes the Grid API already returns:
SCA_SESSION_REQUIRED(409) is added to the sharedError409enum, andPOST /quotes/{quoteId}/authorizenow documents both it and423 ACCOUNT_LOCKED.