> ## Documentation Index
> Fetch the complete documentation index at: https://developers.squads.so/llms.txt
> Use this file to discover all available pages before exploring further.

# Verify OTP

> Verify the OTP code sent to the email address and obtain authentication for existing account

This endpoint verifies the OTP received via email for an existing Grid Account and returns authentication credentials for API access.

<Warning>
  Using the Grid API directly requires **advanced configurations**. Grid SDK is
  the recommended way to authenticate accounts. It handles authentication, key
  management, automatic failover, and transaction signing. Learn more about the
  Grid SDK in the [Grid SDK](/grid/v1/sdk-reference) guide.
</Warning>

<Info>
  This endpoint is for authenticating existing Grid Accounts. For new account
  creation, use the [Create
  Account](/grid/v1/api-reference/endpoint/account-management/post) endpoint
  followed by account verification.
</Info>

### Authentication Flow

1. **Request OTP**: Call [Initiate Authentication](/grid/v1/api-reference/endpoint/authentication/post) with email address
2. **Generate HPKE Keypair**: Create client-side HPKE keys using P-256 curve while waiting for OTP
3. **Verify OTP**: Use this endpoint to verify the received OTP code with HPKE public key
4. **Use Credentials**: Utilize returned authentication tokens for API access

### OTP Limits

* **Attempts**: Maximum 3 verification attempts per OTP
* **Expiration**: 15-minute window from OTP generation
* **Retry**: Must request new OTP if limits exceeded

### Required Configuration

When using Privy as the authentication provider (default), you must include a `kms_provider_config` with your HPKE public key to receive encrypted authorization keys. This enables secure transaction signing for your Grid Account.

## Complete Implementation Guide

For comprehensive implementation details including:

* **kms\_provider\_config creation**
* **HPKE keypair generation** with P-256 curve and DER formatting
* **Authorization key decryption** using ECDH + HKDF + ChaCha20-Poly1305
* **Transaction payload signing** with JSON canonicalization
* **Error handling** and security best practices
* **Language-agnostic examples**

See the [Primary Provider Integration](/grid/v1/api-reference/advanced/privy-signing) guide.

### Response Data

Upon successful verification, you receive:

* **Authentication tokens** for API access
* **Account information** including Grid Account address
* **Session credentials** for subsequent API calls

The authentication session remains valid until expiration, allowing you to make authenticated requests to Grid API endpoints.


## OpenAPI

````yaml POST /api/grid/v1/auth/verify
openapi: 3.1.0
info:
  title: Grid v1 API
  description: Grid v1 REST API for Solana-based smart account system
  contact:
    name: Grid API Support
    url: https://squads.so
    email: support@squads.so
  license:
    name: MIT
  version: 1.0.0
servers:
  - url: https://grid.squads.xyz
    description: Production server
security:
  - bearer_auth: []
tags:
  - name: accounts
    description: Smart account management operations
  - name: spending-limits
    description: Spending limit management
  - name: standing-orders
    description: Standing order operations
  - name: transactions
    description: Transaction management
  - name: trade
    description: Trade operations and management
  - name: payments
    description: Payment intent operations
  - name: passkeys
    description: Passkey management
  - name: kyc
    description: Know Your Customer operations
  - name: external-accounts
    description: External bank account management
  - name: virtual-accounts
    description: Virtual account management
  - name: auth
    description: Authentication operations
  - name: proposals
    description: Proposal management for multi-sig operations
  - name: compliance
    description: Compliance entity management and KYB/KYC operations
paths:
  /api/grid/v1/auth/verify:
    post:
      tags:
        - auth
      summary: Verify OTP and complete authentication
      description: Complete the authentication process by verifying the OTP code
      operationId: handler
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AuthVerifyOtpRequestPayload'
        required: true
      responses:
        '200':
          description: Authentication successful
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AuthVerifyOtpResponsePayload'
        '400':
          description: Invalid OTP code
        '404':
          description: User not found
        '500':
          description: Internal server error
      security:
        - bearer_auth: []
