From 99200498242df831a4a06b9e3a76158f190b9a22 Mon Sep 17 00:00:00 2001 From: Peng Ying Date: Mon, 27 Apr 2026 17:41:34 -0700 Subject: [PATCH 1/3] docs: document Global Account sandbox magic values Adds a new shared snippet listing the four sandbox magic values that unblock the embedded-wallet auth flows without real Turnkey/WebAuthn/ OIDC plumbing, and wires it into the four product-area sandbox-testing pages (payouts-and-b2b, ramps, rewards, global-p2p): | Value | Where it goes | Used by | |------------------------------------|----------------------------------------------|----------------------------------------------------------------| | 000000 | request body otp | POST /auth/credentials/{id}/verify (EMAIL_OTP) | | sandbox-valid-oidc-token | request body oidcToken | POST /auth/credentials (OAUTH create) and verify (OAUTH) | | sandbox-valid-passkey-signature | request body assertion.signature | POST /auth/credentials/{id}/verify (PASSKEY) | | sandbox-valid-signature | HTTP header Grid-Wallet-Signature | All signed-retry flows + /quotes/{id}/execute on EMBEDDED_WALLET | Includes integrator notes on JWT-shape requirement for OAUTH create, the 401 error responses on a wrong magic value, that these are sandbox-only, and that clientPublicKey is still required on every verify (magic values bypass credential checks, not HPKE plumbing). Co-Authored-By: Claude Opus 4.7 (1M context) --- .../global-p2p/platform-tools/sandbox-testing.mdx | 7 +++++++ .../platform-tools/sandbox-testing.mdx | 5 +++++ mintlify/ramps/platform-tools/sandbox-testing.mdx | 5 +++++ .../rewards/platform-tools/sandbox-testing.mdx | 6 ++++++ .../snippets/sandbox-global-account-magic.mdx | 15 +++++++++++++++ 5 files changed, 38 insertions(+) create mode 100644 mintlify/snippets/sandbox-global-account-magic.mdx diff --git a/mintlify/global-p2p/platform-tools/sandbox-testing.mdx b/mintlify/global-p2p/platform-tools/sandbox-testing.mdx index ef159f09..ae1a6967 100644 --- a/mintlify/global-p2p/platform-tools/sandbox-testing.mdx +++ b/mintlify/global-p2p/platform-tools/sandbox-testing.mdx @@ -3,6 +3,9 @@ title: "Sandbox Testing" icon: "/images/icons/hammer.svg" "og:image": "/images/og/og-global-p2p.png" --- + +import SandboxGlobalAccountMagic from '/snippets/sandbox-global-account-magic.mdx'; + The Grid sandbox environment allows you to test your integration without making real payments. When you set up your account, you can configure production and sandbox API tokens. The sandbox token is specifically for testing and development purposes. It corresponds to a separate platform instance in "sandbox" mode, which can only transact with the sandbox UMA addresses for testing. @@ -224,6 +227,10 @@ curl -X GET "https://api.lightspark.com/grid/2025-10-13/receiver/\$non.existent. Each of these will trigger appropriate error webhooks and status updates to help you test your error handling. +## Global Account magic values + + + ## Production vs Sandbox Here are the key differences between production and sandbox environments: diff --git a/mintlify/payouts-and-b2b/platform-tools/sandbox-testing.mdx b/mintlify/payouts-and-b2b/platform-tools/sandbox-testing.mdx index 3e415f27..eb5cdd4c 100644 --- a/mintlify/payouts-and-b2b/platform-tools/sandbox-testing.mdx +++ b/mintlify/payouts-and-b2b/platform-tools/sandbox-testing.mdx @@ -9,6 +9,7 @@ import SandboxBeneficiaryVerification from '/snippets/sandbox-beneficiary-verifi import SandboxExternalAccounts from '/snippets/sandbox-external-accounts.mdx'; import SandboxTransferPatterns from '/snippets/sandbox-transfer-patterns.mdx'; import SandboxQuotePatterns from '/snippets/sandbox-quote-patterns.mdx'; +import SandboxGlobalAccountMagic from '/snippets/sandbox-global-account-magic.mdx'; ## Overview @@ -249,6 +250,10 @@ GET /transactions/{transactionId} # Wait 30s, check again - will show FAILED ``` +## Global Account magic values + + + ## Sandbox Limitations While sandbox closely mimics production, there are some differences: diff --git a/mintlify/ramps/platform-tools/sandbox-testing.mdx b/mintlify/ramps/platform-tools/sandbox-testing.mdx index 16fff472..1a878952 100644 --- a/mintlify/ramps/platform-tools/sandbox-testing.mdx +++ b/mintlify/ramps/platform-tools/sandbox-testing.mdx @@ -8,6 +8,7 @@ icon: "/images/icons/hammer.svg" import SandboxBeneficiaryVerification from '/snippets/sandbox-beneficiary-verification.mdx'; import SandboxExternalAccounts from '/snippets/sandbox-external-accounts.mdx'; import SandboxTransferPatterns from '/snippets/sandbox-transfer-patterns.mdx'; +import SandboxGlobalAccountMagic from '/snippets/sandbox-global-account-magic.mdx'; The Grid Sandbox environment provides a complete testing environment for ramp operations, allowing you to validate on-ramp and off-ramp flows without using real money or cryptocurrency. @@ -371,6 +372,10 @@ curl -X POST 'https://api.lightspark.com/grid/2025-10-13/customers/external-acco # Response: 400 Bad Request with validation error ``` +## Global Account magic values + + + ## Moving to Production When you're ready to move to production: diff --git a/mintlify/rewards/platform-tools/sandbox-testing.mdx b/mintlify/rewards/platform-tools/sandbox-testing.mdx index d8013819..b83f588d 100644 --- a/mintlify/rewards/platform-tools/sandbox-testing.mdx +++ b/mintlify/rewards/platform-tools/sandbox-testing.mdx @@ -5,6 +5,8 @@ icon: "/images/icons/hammer.svg" "og:image": "/images/og/og-rewards.png" --- +import SandboxGlobalAccountMagic from '/snippets/sandbox-global-account-magic.mdx'; + ## Overview The Grid sandbox environment allows you to test your rewards integration without moving real money or cryptocurrency. All API endpoints work the same way in sandbox as they do in production, but transactions are simulated and you can control test scenarios using special test values. @@ -322,6 +324,10 @@ curl -X POST "https://api.lightspark.com/grid/2025-10-13/quotes" \ # Wait 30s, check again - will show FAILED ``` +## Global Account magic values + + + ## Sandbox Limitations While sandbox closely mimics production, there are some differences: diff --git a/mintlify/snippets/sandbox-global-account-magic.mdx b/mintlify/snippets/sandbox-global-account-magic.mdx new file mode 100644 index 00000000..4e078f44 --- /dev/null +++ b/mintlify/snippets/sandbox-global-account-magic.mdx @@ -0,0 +1,15 @@ +The Grid sandbox accepts four magic values that bypass real auth and credential checks for Global Account flows. Each one is scoped to a specific request location, so the sandbox can recognize and accept it without any other call-site changes. + +| Magic value | Where it goes | Used by | +|---|---|---| +| `000000` | Request body `otp` field | `POST /auth/credentials/{id}/verify` (when `type: EMAIL_OTP`) | +| `sandbox-valid-oidc-token` | Request body `oidcToken` field | `POST /auth/credentials` (`type: OAUTH` create) and `POST /auth/credentials/{id}/verify` (`type: OAUTH`) | +| `sandbox-valid-passkey-signature` | Request body `assertion.signature` field | `POST /auth/credentials/{id}/verify` (`type: PASSKEY`) | +| `sandbox-valid-signature` | HTTP header `Grid-Wallet-Signature` | All signed-retry flows: `POST /auth/credentials` (add-additional-credential signed retry), `DELETE /auth/credentials/{id}` (revoke credential), `DELETE /auth/sessions/{id}` (revoke session), `POST /internal-accounts/{id}/export` (export wallet), and `POST /quotes/{quoteId}/execute` when the source is an embedded wallet | + + + - **OAUTH create still requires a JWT-shaped token.** `sandbox-valid-oidc-token` is accepted by `verify` without IdP validation, but the initial `POST /auth/credentials` (OAUTH create) requires the `oidcToken` to be a structurally valid JWT (`header.payload.signature`) so Grid can decode the `iss` claim to resolve the provider name. The sandbox token bypasses signature verification, not JWT structure parsing. + - **Wrong magic value** returns `401 UNAUTHORIZED` with a specific reason: `Invalid OTP code`, `Invalid OIDC token`, `Invalid passkey signature`, or `Invalid Grid-Wallet-Signature`. + - **Sandbox-only.** Production enforces real Turnkey signature verification, WebAuthn assertion, and OIDC nonce binding — the magic values don't apply. + - **Bring your own `clientPublicKey`** on every `verify` call and on PASSKEY rechallenge. Magic values bypass credential checks, not the HPKE encryption-key plumbing — sessions are still sealed to the public key the integrator supplies. + From 500045d7fc6b9257d8e330ffea726bdd9eee8d79 Mon Sep 17 00:00:00 2001 From: Peng Ying Date: Mon, 27 Apr 2026 17:52:28 -0700 Subject: [PATCH 2/3] docs: include Global Account sandbox magic values on api-reference page Co-Authored-By: Claude Opus 4.7 (1M context) --- mintlify/api-reference/sandbox-testing.mdx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mintlify/api-reference/sandbox-testing.mdx b/mintlify/api-reference/sandbox-testing.mdx index 9313ecd8..d73d723b 100644 --- a/mintlify/api-reference/sandbox-testing.mdx +++ b/mintlify/api-reference/sandbox-testing.mdx @@ -11,6 +11,7 @@ import SandboxTransferPatterns from '/snippets/sandbox-transfer-patterns.mdx'; import SandboxQuotePatterns from '/snippets/sandbox-quote-patterns.mdx'; import SandboxUmaAddresses from '/snippets/sandbox-uma-addresses.mdx'; import SandboxKybVerification from '/snippets/sandbox-kyb-verification.mdx'; +import SandboxGlobalAccountMagic from '/snippets/sandbox-global-account-magic.mdx'; The Grid sandbox environment simulates real payment flows without moving real money. You can control test outcomes using special account number patterns and test addresses. @@ -97,3 +98,7 @@ curl -X POST https://api.lightspark.com/grid/2025-10-13/sandbox/uma/receive \ "receivingCurrencyAmount": 5000 }' ``` + +## Global Account magic values + + From b1c65d6b0f6ed9d00d80f601b0524e3bf75edd2e Mon Sep 17 00:00:00 2001 From: Peng Ying Date: Mon, 27 Apr 2026 17:57:35 -0700 Subject: [PATCH 3/3] docs: restructure Global Account magic values by auth flow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Splits the single magic-values table into four flow-keyed sections — email OTP, passkey assertion, OAuth (OIDC) token, and Grid-Wallet-Signature header — to match the look and feel of the api-reference sandbox-testing page (each section is a curl example, the field placement, and the specific 401 reason on a wrong value). Inlines the relevant integrator notes per section instead of stacking them in a closing block: - OAUTH create JWT-structure caveat lives in the OAuth section - clientPublicKey reminder lives in the Passkey section (it applies to any verify call but is most surprising for passkey users) - The "sandbox-only / production enforces real verification" framing is now the lead-in instead of a trailing bullet Co-Authored-By: Claude Opus 4.7 (1M context) --- .../snippets/sandbox-global-account-magic.mdx | 93 ++++++++++++++++--- 1 file changed, 82 insertions(+), 11 deletions(-) diff --git a/mintlify/snippets/sandbox-global-account-magic.mdx b/mintlify/snippets/sandbox-global-account-magic.mdx index 4e078f44..e014e2a5 100644 --- a/mintlify/snippets/sandbox-global-account-magic.mdx +++ b/mintlify/snippets/sandbox-global-account-magic.mdx @@ -1,15 +1,86 @@ -The Grid sandbox accepts four magic values that bypass real auth and credential checks for Global Account flows. Each one is scoped to a specific request location, so the sandbox can recognize and accept it without any other call-site changes. +The Grid sandbox accepts a small set of magic values that bypass real auth and credential checks for Global Account flows, so you can exercise the full request shape without standing up Turnkey, WebAuthn, or an OIDC provider. These values are sandbox-only — production enforces real signature verification, WebAuthn assertion, and OIDC nonce binding. -| Magic value | Where it goes | Used by | -|---|---|---| -| `000000` | Request body `otp` field | `POST /auth/credentials/{id}/verify` (when `type: EMAIL_OTP`) | -| `sandbox-valid-oidc-token` | Request body `oidcToken` field | `POST /auth/credentials` (`type: OAUTH` create) and `POST /auth/credentials/{id}/verify` (`type: OAUTH`) | -| `sandbox-valid-passkey-signature` | Request body `assertion.signature` field | `POST /auth/credentials/{id}/verify` (`type: PASSKEY`) | -| `sandbox-valid-signature` | HTTP header `Grid-Wallet-Signature` | All signed-retry flows: `POST /auth/credentials` (add-additional-credential signed retry), `DELETE /auth/credentials/{id}` (revoke credential), `DELETE /auth/sessions/{id}` (revoke session), `POST /internal-accounts/{id}/export` (export wallet), and `POST /quotes/{quoteId}/execute` when the source is an embedded wallet | +A wrong magic value (or any other value) returns `401 UNAUTHORIZED` with a `reason` field that names the specific check that failed. + +### Email OTP code + +Pass `000000` as the body `otp` on `POST /auth/credentials/{id}/verify` when the credential type is `EMAIL_OTP`. The sandbox skips OTP delivery and accepts this value as a valid response to the issued challenge. + +```bash +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" \ + -d '{ + "type": "EMAIL_OTP", + "otp": "000000", + "clientPublicKey": "04f45f2a..." + }' +``` + +Any other code returns `401 UNAUTHORIZED` with `reason: "Invalid OTP code"`. + +### Passkey assertion signature + +Pass `sandbox-valid-passkey-signature` as `assertion.signature` on `POST /auth/credentials/{id}/verify` when the credential type is `PASSKEY`. The sandbox accepts the rest of the assertion as-is and skips the WebAuthn signature check. + +```bash +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" \ + -d '{ + "type": "PASSKEY", + "assertion": { + "credentialId": "...", + "clientDataJson": "...", + "authenticatorData": "...", + "signature": "sandbox-valid-passkey-signature" + }, + "clientPublicKey": "04f45f2a..." + }' +``` + +Any other signature returns `401 UNAUTHORIZED` with `reason: "Invalid passkey signature"`. `clientPublicKey` is still required — the magic value bypasses the credential check, not the HPKE plumbing that seals the session signing key to the public key you supply. + +### OAuth (OIDC) token + +Pass `sandbox-valid-oidc-token` as the body `oidcToken` on both `POST /auth/credentials` (OAUTH create) and `POST /auth/credentials/{id}/verify` (OAUTH). + +```bash +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" \ + -d '{ + "type": "OAUTH", + "oidcToken": "sandbox-valid-oidc-token", + "clientPublicKey": "04f45f2a..." + }' +``` + +Any other token returns `401 UNAUTHORIZED` with `reason: "Invalid OIDC token"`. - - **OAUTH create still requires a JWT-shaped token.** `sandbox-valid-oidc-token` is accepted by `verify` without IdP validation, but the initial `POST /auth/credentials` (OAUTH create) requires the `oidcToken` to be a structurally valid JWT (`header.payload.signature`) so Grid can decode the `iss` claim to resolve the provider name. The sandbox token bypasses signature verification, not JWT structure parsing. - - **Wrong magic value** returns `401 UNAUTHORIZED` with a specific reason: `Invalid OTP code`, `Invalid OIDC token`, `Invalid passkey signature`, or `Invalid Grid-Wallet-Signature`. - - **Sandbox-only.** Production enforces real Turnkey signature verification, WebAuthn assertion, and OIDC nonce binding — the magic values don't apply. - - **Bring your own `clientPublicKey`** on every `verify` call and on PASSKEY rechallenge. Magic values bypass credential checks, not the HPKE encryption-key plumbing — sessions are still sealed to the public key the integrator supplies. + **OAUTH create still requires a JWT-shaped token.** On the initial `POST /auth/credentials` (OAUTH create), the `oidcToken` must be a structurally valid JWT (`header.payload.signature`) so Grid can decode the `iss` claim and resolve the provider name. The literal `sandbox-valid-oidc-token` works on `verify` but not on `create` — for `create`, sign your own dummy JWT with any payload that includes a recognized `iss` claim. The sandbox bypasses signature verification, not JWT structure parsing. + +### Wallet signature header + +Pass `sandbox-valid-signature` as the `Grid-Wallet-Signature` HTTP header on any signed-retry flow: + +- `POST /auth/credentials` (add-additional-credential signed retry) +- `DELETE /auth/credentials/{id}` (revoke credential) +- `DELETE /auth/sessions/{id}` (revoke session) +- `POST /internal-accounts/{id}/export` (export wallet) +- `POST /quotes/{quoteId}/execute` (when source is an embedded wallet) + +```bash +curl -X POST https://api.lightspark.com/grid/2025-10-13/quotes/Quote:abc123/execute \ + -u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \ + -H "Content-Type: application/json" \ + -H "Idempotency-Key: 7c4a8d09-ca37-4e3e-9e0d-8c2b3e9a1f21" \ + -H "Grid-Wallet-Signature: sandbox-valid-signature" +``` + +Any other header value returns `401 UNAUTHORIZED` with `reason: "Invalid Grid-Wallet-Signature"`.