Skip to main content
POST
/
auth
/
credentials
/
{id}
/
verify
cURL
curl --request POST \
  --url https://api.lightspark.com/grid/2025-10-13/auth/credentials/{id}/verify \
  --header 'Authorization: Basic <encoded-value>' \
  --header 'Content-Type: application/json' \
  --data '
{
  "type": "EMAIL_OTP",
  "encryptedOtpBundle": "{\"encappedPublic\":\"044f631a2d890bc6668d997ee184e190650d06adf970987568ec641214a00403b73effe1ef406c60a5cde8508a4484567ddb8056fbd493bee614cd727aef02a838\",\"ciphertext\":\"1fa1023390a56539aa48cbb380aa28f544ed5cc04861566bb806e25ba026f14660eaf4140a05b388dd012eaa899759a6a92576cdca8c1b7d12e147bd96cc26ed9f74886794155d8ac5cf0fdc\"}"
}
'
{
  "id": "Session:019542f5-b3e7-1d02-0000-000000000003",
  "accountId": "InternalAccount:019542f5-b3e7-1d02-0000-000000000002",
  "nickname": "example@lightspark.com",
  "createdAt": "2026-04-08T15:30:01Z",
  "updatedAt": "2026-04-08T15:35:00Z",
  "expiresAt": "2026-04-09T15:30:01Z",
  "credentialId": "KEbWNCc7NgaYnUyrNeFGX9_3Y-8oJ3KwzjnaiD1d1LVTxR7v3CaKfCz2Vy_g_MHSh7yJ8yL0Pxg6jo_o0hYiew",
  "encryptedSessionSigningKey": "w99a5xV6A75TfoAUkZn869fVyDYvgVsKrawMALZXmrauZd8hEv66EkPU1Z42CUaHESQjcA5bqd8dynTGBMLWB9ewtXWPEVbZvocB4Tw2K1vQVp7uwjf"
}

Authorizations

Authorization
string
header
required

API token authentication using format <api token id>:<api client secret>

Headers

Grid-Wallet-Signature
string

Full API-key stamp built over the prior payloadToSign with the TEK (Target Encryption Key) keypair the client generated for this login. Required on the signed retry that completes an EMAIL_OTP verification. Not used by OAUTH or PASSKEY verification, which complete in a single call.

Request-Id
string

The requestId returned in a prior 202 response from this endpoint, echoed back exactly here so the server can correlate the signed retry with the issued challenge. Required on the signed retry that completes an EMAIL_OTP verification; must be paired with Grid-Wallet-Signature. For PASSKEY verification, the requestId issued from POST /auth/credentials/{id}/challenge is echoed here instead so the server can correlate the assertion with the pending challenge.

Path Parameters

id
string
required

The id of the authentication credential to verify (the id field of the AuthMethod returned from POST /auth/credentials).

Body

application/json

Verify an email-OTP credential via the secure two-leg flow. The client HPKE-encrypts the OTP code (together with its public key) under the otpEncryptionTargetBundle returned from the credential's registration or POST /auth/credentials/{id}/challenge, submits the result here, and receives 202 with a payloadToSign carrying a verificationToken bound to the client's public key. The client signs that token with the matching private key and retries this request with Grid-Wallet-Signature + Request-Id headers to obtain the session. Plaintext OTP codes are never sent over the wire.

type
enum<string>
required

Discriminator value identifying this as an email OTP verification.

Available options:
EMAIL_OTP
encryptedOtpBundle
string
required

