Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .stainless/stainless.yml
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ resources:
business_info: "#/components/schemas/BusinessInfo"
internal_account_export_request: '#/components/schemas/InternalAccountExportRequest'
internal_account_export_response: '#/components/schemas/InternalAccountExportResponse'
internal_account_update_request: '#/components/schemas/InternalAccountUpdateRequest'
methods:
create:
endpoint: post /customers
Expand All @@ -104,6 +105,9 @@ resources:
get_kyc_link: get /customers/kyc-link
list_internal_accounts: get /customers/internal-accounts
export: post /internal-accounts/{id}/export
update_internal_account:
endpoint: patch /internal-accounts/{id}
body_param_name: InternalAccountUpdateRequest
# Subresources define resources that are nested within another for more powerful
# logical groupings, e.g. `cards.payments`.
subresources:
Expand Down Expand Up @@ -476,9 +480,15 @@ resources:
list:
endpoint: get /auth/sessions
paginated: false
refresh:
endpoint: post /auth/sessions/{id}/refresh
body_param_name: AuthSessionRefreshRequest
delete: delete /auth/sessions/{id}
models:
session_list_response: '#/components/schemas/SessionListResponse'
auth_session_refresh_request: '#/components/schemas/AuthSessionRefreshRequest'
auth_session: '#/components/schemas/AuthSession'
signed_request_challenge: "#/components/schemas/SignedRequestChallenge"

agents:
methods:
Expand Down
326 changes: 284 additions & 42 deletions mintlify/openapi.yaml

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions mintlify/snippets/global-accounts/authentication.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -540,7 +540,7 @@ The response is not paginated — each account holds a small, bounded number of

### The signed-retry pattern

Adding an additional credential, revoking a credential, revoking a session, and exporting a wallet all share the same shape:
Adding an additional credential, revoking a credential, revoking a session, exporting a wallet, and updating wallet privacy all share the same shape:

```mermaid
sequenceDiagram
Expand Down Expand Up @@ -587,8 +587,8 @@ Requires an active session on an *existing* credential on the same account. The
```json
{
"type": "EMAIL_OTP",
"payloadToSign": "{\"requestId\":\"7c4a8d09-ca37-4e3e-9e0d-8c2b3e9a1f21\",\"type\":\"EMAIL_OTP\",\"accountId\":\"EmbeddedWallet:019542f5-b3e7-1d02-0000-000000000002\",\"expiresAt\":\"2026-04-08T15:35:00Z\"}",
"requestId": "7c4a8d09-ca37-4e3e-9e0d-8c2b3e9a1f21",
"payloadToSign": "{\"requestId\":\"Request:7c4a8d09-ca37-4e3e-9e0d-8c2b3e9a1f21\",\"type\":\"EMAIL_OTP\",\"accountId\":\"EmbeddedWallet:019542f5-b3e7-1d02-0000-000000000002\",\"expiresAt\":\"2026-04-08T15:35:00Z\"}",
"requestId": "Request:7c4a8d09-ca37-4e3e-9e0d-8c2b3e9a1f21",
"expiresAt": "2026-04-08T15:35:00Z"
}
```
Expand All @@ -604,7 +604,7 @@ Requires an active session on an *existing* credential on the same account. The
-u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \
-H "Content-Type: application/json" \
-H "Grid-Wallet-Signature: MEUCIQDx7k2N0aK4p8f3vR9J6yT5wL1mB0sXnG2hQ4vJ8zYkCgIgZ4rP9dT7eWfU3oM6KjR1qSpNvBwL0tXyA2iG8fH5dE=" \
-H "Request-Id: 7c4a8d09-ca37-4e3e-9e0d-8c2b3e9a1f21" \
-H "Request-Id: Request:7c4a8d09-ca37-4e3e-9e0d-8c2b3e9a1f21" \
-d '{
"type": "EMAIL_OTP",
"accountId": "EmbeddedWallet:019542f5-b3e7-1d02-0000-000000000002",
Expand Down Expand Up @@ -640,7 +640,7 @@ A credential is revoked by signing with a session from **a different credential
{
"type": "PASSKEY",
"payloadToSign": "Y2hhbGxlbmdlLXBheWxvYWQtdG8tc2lnbg==",
"requestId": "9f7a2c10-5e88-4fb1-bd0e-1c3a8e7b2d45",
"requestId": "Request:9f7a2c10-5e88-4fb1-bd0e-1c3a8e7b2d45",
"expiresAt": "2026-04-08T15:35:00Z"
}
```
Expand All @@ -653,7 +653,7 @@ A credential is revoked by signing with a session from **a different credential
curl -X DELETE "$GRID_BASE_URL/auth/credentials/AuthMethod:019542f5-b3e7-1d02-0000-000000000001" \
-u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \
-H "Grid-Wallet-Signature: MEUCIQDx7k2N0aK4p8f3vR9J6yT5wL1mB0sXnG2hQ4vJ8zYkCgIgZ4rP9dT7eWfU3oM6KjR1qSpNvBwL0tXyA2iG8fH5dE=" \
-H "Request-Id: 9f7a2c10-5e88-4fb1-bd0e-1c3a8e7b2d45"
-H "Request-Id: Request:9f7a2c10-5e88-4fb1-bd0e-1c3a8e7b2d45"
```

**Response:** `204 No Content`. All active sessions issued by the revoked credential are also revoked.
Expand Down
2 changes: 1 addition & 1 deletion mintlify/snippets/global-accounts/client-keys.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ Grid returns `payloadToSign` strings from several endpoints:

- `POST /quotes` (when the source is a Global Account) — the quote's `paymentInstructions[].accountOrWalletInfo.payloadToSign`.
- `POST /auth/credentials` (adding an additional credential) — 202 response body.
- `DELETE /auth/credentials/{id}`, `DELETE /auth/sessions/{id}`, `POST /internal-accounts/{id}/export` — all 202 response bodies.
- `DELETE /auth/credentials/{id}`, `DELETE /auth/sessions/{id}`, `POST /internal-accounts/{id}/export`, `PATCH /internal-accounts/{id}` — all 202 response bodies.

Sign the payload **byte-for-byte as returned** (do not re-parse, re-serialize, or trim whitespace). The signature is ECDSA over SHA-256 using the session signing key, DER-encoded, then base64-encoded. Pass it as the `Grid-Wallet-Signature` header on the retry (and, for endpoints that use it, the `Request-Id` header echoed back from the 202).

Expand Down
6 changes: 3 additions & 3 deletions mintlify/snippets/global-accounts/concepts.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,12 @@ The client **never** talks to Grid directly. Every request flows client → inte

## Auth credentials, client keys, and session signing keys

Three distinct pieces of crypto collaborate to authorize actions on the Global Account (withdrawals, credential changes, session revocations, and wallet exports):
Three distinct pieces of crypto collaborate to authorize actions on the Global Account (withdrawals, credential changes, session revocations, wallet exports, and wallet privacy updates):

| Piece | Where it lives | How long it lives | What it proves |
|---|---|---|---|
| **Auth credential** — passkey, OIDC token, or email OTP | Registered on the account; the passkey itself lives on the authenticator, OIDC on your IdP, OTP in the user's inbox | Until the customer revokes it | *"I am the human who owns this account."* Used to authenticate the user at the start of each session. |
| **Client key pair** (P-256) | Generated on the client device for each verification request; private key stays in device-local secure storage | One verification request | Binds a given session signing key delivery to the exact device that asked for it — Grid encrypts the session to this public key, so only this device can decrypt. |
| **Session signing key** (P-256) | Issued by Grid, sealed to the client public key, decrypted and held on the device for the session's lifetime | 15 minutes (default) | *"This specific account action was approved on an authenticated device."* Signs the `payloadToSign` Grid returns on quotes, credential changes, session revocations, and wallet exports. |
| **Session signing key** (P-256) | Issued by Grid, sealed to the client public key, decrypted and held on the device for the session's lifetime | 15 minutes (default) | *"This specific account action was approved on an authenticated device."* Signs the `payloadToSign` Grid returns on quotes, credential changes, session revocations, wallet exports, and wallet privacy updates. |

The flow is always the same: verify an auth credential → receive a short-lived session signing key → sign `payloadToSign` bytes on the client → pass the signature as the `Grid-Wallet-Signature` header on the request that actually moves funds or changes account state. This applies to withdrawals, adding or removing credentials, revoking sessions, and exporting the wallet seed.
The flow is always the same: verify an auth credential → receive a short-lived session signing key → sign `payloadToSign` bytes on the client → pass the signature as the `Grid-Wallet-Signature` header on the request that actually moves funds or changes account state. This applies to withdrawals, adding or removing credentials, revoking sessions, exporting the wallet seed, and updating wallet privacy.
4 changes: 2 additions & 2 deletions mintlify/snippets/global-accounts/exporting-wallet.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ sequenceDiagram
```json
{
"payloadToSign": "Y2hhbGxlbmdlLXBheWxvYWQtdG8tc2lnbg==",
"requestId": "c3f8a614-47e2-4a19-9f5d-2b0a91d47e08",
"requestId": "Request:c3f8a614-47e2-4a19-9f5d-2b0a91d47e08",
"expiresAt": "2026-04-19T12:10:00Z"
}
```
Expand All @@ -51,7 +51,7 @@ sequenceDiagram
-u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \
-H "Content-Type: application/json" \
-H "Grid-Wallet-Signature: MEUCIQDx7k2N0aK4p8f3vR9J6yT5wL1mB0sXnG2hQ4vJ8zYkCgIgZ4rP9dT7eWfU3oM6KjR1qSpNvBwL0tXyA2iG8fH5dE=" \
-H "Request-Id: c3f8a614-47e2-4a19-9f5d-2b0a91d47e08" \
-H "Request-Id: Request:c3f8a614-47e2-4a19-9f5d-2b0a91d47e08" \
-d '{
"clientPublicKey": "04f45f2a22c908b9ce09a7150e514afd24627c401c38a4afc164e1ea783adaaa31d4245acfb88c2ebd42b47628d63ecabf345484f0a9f665b63c54c897d5578be2"
}'
Expand Down
4 changes: 2 additions & 2 deletions mintlify/snippets/global-accounts/managing-sessions.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ Session revocation uses the same <a href="authentication#the-signed-retry-patter
{
"type": "PASSKEY",
"payloadToSign": "Y2hhbGxlbmdlLXBheWxvYWQtdG8tc2lnbg==",
"requestId": "2b1e5a08-9c44-4e91-ae7f-6d0b3f8c1e22",
"requestId": "Request:2b1e5a08-9c44-4e91-ae7f-6d0b3f8c1e22",
"expiresAt": "2026-04-19T12:10:00Z"
}
```
Expand All @@ -66,7 +66,7 @@ Session revocation uses the same <a href="authentication#the-signed-retry-patter
curl -X DELETE "$GRID_BASE_URL/auth/sessions/Session:019542f5-b3e7-1d02-0000-000000000003" \
-u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \
-H "Grid-Wallet-Signature: MEUCIQDx7k2N0aK4p8f3vR9J6yT5wL1mB0sXnG2hQ4vJ8zYkCgIgZ4rP9dT7eWfU3oM6KjR1qSpNvBwL0tXyA2iG8fH5dE=" \
-H "Request-Id: 2b1e5a08-9c44-4e91-ae7f-6d0b3f8c1e22"
-H "Request-Id: Request:2b1e5a08-9c44-4e91-ae7f-6d0b3f8c1e22"
```

**Response:** `204 No Content`.
Expand Down
4 changes: 2 additions & 2 deletions mintlify/snippets/global-accounts/walkthrough.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ The customer has an outstanding quote with a `payloadToSign`. Now we need a sess
"createdAt": "2026-04-19T12:00:01Z",
"updatedAt": "2026-04-19T12:05:00Z",
"challenge": "VjZ6o8KfE9V3q3LkR2nH5eZ6dM8yA1xW",
"requestId": "7c4a8d09-ca37-4e3e-9e0d-8c2b3e9a1f21",
"requestId": "Request:7c4a8d09-ca37-4e3e-9e0d-8c2b3e9a1f21",
"expiresAt": "2026-04-19T12:10:00Z"
}
```
Expand Down Expand Up @@ -295,7 +295,7 @@ The customer has an outstanding quote with a `payloadToSign`. Now we need a sess
curl -X POST "$GRID_BASE_URL/auth/credentials/AuthMethod:019542f5-b3e7-1d02-0000-000000000001/verify" \
-u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \
-H "Content-Type: application/json" \
-H "Request-Id: 7c4a8d09-ca37-4e3e-9e0d-8c2b3e9a1f21" \
-H "Request-Id: Request:7c4a8d09-ca37-4e3e-9e0d-8c2b3e9a1f21" \
-d '{
"type": "PASSKEY",
"assertion": {
Expand Down
7 changes: 4 additions & 3 deletions mintlify/snippets/sandbox-global-account-magic.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Pass `000000` as the body `otp` on `POST /auth/credentials/{id}/verify` when the
curl -X POST https://api.lightspark.com/grid/2025-10-13/auth/credentials/AuthMethod:abc123/verify \
-u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \
-H "Content-Type: application/json" \
-H "Request-Id: 7c4a8d09-ca37-4e3e-9e0d-8c2b3e9a1f21" \
-H "Request-Id: Request:7c4a8d09-ca37-4e3e-9e0d-8c2b3e9a1f21" \
-d '{
"type": "EMAIL_OTP",
"otp": "000000",
Expand Down Expand Up @@ -39,7 +39,7 @@ curl -X POST https://api.lightspark.com/grid/2025-10-13/auth/credentials/AuthMet
curl -X POST https://api.lightspark.com/grid/2025-10-13/auth/credentials/AuthMethod:abc123/verify \
-u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \
-H "Content-Type: application/json" \
-H "Request-Id: 7c4a8d09-ca37-4e3e-9e0d-8c2b3e9a1f21" \
-H "Request-Id: Request:7c4a8d09-ca37-4e3e-9e0d-8c2b3e9a1f21" \
-d '{
"type": "PASSKEY",
"assertion": {
Expand All @@ -61,7 +61,7 @@ Pass `sandbox-valid-oidc-token` as the body `oidcToken` on both `POST /auth/cred
curl -X POST https://api.lightspark.com/grid/2025-10-13/auth/credentials/AuthMethod:abc123/verify \
-u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \
-H "Content-Type: application/json" \
-H "Request-Id: 7c4a8d09-ca37-4e3e-9e0d-8c2b3e9a1f21" \
-H "Request-Id: Request:7c4a8d09-ca37-4e3e-9e0d-8c2b3e9a1f21" \
-d '{
"type": "OAUTH",
"oidcToken": "sandbox-valid-oidc-token",
Expand All @@ -83,6 +83,7 @@ Pass `sandbox-valid-signature` as the `Grid-Wallet-Signature` HTTP header on any
- `DELETE /auth/credentials/{id}` (revoke credential)
- `DELETE /auth/sessions/{id}` (revoke session)
- `POST /internal-accounts/{id}/export` (export wallet)
- `PATCH /internal-accounts/{id}` (update wallet privacy)
- `POST /quotes/{quoteId}/execute` (when source is an embedded wallet)

```bash
Expand Down
Loading
Loading