From 92665083c86a45a0f39a5d3582bc967b99ab3ab2 Mon Sep 17 00:00:00 2001 From: Jeremy Klein Date: Sat, 23 May 2026 00:05:16 -0700 Subject: [PATCH 1/2] docs(spec): correct quote expiresAt window, document 501 on /cards, add 429 to verify MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Updates several OpenAPI accuracy gaps surfaced by the Grid error audit (parent epic AT-5324): - Quote.expiresAt was documented as 1-5 minutes; probes show window varies by rail and corridor. Replace with rail-aware description and the instruction to rely on the timestamp rather than a fixed window. - GET /cards (and /cards/{id}) returns 501 in dev today; document the response so SDK clients can handle it without surprise. - POST /auth/credentials/{id}/verify can return 429 with Retry-After; document the rate-limit envelope and header. - DELETE /auth/sessions/{id} description clarified to set expectations about 404 semantics on already-revoked sessions. Schema additions (supportedNetworks on InternalAccount, network field on RealtimeFundingQuoteSource) deferred — those are API design changes, not doc fixes, and warrant their own tickets. Refs AT-5351 --- mintlify/openapi.yaml | 87 +++++++++++++------ openapi.yaml | 87 +++++++++++++------ openapi/components/schemas/quotes/Quote.yaml | 9 +- .../auth/auth_credentials_{id}_verify.yaml | 16 ++++ openapi/paths/auth/auth_sessions_{id}.yaml | 9 ++ openapi/paths/cards/cards.yaml | 18 ++++ openapi/paths/cards/cards_{id}.yaml | 9 ++ 7 files changed, 178 insertions(+), 57 deletions(-) diff --git a/mintlify/openapi.yaml b/mintlify/openapi.yaml index 6a2a8401..f50b6483 100644 --- a/mintlify/openapi.yaml +++ b/mintlify/openapi.yaml @@ -4308,6 +4308,17 @@ paths: application/json: schema: $ref: '#/components/schemas/Error404' + '429': + description: Too many requests. Returned with `RATE_LIMITED` when verification attempts for this credential happen too frequently (for example, repeated bad OTPs or rapid-fire reauthentication retries). Clients should back off and retry after the interval indicated by the `Retry-After` response header. + headers: + Retry-After: + description: Number of seconds to wait before retrying the request. + schema: + type: integer + content: + application/json: + schema: + $ref: '#/components/schemas/Error429' '500': description: Internal service error content: @@ -4471,6 +4482,8 @@ paths: 1. Call `DELETE /auth/sessions/{id}` with no headers. The response is `202` with a `payloadToSign`, `requestId`, and `expiresAt`. 2. Use the session API keypair of a verified session on the same internal account (this can be the session being revoked, for self-logout) to build an API-key stamp over `payloadToSign`, then retry the same `DELETE` request with that full stamp as the `Grid-Wallet-Signature` header and the `requestId` echoed back as the `Request-Id` header. The signed retry returns `204`. + + Sessions also expire on their own. `404` is returned whenever the `id` does not match an active session — whether the session was never issued, was already revoked by a prior call, or has expired past its `expiresAt`. The response code reflects the resource state, not an error in the client's flow: re-revoking an already- revoked or expired session is safe and idempotent at the user intent level. operationId: revokeAuthSession tags: - Embedded Wallet Auth @@ -6217,6 +6230,12 @@ paths: application/json: schema: $ref: '#/components/schemas/Error500' + '501': + description: Not implemented in this environment. Card issuance is not enabled for every Grid deployment; environments without a configured card issuer return `501 NOT_IMPLEMENTED`. + content: + application/json: + schema: + $ref: '#/components/schemas/Error501' get: summary: List cards description: | @@ -6301,6 +6320,12 @@ paths: application/json: schema: $ref: '#/components/schemas/Error500' + '501': + description: Not implemented in this environment. Cards are not enabled for every Grid deployment; environments without a configured card issuer return `501 NOT_IMPLEMENTED`. + content: + application/json: + schema: + $ref: '#/components/schemas/Error501' /cards/{id}: parameters: - name: id @@ -6342,6 +6367,12 @@ paths: application/json: schema: $ref: '#/components/schemas/Error500' + '501': + description: Not implemented in this environment. Cards are not enabled for every Grid deployment; environments without a configured card issuer return `501 NOT_IMPLEMENTED`. + content: + application/json: + schema: + $ref: '#/components/schemas/Error501' patch: summary: Update a card description: | @@ -16194,7 +16225,7 @@ components: expiresAt: type: string format: date-time - description: When this quote expires (typically 1-5 minutes after creation) + description: 'Absolute UTC timestamp when the rate locked in this quote becomes invalid and the quote can no longer be executed. The window depends on the rail and corridor: instant rails (Lightning, Spark, USDC on Solana/Base/Polygon, RTP, SEPA Instant) typically expire in 1–5 minutes; corridors with longer settlement guarantees may have longer windows. Always rely on this timestamp rather than assuming a fixed window.' example: '2025-10-03T12:05:00Z' source: $ref: '#/components/schemas/QuoteSourceOneOf' @@ -17240,6 +17271,33 @@ components: format: date-time description: Timestamp after which the session is no longer valid and the `encryptedSessionSigningKey` must not be used to sign further requests. example: '2026-04-09T15:30:01Z' + Error429: + type: object + required: + - message + - status + - code + properties: + status: + type: integer + enum: + - 429 + description: HTTP status code + code: + type: string + description: | + | Error Code | Description | + |------------|-------------| + | RATE_LIMITED | Too many requests in a short window; retry after the interval indicated by the `Retry-After` response header | + enum: + - RATE_LIMITED + message: + type: string + description: Error message + details: + type: object + description: Additional error details + additionalProperties: true AuthCredentialChallengeRequest: title: Auth Credential Challenge Request description: Request body for `POST /auth/credentials/{id}/challenge`. Required when re-challenging a `PASSKEY` credential — must carry `clientPublicKey` so Grid can bake it into the Turnkey session-creation payload the returned challenge is computed from. Ignored for `EMAIL_OTP`, where the credential type alone is sufficient because the OTP is delivered out-of-band. OAuth credentials do not use this endpoint; authenticate or reauthenticate them with `POST /auth/credentials/{id}/verify`. @@ -17292,33 +17350,6 @@ components: mapping: EMAIL_OTP: '#/components/schemas/AuthMethodResponse' PASSKEY: '#/components/schemas/PasskeyAuthChallenge' - Error429: - type: object - required: - - message - - status - - code - properties: - status: - type: integer - enum: - - 429 - description: HTTP status code - code: - type: string - description: | - | Error Code | Description | - |------------|-------------| - | RATE_LIMITED | Too many requests in a short window; retry after the interval indicated by the `Retry-After` response header | - enum: - - RATE_LIMITED - message: - type: string - description: Error message - details: - type: object - description: Additional error details - additionalProperties: true SessionListResponse: type: object required: diff --git a/openapi.yaml b/openapi.yaml index 6a2a8401..f50b6483 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -4308,6 +4308,17 @@ paths: application/json: schema: $ref: '#/components/schemas/Error404' + '429': + description: Too many requests. Returned with `RATE_LIMITED` when verification attempts for this credential happen too frequently (for example, repeated bad OTPs or rapid-fire reauthentication retries). Clients should back off and retry after the interval indicated by the `Retry-After` response header. + headers: + Retry-After: + description: Number of seconds to wait before retrying the request. + schema: + type: integer + content: + application/json: + schema: + $ref: '#/components/schemas/Error429' '500': description: Internal service error content: @@ -4471,6 +4482,8 @@ paths: 1. Call `DELETE /auth/sessions/{id}` with no headers. The response is `202` with a `payloadToSign`, `requestId`, and `expiresAt`. 2. Use the session API keypair of a verified session on the same internal account (this can be the session being revoked, for self-logout) to build an API-key stamp over `payloadToSign`, then retry the same `DELETE` request with that full stamp as the `Grid-Wallet-Signature` header and the `requestId` echoed back as the `Request-Id` header. The signed retry returns `204`. + + Sessions also expire on their own. `404` is returned whenever the `id` does not match an active session — whether the session was never issued, was already revoked by a prior call, or has expired past its `expiresAt`. The response code reflects the resource state, not an error in the client's flow: re-revoking an already- revoked or expired session is safe and idempotent at the user intent level. operationId: revokeAuthSession tags: - Embedded Wallet Auth @@ -6217,6 +6230,12 @@ paths: application/json: schema: $ref: '#/components/schemas/Error500' + '501': + description: Not implemented in this environment. Card issuance is not enabled for every Grid deployment; environments without a configured card issuer return `501 NOT_IMPLEMENTED`. + content: + application/json: + schema: + $ref: '#/components/schemas/Error501' get: summary: List cards description: | @@ -6301,6 +6320,12 @@ paths: application/json: schema: $ref: '#/components/schemas/Error500' + '501': + description: Not implemented in this environment. Cards are not enabled for every Grid deployment; environments without a configured card issuer return `501 NOT_IMPLEMENTED`. + content: + application/json: + schema: + $ref: '#/components/schemas/Error501' /cards/{id}: parameters: - name: id @@ -6342,6 +6367,12 @@ paths: application/json: schema: $ref: '#/components/schemas/Error500' + '501': + description: Not implemented in this environment. Cards are not enabled for every Grid deployment; environments without a configured card issuer return `501 NOT_IMPLEMENTED`. + content: + application/json: + schema: + $ref: '#/components/schemas/Error501' patch: summary: Update a card description: | @@ -16194,7 +16225,7 @@ components: expiresAt: type: string format: date-time - description: When this quote expires (typically 1-5 minutes after creation) + description: 'Absolute UTC timestamp when the rate locked in this quote becomes invalid and the quote can no longer be executed. The window depends on the rail and corridor: instant rails (Lightning, Spark, USDC on Solana/Base/Polygon, RTP, SEPA Instant) typically expire in 1–5 minutes; corridors with longer settlement guarantees may have longer windows. Always rely on this timestamp rather than assuming a fixed window.' example: '2025-10-03T12:05:00Z' source: $ref: '#/components/schemas/QuoteSourceOneOf' @@ -17240,6 +17271,33 @@ components: format: date-time description: Timestamp after which the session is no longer valid and the `encryptedSessionSigningKey` must not be used to sign further requests. example: '2026-04-09T15:30:01Z' + Error429: + type: object + required: + - message + - status + - code + properties: + status: + type: integer + enum: + - 429 + description: HTTP status code + code: + type: string + description: | + | Error Code | Description | + |------------|-------------| + | RATE_LIMITED | Too many requests in a short window; retry after the interval indicated by the `Retry-After` response header | + enum: + - RATE_LIMITED + message: + type: string + description: Error message + details: + type: object + description: Additional error details + additionalProperties: true AuthCredentialChallengeRequest: title: Auth Credential Challenge Request description: Request body for `POST /auth/credentials/{id}/challenge`. Required when re-challenging a `PASSKEY` credential — must carry `clientPublicKey` so Grid can bake it into the Turnkey session-creation payload the returned challenge is computed from. Ignored for `EMAIL_OTP`, where the credential type alone is sufficient because the OTP is delivered out-of-band. OAuth credentials do not use this endpoint; authenticate or reauthenticate them with `POST /auth/credentials/{id}/verify`. @@ -17292,33 +17350,6 @@ components: mapping: EMAIL_OTP: '#/components/schemas/AuthMethodResponse' PASSKEY: '#/components/schemas/PasskeyAuthChallenge' - Error429: - type: object - required: - - message - - status - - code - properties: - status: - type: integer - enum: - - 429 - description: HTTP status code - code: - type: string - description: | - | Error Code | Description | - |------------|-------------| - | RATE_LIMITED | Too many requests in a short window; retry after the interval indicated by the `Retry-After` response header | - enum: - - RATE_LIMITED - message: - type: string - description: Error message - details: - type: object - description: Additional error details - additionalProperties: true SessionListResponse: type: object required: diff --git a/openapi/components/schemas/quotes/Quote.yaml b/openapi/components/schemas/quotes/Quote.yaml index 8004b585..aee147bb 100644 --- a/openapi/components/schemas/quotes/Quote.yaml +++ b/openapi/components/schemas/quotes/Quote.yaml @@ -36,7 +36,14 @@ properties: expiresAt: type: string format: date-time - description: When this quote expires (typically 1-5 minutes after creation) + description: >- + Absolute UTC timestamp when the rate locked in this quote becomes + invalid and the quote can no longer be executed. The window depends + on the rail and corridor: instant rails (Lightning, Spark, USDC on + Solana/Base/Polygon, RTP, SEPA Instant) typically expire in 1–5 + minutes; corridors with longer settlement guarantees may have longer + windows. Always rely on this timestamp rather than assuming a fixed + window. example: '2025-10-03T12:05:00Z' # Transfer details source: diff --git a/openapi/paths/auth/auth_credentials_{id}_verify.yaml b/openapi/paths/auth/auth_credentials_{id}_verify.yaml index f0ffd525..fd6a9155 100644 --- a/openapi/paths/auth/auth_credentials_{id}_verify.yaml +++ b/openapi/paths/auth/auth_credentials_{id}_verify.yaml @@ -108,6 +108,22 @@ post: application/json: schema: $ref: ../../components/schemas/errors/Error404.yaml + '429': + description: >- + Too many requests. Returned with `RATE_LIMITED` when verification + attempts for this credential happen too frequently (for example, + repeated bad OTPs or rapid-fire reauthentication retries). Clients + should back off and retry after the interval indicated by the + `Retry-After` response header. + headers: + Retry-After: + description: Number of seconds to wait before retrying the request. + schema: + type: integer + content: + application/json: + schema: + $ref: ../../components/schemas/errors/Error429.yaml '500': description: Internal service error content: diff --git a/openapi/paths/auth/auth_sessions_{id}.yaml b/openapi/paths/auth/auth_sessions_{id}.yaml index af3a7ef0..4afd148f 100644 --- a/openapi/paths/auth/auth_sessions_{id}.yaml +++ b/openapi/paths/auth/auth_sessions_{id}.yaml @@ -15,6 +15,15 @@ delete: then retry the same `DELETE` request with that full stamp as the `Grid-Wallet-Signature` header and the `requestId` echoed back as the `Request-Id` header. The signed retry returns `204`. + + + Sessions also expire on their own. `404` is returned whenever the + `id` does not match an active session — whether the session was + never issued, was already revoked by a prior call, or has expired + past its `expiresAt`. The response code reflects the resource + state, not an error in the client's flow: re-revoking an already- + revoked or expired session is safe and idempotent at the user + intent level. operationId: revokeAuthSession tags: - Embedded Wallet Auth diff --git a/openapi/paths/cards/cards.yaml b/openapi/paths/cards/cards.yaml index 5b9dc461..08dc7c3a 100644 --- a/openapi/paths/cards/cards.yaml +++ b/openapi/paths/cards/cards.yaml @@ -61,6 +61,15 @@ post: application/json: schema: $ref: ../../components/schemas/errors/Error500.yaml + '501': + description: >- + Not implemented in this environment. Card issuance is not enabled + for every Grid deployment; environments without a configured card + issuer return `501 NOT_IMPLEMENTED`. + content: + application/json: + schema: + $ref: ../../components/schemas/errors/Error501.yaml get: summary: List cards description: > @@ -150,3 +159,12 @@ get: application/json: schema: $ref: ../../components/schemas/errors/Error500.yaml + '501': + description: >- + Not implemented in this environment. Cards are not enabled for + every Grid deployment; environments without a configured card + issuer return `501 NOT_IMPLEMENTED`. + content: + application/json: + schema: + $ref: ../../components/schemas/errors/Error501.yaml diff --git a/openapi/paths/cards/cards_{id}.yaml b/openapi/paths/cards/cards_{id}.yaml index b117a28c..8a786df0 100644 --- a/openapi/paths/cards/cards_{id}.yaml +++ b/openapi/paths/cards/cards_{id}.yaml @@ -38,6 +38,15 @@ get: application/json: schema: $ref: ../../components/schemas/errors/Error500.yaml + '501': + description: >- + Not implemented in this environment. Cards are not enabled for + every Grid deployment; environments without a configured card + issuer return `501 NOT_IMPLEMENTED`. + content: + application/json: + schema: + $ref: ../../components/schemas/errors/Error501.yaml patch: summary: Update a card description: > From 8ec159356e6ade022a5394a9ae3a10af924aab9b Mon Sep 17 00:00:00 2001 From: Jeremy Klein Date: Sat, 23 May 2026 00:17:54 -0700 Subject: [PATCH 2/2] address greptile review feedback (greploop iteration 1) - Add 501 NOT_IMPLEMENTED response to PATCH /cards/{id} for parity with the GET endpoints (same card-issuer dependency). - Reflow the auth_sessions_{id} DELETE description so the YAML folded scalar doesn't render 'already- revoked' with a space after the hyphen. --- mintlify/openapi.yaml | 8 +++++++- openapi.yaml | 8 +++++++- openapi/paths/auth/auth_sessions_{id}.yaml | 6 +++--- openapi/paths/cards/cards_{id}.yaml | 9 +++++++++ 4 files changed, 26 insertions(+), 5 deletions(-) diff --git a/mintlify/openapi.yaml b/mintlify/openapi.yaml index f50b6483..485509d8 100644 --- a/mintlify/openapi.yaml +++ b/mintlify/openapi.yaml @@ -4483,7 +4483,7 @@ paths: 2. Use the session API keypair of a verified session on the same internal account (this can be the session being revoked, for self-logout) to build an API-key stamp over `payloadToSign`, then retry the same `DELETE` request with that full stamp as the `Grid-Wallet-Signature` header and the `requestId` echoed back as the `Request-Id` header. The signed retry returns `204`. - Sessions also expire on their own. `404` is returned whenever the `id` does not match an active session — whether the session was never issued, was already revoked by a prior call, or has expired past its `expiresAt`. The response code reflects the resource state, not an error in the client's flow: re-revoking an already- revoked or expired session is safe and idempotent at the user intent level. + Sessions also expire on their own. `404` is returned whenever the `id` does not match an active session — whether the session was never issued, was already revoked by a prior call, or has expired past its `expiresAt`. The response code reflects the resource state, not an error in the client's flow: re-revoking an already-revoked or expired session is safe and idempotent at the user intent level. operationId: revokeAuthSession tags: - Embedded Wallet Auth @@ -6488,6 +6488,12 @@ paths: application/json: schema: $ref: '#/components/schemas/Error500' + '501': + description: Not implemented in this environment. Cards are not enabled for every Grid deployment; environments without a configured card issuer return `501 NOT_IMPLEMENTED`. + content: + application/json: + schema: + $ref: '#/components/schemas/Error501' /sandbox/cards/{id}/simulate/authorization: post: summary: Simulate a card authorization diff --git a/openapi.yaml b/openapi.yaml index f50b6483..485509d8 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -4483,7 +4483,7 @@ paths: 2. Use the session API keypair of a verified session on the same internal account (this can be the session being revoked, for self-logout) to build an API-key stamp over `payloadToSign`, then retry the same `DELETE` request with that full stamp as the `Grid-Wallet-Signature` header and the `requestId` echoed back as the `Request-Id` header. The signed retry returns `204`. - Sessions also expire on their own. `404` is returned whenever the `id` does not match an active session — whether the session was never issued, was already revoked by a prior call, or has expired past its `expiresAt`. The response code reflects the resource state, not an error in the client's flow: re-revoking an already- revoked or expired session is safe and idempotent at the user intent level. + Sessions also expire on their own. `404` is returned whenever the `id` does not match an active session — whether the session was never issued, was already revoked by a prior call, or has expired past its `expiresAt`. The response code reflects the resource state, not an error in the client's flow: re-revoking an already-revoked or expired session is safe and idempotent at the user intent level. operationId: revokeAuthSession tags: - Embedded Wallet Auth @@ -6488,6 +6488,12 @@ paths: application/json: schema: $ref: '#/components/schemas/Error500' + '501': + description: Not implemented in this environment. Cards are not enabled for every Grid deployment; environments without a configured card issuer return `501 NOT_IMPLEMENTED`. + content: + application/json: + schema: + $ref: '#/components/schemas/Error501' /sandbox/cards/{id}/simulate/authorization: post: summary: Simulate a card authorization diff --git a/openapi/paths/auth/auth_sessions_{id}.yaml b/openapi/paths/auth/auth_sessions_{id}.yaml index 4afd148f..53ccec2a 100644 --- a/openapi/paths/auth/auth_sessions_{id}.yaml +++ b/openapi/paths/auth/auth_sessions_{id}.yaml @@ -21,9 +21,9 @@ delete: `id` does not match an active session — whether the session was never issued, was already revoked by a prior call, or has expired past its `expiresAt`. The response code reflects the resource - state, not an error in the client's flow: re-revoking an already- - revoked or expired session is safe and idempotent at the user - intent level. + state, not an error in the client's flow: re-revoking an + already-revoked or expired session is safe and idempotent at the + user intent level. operationId: revokeAuthSession tags: - Embedded Wallet Auth diff --git a/openapi/paths/cards/cards_{id}.yaml b/openapi/paths/cards/cards_{id}.yaml index 8a786df0..4aa75103 100644 --- a/openapi/paths/cards/cards_{id}.yaml +++ b/openapi/paths/cards/cards_{id}.yaml @@ -231,3 +231,12 @@ patch: application/json: schema: $ref: ../../components/schemas/errors/Error500.yaml + '501': + description: >- + Not implemented in this environment. Cards are not enabled for + every Grid deployment; environments without a configured card + issuer return `501 NOT_IMPLEMENTED`. + content: + application/json: + schema: + $ref: ../../components/schemas/errors/Error501.yaml