HPKE-sealed OTP attempt — the OTP code never reaches Grid in plaintext. The client generates a fresh ephemeral P-256 key pair (the session signing key pair it keeps once login completes), HPKE-encrypts {otp_code, public_key} (the code the user entered plus that key pair's public key) to the key in otpEncryptionTargetBundle, and submits the encrypted result here. The value is the {encappedPublic, ciphertext} JSON an HPKE library produces; the Global Accounts client-keys guide has a worked example.

On success the response is 202 with a payloadToSign carrying a verificationToken bound to the public key sealed in this bundle. Sign that token with the matching private key, then retry this request with the full stamp in Grid-Wallet-Signature and the requestId in Request-Id to complete the flow and receive the session. The client keeps that private key as the session signing key, and its public key becomes the session API key.

Example:

"{\"encappedPublic\":\"044f631a2d890bc6668d997ee184e190650d06adf970987568ec641214a00403b73effe1ef406c60a5cde8508a4484567ddb8056fbd493bee614cd727aef02a838\",\"ciphertext\":\"1fa1023390a56539aa48cbb380aa28f544ed5cc04861566bb806e25ba026f14660eaf4140a05b388dd012eaa899759a6a92576cdca8c1b7d12e147bd96cc26ed9f74886794155d8ac5cf0fdc\"}"

Response

Authentication credential verified and session issued

An authentication session on an Embedded Wallet internal account. Returned from GET /auth/sessions (list) and POST /auth/credentials/{id}/verify (on credential verification) or POST /auth/sessions/{id}/refresh (on mid-session refresh). Only session-issuing responses include encryptedSessionSigningKey — it is delivered exactly once at the moment the session is issued and is never returned by the list endpoint.

id
string
required

System-generated unique identifier for the session. Pass this value to DELETE /auth/sessions/{id} to revoke the session before expiresAt. Overrides the id inherited from AuthMethod so this response identifies the session rather than the authenticating credential.

Example:

"Session:019542f5-b3e7-1d02-0000-000000000003"

accountId
string
required

Identifier of the internal account that this credential authenticates.

Example:

"InternalAccount:019542f5-b3e7-1d02-0000-000000000002"

type
enum<string>
required

The type of authentication credential.

  • OAUTH: OpenID Connect (OIDC) token issued by an identity provider such as Google or Apple.
  • EMAIL_OTP: A one-time password delivered to the user's email address.
  • PASSKEY: A WebAuthn passkey bound to the user's device.
Available options:
OAUTH,
EMAIL_OTP,
PASSKEY
nickname
string
required

Human-readable identifier for this credential. For EMAIL_OTP credentials this is the email address; for OAUTH credentials it is typically the email claim from the OIDC token; for PASSKEY credentials it is the validated nickname provided at registration time.

Example:

"example@lightspark.com"

createdAt
string<date-time>
required

Creation timestamp.

Example:

"2026-04-08T15:30:01Z"

updatedAt
string<date-time>
required

Last update timestamp.

Example:

"2026-04-08T15:35:00Z"

expiresAt
string<date-time>
required

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"

credentialId
string

Base64url-encoded WebAuthn credential identifier for this passkey. Present only for PASSKEY authentication credentials. Corresponds to PublicKeyCredential.rawId; pass this value as allowCredentials[].id when requesting a passkey assertion for this auth method.

Example:

"KEbWNCc7NgaYnUyrNeFGX9_3Y-8oJ3KwzjnaiD1d1LVTxR7v3CaKfCz2Vy_g_MHSh7yJ8yL0Pxg6jo_o0hYiew"

encryptedSessionSigningKey
string

HPKE-encrypted session signing key, sealed to the clientPublicKey supplied on the verification or refresh request. Encoded as a base58check string: the decoded payload is a 33-byte compressed P-256 encapsulated public key followed by AES-256-GCM ciphertext. The client decrypts this key with its private key and uses it to sign subsequent Embedded Wallet requests until expiresAt.

Returned only by session-issuing responses for OAUTH and PASSKEY credentials. EMAIL_OTP sessions omit this field — the client generates a TEK keypair before verification and retains the private key throughout, so the server has nothing to deliver. Always omitted from list responses (GET /auth/sessions) since Grid does not retain the plaintext key after the client has decrypted it.

Example:

"w99a5xV6A75TfoAUkZn869fVyDYvgVsKrawMALZXmrauZd8hEv66EkPU1Z42CUaHESQjcA5bqd8dynTGBMLWB9ewtXWPEVbZvocB4Tw2K1vQVp7uwjf"