feat(sca): return the session expiry and require an end-user IP on SCA login complete - #780
Conversation
…A login complete Two additive-now, breaking-later gaps on the SCA login surface. The 180-day SCA session expiry that gates money movement in SCA-regulated currencies was not reported anywhere, so an integrator could only discover a lapsed session as a failed payment. `ScaLoginComplete` now carries `sessionExpiresAt`, letting a platform prompt a re-login ahead of the lapse. The end user's IP is recorded against the login event by the SCA provider and feeds its risk assessment and any transaction-risk exemption. Only the platform relaying the login knows that address, so `ScaLoginCompleteRequest` now requires `endUserIpAddress`. `ScaAuthorization` gains the same field as optional: it is shared by quote authorization and beneficiary trust changes, and only the former records an IP. Adding a required request property is a breaking change (oasdiff: new-required-request-property). No `info.version` bump: the endpoint has no callers, so there is no existing contract to protect. Also drops the claim that `status` is passed through verbatim without normalization, which contradicted the same schema documenting `SUCCESS`.
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 ✅ grid-ruby studio · code
|
Greptile SummaryThis PR expands the SCA API contract with session-expiry and end-user IP metadata.
Confidence Score: 5/5The PR appears safe to merge with the source schemas and generated bundles consistently representing the intended SCA contract. The required login IP composes with the existing proof requirements, the shared authorization IP remains optional, and session expiry is modeled consistently with other conditionally present SCA response fields.
|
| Filename | Overview |
|---|---|
| openapi/components/schemas/sca/ScaLoginCompleteRequest.yaml | Requires the end user's IP on login completion while preserving the existing proof-selection constraints. |
| openapi/components/schemas/sca/ScaLoginComplete.yaml | Adds the conditionally present session-expiry timestamp and corrects the status documentation. |
| openapi/components/schemas/sca/ScaAuthorization.yaml | Adds nullable, optional end-user IP metadata without breaking operations sharing this authorization schema. |
| openapi.yaml | Accurately bundles the modular SCA schema changes. |
| mintlify/openapi.yaml | Remains synchronized with the root generated OpenAPI bundle. |
Reviews (1): Last reviewed commit: "feat(sca): return the session expiry and..." | Re-trigger Greptile

Summary
Two additive-now, breaking-later gaps on the SCA login surface.
sessionExpiresAtonScaLoginComplete. Completing an SCA login establishes a 180-day session, and money movement in SCA-regulated currencies (EUR / USDC) is refused once it lapses. That expiry wasn't reported anywhere, so an integrator could only discover a lapsed session as a failed payment. Returning it lets a platform prompt a re-login ahead of time.endUserIpAddress, required onScaLoginCompleteRequest. The end user's IP is recorded against the login event by the SCA provider, where it feeds risk assessment and any transaction-risk exemption. A platform relaying the login on its customer's behalf is the only party that knows that address — so it has to travel in the request rather than being inferred from the connection, which sees the platform's server.ScaAuthorizationgains the same field as optional: that schema is shared by quote authorization and beneficiary trust changes, and only the former records an IP, so requiring it would demand a value from callers of operations that ignore it.Breaking change
Adding a required request property is breaking (
oasdiff:new-required-request-propertyonPOST /sca/login/complete) and the PR is labelled accordingly.No
info.versionbump. The versioning rule exists to protect integrators against a silently-changed contract, and this endpoint has no callers yet — so minting a new dated API version and theservers.urlpath that must accompany it would fragment the version namespace with no one to protect.Also
Drops the
statusdescription's claim that the value is "passed through verbatim (Grid does not normalize it)". That contradicted the same schema documenting a successful login as reportingSUCCESS; the value is normalized, and the description now says only what's true.Test plan
make build— bundledopenapi.yamlandmintlify/openapi.yamlregenerated in lockstep;info.versionunchanged at2025-10-13.make lint-openapi— exits 0. The remainingschema-properties-have-*findings are pre-existing repo-wide noise; the one namingScaLoginCompleteRequestis on the untouchedfactorproperty (confirmed identical onmain).oasdiff breakingagainstmainwith the CI-pinned v1.16.0 — exactly one error, the expectednew-required-request-property, and no others.requiredcomposes with the existinganyOfproof constraint rather than replacing it;sessionExpiresAtis a nullabledate-time;ScaAuthorization.endUserIpAddressis nullable and absent from anyrequiredlist.Requested by @jklein24
Original PR: #779