components:
  schemas:
    AuthVerifyOtpRequestPayload:
      type: object
      required:
        - email
        - otp_code
        - kms_provider
        - kms_provider_config
      properties:
        email:
          type: string
        kms_provider:
          $ref: '#/components/schemas/GridMPCProvider'
        kms_provider_config:
          $ref: '#/components/schemas/KmsProviderConfig'
        otp_code:
          type: string
        smart_account_address:
          type:
            - string
            - 'null'
    AuthVerifyOtpResponsePayload:
      type: object
      required:
        - address
        - policies
        - grid_user_id
        - authentication
      properties:
        address:
          type: string
        authentication:
          type: array
          items:
            $ref: '#/components/schemas/AuthenticationProvider'
        grid_user_id:
          type: string
          format: uuid
        policies:
          $ref: '#/components/schemas/AccountPolicies'
    GridMPCProvider:
      type: string
      enum:
        - privy
        - dynamic
        - passkey
        - turnkey
        - external
    KmsProviderConfig:
      oneOf:
        - $ref: '#/components/schemas/TurnkeyKmsProviderConfig'
        - $ref: '#/components/schemas/PrivyKmsProviderConfig'
    AuthenticationProvider:
      type: object
      required:
        - provider
        - session
      properties:
        provider:
          $ref: '#/components/schemas/GridMPCProvider'
        session:
          $ref: '#/components/schemas/Session'
    AccountPolicies:
      type: object
      required:
        - signers
        - threshold
      properties:
        admin_address:
          type:
            - string
            - 'null'
        signers:
          type: array
          items:
            $ref: '#/components/schemas/AccountSigner'
        threshold:
          type: integer
          format: int32
          minimum: 0
        time_lock:
          type:
            - integer
            - 'null'
          format: int32
          minimum: 0
    TurnkeyKmsProviderConfig:
      type: object
      required:
        - encryption_public_key
        - otp_id
      properties:
        encryption_public_key:
          type: string
        otp_id:
          type: string
      additionalProperties: false
    PrivyKmsProviderConfig:
      type: object
      properties:
        encryption_public_key:
          type:
            - string
            - 'null'
      additionalProperties: false
    Session:
      oneOf:
        - type: object
          required:
            - Privy
          properties:
            Privy:
              $ref: '#/components/schemas/PrivySession'
        - type: object
          required:
            - Turnkey
          properties:
            Turnkey:
              $ref: '#/components/schemas/TurnkeySession'
        - type: object
          required:
            - Passkey
          properties:
            Passkey:
              $ref: '#/components/schemas/PasskeySession'
    AccountSigner:
      type: object
      required:
        - address
        - role
        - permissions
      properties:
        address:
          type: string
        permissions:
          type: array
          items:
            $ref: '#/components/schemas/Permission'
        provider:
          $ref: '#/components/schemas/GridMPCProvider'
        role:
          $ref: '#/components/schemas/GridSignerRole'
    PrivySession:
      type: object
      required:
        - user_id
        - session
        - token
        - privy_access_token
        - refresh_token
      properties:
        privy_access_token:
          type: string
        refresh_token:
          type: string
        session:
          $ref: '#/components/schemas/AuthenticateResponse'
        token:
          type: string
        user_id:
          type: string
    TurnkeySession:
      type: object
      required:
        - user_id
        - api_key_id
        - credential_bundle
      properties:
        api_key_id:
          type: string
        credential_bundle:
          type: string
        user_id:
          type: string
    PasskeySession:
      type: object
      required:
        - passkey_account
        - pubkey
        - relying_party_id
        - session_key
      properties:
        passkey_account:
          type: string
        pubkey:
          type: string
        relying_party_id:
          type: string
        session_key:
          $ref: '#/components/schemas/SessionKey'
    Permission:
      type: string
      enum:
        - CAN_INITIATE
        - CAN_VOTE
        - CAN_EXECUTE
    GridSignerRole:
      type: string
      enum:
        - primary
        - backup
    AuthenticateResponse:
      type: object
      required:
        - expires_at
        - wallets
      properties:
        authorization_key:
          type:
            - string
            - 'null'
        encrypted_authorization_key:
          oneOf:
            - type: 'null'
            - $ref: '#/components/schemas/EncryptedAuthorizationKey'
        expires_at:
          type: integer
          format: int64
          minimum: 0
        wallets:
          type: array
          items:
            $ref: '#/components/schemas/Wallet'
    SessionKey:
      type: object
      description: >-
        Grid v1 API SessionKey type that supports backward-compatible
        deserialization

        from both raw bytes array (old format) and base58 string (new format).

        Always serializes to base58 string format.
      required:
        - key
        - expiration
      properties:
        expiration:
          type: integer
          format: int64
          minimum: 0
        key:
          type: string
          example: '11111111111111111111111111111111'
    EncryptedAuthorizationKey:
      type: object
      required:
        - encryption_type
        - encapsulated_key
        - ciphertext
      properties:
        ciphertext:
          type: string
        encapsulated_key:
          type: string
        encryption_type:
          type: string
    Wallet:
      type: object
      required:
        - id
        - address
        - created_at
        - chain_type
        - policy_ids
        - additional_signers
      properties:
        additional_signers:
          type: array
          items:
            $ref: '#/components/schemas/AdditionalSigner'
        address:
          type: string
        chain_type:
          $ref: '#/components/schemas/WalletChainType'
        created_at:
          type: integer
          format: int64
          minimum: 0
        exported_at:
          type:
            - integer
            - 'null'
          format: int64
          minimum: 0
        id:
          type: string
        imported_at:
          type:
            - integer
            - 'null'
          format: int64
          minimum: 0
        owner_id:
          type:
            - string
            - 'null'
        policy_ids:
          type: array
          items:
            type: string
        public_key:
          type:
            - string
            - 'null'
    AdditionalSigner:
      type: object
      required:
        - signer_id
      properties:
        override_policy_ids:
          type: array
          items:
            type: string
          nullable: true
        signer_id:
          type: string
    WalletChainType:
      type: string
      enum:
        - solana
        - ethereum
        - cosmos
        - stellar
        - sui
        - tron
        - bitcoin-segwit
  securitySchemes:
    bearer_auth:
      type: http
      scheme: bearer
      description: Your Grid API key from the Grid Dashboard

````