> ## Documentation Index
> Fetch the complete documentation index at: https://ramps-04-30-docs-add-grid-tutorial-skill-interactive-zero-t.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Re-issue an authentication credential challenge

> Re-issue the challenge for an existing authentication credential.

For `EMAIL_OTP` credentials, this triggers a new one-time password email to the address on file. The response is a plain `AuthMethod`; there is no challenge body to surface because the OTP is delivered out-of-band via email. After the user receives the new OTP, call `POST /auth/credentials/{id}/verify` to complete verification and issue a session.

For `PASSKEY` credentials, this issues a fresh Grid-generated WebAuthn challenge for reauthentication. The request body must carry the client's ephemeral `clientPublicKey` so Grid can bake it into the Turnkey session-creation payload the returned challenge is computed from — this seals the resulting session signing key to the client. The response is a `PasskeyAuthChallenge` — the base `AuthMethod` fields plus the new `challenge`, `requestId`, and `expiresAt`. The client passes the `challenge` into `navigator.credentials.get()` and submits the resulting assertion to `POST /auth/credentials/{id}/verify` with `Request-Id: <requestId>` to receive a session.




## OpenAPI

````yaml https://app.stainless.com/api/spec/documented/grid/openapi.documented.yml post /auth/credentials/{id}/challenge
openapi: 3.1.0
info:
  title: Grid API
  description: >
    API for managing global payments on the open Money Grid. Built by
    Lightspark. See the full documentation at https://grid.lightspark.com/.
  version: '2025-10-13'
  contact:
    name: Lightspark Support
    email: support@lightspark.com
  license:
    name: Proprietary
    url: https://lightspark.com/terms
servers:
  - url: https://api.lightspark.com/grid/2025-10-13
    description: Production server
security:
  - BasicAuth: []
tags:
  - name: Platform Configuration
    description: >-
      Platform configuration endpoints for managing global settings. You can
      also configure these settings in the Grid dashboard.
  - name: Customers
    description: >-
      Customer management endpoints for creating and updating customer
      information
  - name: KYC/KYB Verifications
    description: >-
      Endpoints for Know Your Customer (KYC) and Know Your Business (KYB)
      verification, including managing beneficial owners and triggering
      verification for customers.
  - name: Documents
    description: >-
      Endpoints for uploading and managing verification documents for customers
      and beneficial owners. Supports KYC and KYB document requirements.
  - name: Internal Accounts
    description: >-
      Internal account management endpoints for creating and managing internal
      accounts
  - name: External Accounts
    description: >-
      External account management endpoints for creating and managing external
      bank accounts
  - name: Same-Currency Transfers
    description: >-
      Endpoints for transferring funds between internal and external accounts
      with the same currency
  - name: Cross-Currency Transfers
    description: Endpoints for creating and confirming quotes for cross-currency transfers
  - name: Transactions
    description: Endpoints for retrieving transaction information
  - name: Webhooks
    description: Webhook endpoints and configuration for receiving notifications
  - name: Invitations
    description: Endpoints for creating, claiming and managing UMA invitations
  - name: Sandbox
    description: Endpoints to trigger test cases in sandbox
  - name: API Tokens
    description: Endpoints to programmatically manage API tokens
  - name: Exchange Rates
    description: >-
      Endpoints for retrieving cached foreign exchange rates. Rates are cached
      for approximately 5 minutes and include platform-specific fees.
  - name: Discoveries
    description: >-
      Endpoints for discovering available payment rails, banks, and providers
      for a given country and currency corridor.
  - name: Embedded Wallet Auth
    description: >-
      Endpoints for registering and verifying end-user authentication
      credentials (email OTP, OAuth, passkey) used to sign Embedded Wallet
      actions.
paths:
  /auth/credentials/{id}/challenge:
    post:
      tags:
        - Embedded Wallet Auth
      summary: Re-issue an authentication credential challenge
      description: >
        Re-issue the challenge for an existing authentication credential.


        For `EMAIL_OTP` credentials, this triggers a new one-time password email
        to the address on file. The response is a plain `AuthMethod`; there is
        no challenge body to surface because the OTP is delivered out-of-band
        via email. After the user receives the new OTP, call `POST
        /auth/credentials/{id}/verify` to complete verification and issue a
        session.


        For `PASSKEY` credentials, this issues a fresh Grid-generated WebAuthn
        challenge for reauthentication. The request body must carry the client's
        ephemeral `clientPublicKey` so Grid can bake it into the Turnkey
        session-creation payload the returned challenge is computed from — this
        seals the resulting session signing key to the client. The response is a
        `PasskeyAuthChallenge` — the base `AuthMethod` fields plus the new
        `challenge`, `requestId`, and `expiresAt`. The client passes the
        `challenge` into `navigator.credentials.get()` and submits the resulting
        assertion to `POST /auth/credentials/{id}/verify` with `Request-Id:
        <requestId>` to receive a session.
      operationId: challengeAuthCredential
      parameters:
        - name: id
          in: path
          description: >-
            The id of the authentication credential to re-challenge (the `id`
            field of the `AuthMethod` returned from `POST /auth/credentials`).
          required: true
          schema:
            type: string
      requestBody:
        description: >-
          Request body. Required when re-challenging a `PASSKEY` credential
          (must carry `clientPublicKey`). Ignored for `EMAIL_OTP` and `OAUTH`,
          where the credential type alone is sufficient — the OTP is delivered
          out-of-band (EMAIL_OTP) or there is no server-side challenge (OAUTH).
        required: false
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AuthCredentialChallengeRequest'
            examples:
              passkey:
                summary: Re-challenge a passkey credential
                value:
                  clientPublicKey: >-
                    04f45f2a22c908b9ce09a7150e514afd24627c401c38a4afc164e1ea783adaaa31d4245acfb88c2ebd42b47628d63ecabf345484f0a9f665b63c54c897d5578be2
              emailOtpOrOauth:
                summary: Re-challenge an email-OTP or OAuth credential (empty body)
                value: {}
      responses:
        '200':
          description: >-
            Challenge re-issued for the authentication credential. For
            `EMAIL_OTP` the body is a plain `AuthMethod` and a new OTP email has
            been sent. For `PASSKEY` the body is a `PasskeyAuthChallenge`
            carrying the freshly issued `challenge`, `requestId`, and
            `expiresAt` required to complete reauthentication via `POST
            /auth/credentials/{id}/verify`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AuthCredentialResponseOneOf'
              examples:
                emailOtp:
                  summary: Email OTP challenge re-issued
                  value:
                    id: AuthMethod:019542f5-b3e7-1d02-0000-000000000001
                    accountId: InternalAccount:019542f5-b3e7-1d02-0000-000000000002
                    type: EMAIL_OTP
                    nickname: example@lightspark.com
                    createdAt: '2026-04-08T15:30:01Z'
                    updatedAt: '2026-04-08T15:35:00Z'
                passkey:
                  summary: Passkey reauthentication challenge issued
                  value:
                    id: AuthMethod:019542f5-b3e7-1d02-0000-000000000001
                    accountId: InternalAccount:019542f5-b3e7-1d02-0000-000000000002
                    type: PASSKEY
                    nickname: iPhone Face-ID
                    createdAt: '2026-04-08T15:30:01Z'
                    updatedAt: '2026-04-08T15:35:00Z'
                    challenge: VjZ6o8KfE9V3q3LkR2nH5eZ6dM8yA1xW
                    requestId: 7c4a8d09-ca37-4e3e-9e0d-8c2b3e9a1f21
                    expiresAt: '2026-04-08T15:35:00Z'
        '400':
          description: Bad request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error400'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error401'
        '404':
          description: Authentication credential not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error404'
        '429':
          description: >-
            Too many requests. Returned with `RATE_LIMITED` when challenge
            re-issues are requested more frequently than the OTP rate limit
            allows. 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:
            application/json:
              schema:
                $ref: '#/components/schemas/Error500'
      security:
        - BasicAuth: []
      x-codeSamples:
        - lang: JavaScript
          source: >-
            import LightsparkGrid from '@lightsparkdev/grid';


            const client = new LightsparkGrid({
              username: process.env['GRID_CLIENT_ID'], // This is the default and can be omitted
              password: process.env['GRID_CLIENT_SECRET'], // This is the default and can be omitted
            });


            const response = await client.auth.credentials.resendChallenge('id',
            {
              clientPublicKey:
                '04f45f2a22c908b9ce09a7150e514afd24627c401c38a4afc164e1ea783adaaa31d4245acfb88c2ebd42b47628d63ecabf345484f0a9f665b63c54c897d5578be2',
            });


            console.log(response);
        - lang: Python
          source: |-
            import os
            from grid import LightsparkGrid

            client = LightsparkGrid(
                username=os.environ.get("GRID_CLIENT_ID"),  # This is the default and can be omitted
                password=os.environ.get("GRID_CLIENT_SECRET"),  # This is the default and can be omitted
            )
            response = client.auth.credentials.resend_challenge(
                id="id",
                client_public_key="04f45f2a22c908b9ce09a7150e514afd24627c401c38a4afc164e1ea783adaaa31d4245acfb88c2ebd42b47628d63ecabf345484f0a9f665b63c54c897d5578be2",
            )
            print(response)
        - lang: Kotlin
          source: >-
            package com.lightspark.grid.example


            import com.lightspark.grid.client.LightsparkGridClient

            import com.lightspark.grid.client.okhttp.LightsparkGridOkHttpClient

            import
            com.lightspark.grid.models.auth.credentials.CredentialResendChallengeParams

            import
            com.lightspark.grid.models.auth.credentials.CredentialResendChallengeResponse


            fun main() {
                val client: LightsparkGridClient = LightsparkGridOkHttpClient.fromEnv()

                val response: CredentialResendChallengeResponse = client.auth().credentials().resendChallenge("id")
            }
components:
  schemas:
    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` and `OAUTH`, where
        the credential type alone is sufficient (the OTP is delivered
        out-of-band for `EMAIL_OTP`; there is no server-side challenge for
        `OAUTH`).
      type: object
      properties:
        clientPublicKey:
          type: string
          pattern: ^04[0-9a-fA-F]{128}$
          minLength: 130
          maxLength: 130
          description: >-
            Required for `PASSKEY` credentials. Client-generated P-256 public
            key, hex-encoded in uncompressed SEC1 format (`04` prefix followed
            by the 32-byte X and 32-byte Y coordinates; 130 hex characters
            total). The matching private key must remain on the client. Grid
            bakes this key into the Turnkey session-creation payload that the
            returned `challenge` is computed from, so the resulting session
            signing key is sealed to the client. Ignored for `EMAIL_OTP` and
            `OAUTH` credentials.
          example: >-
            04f45f2a22c908b9ce09a7150e514afd24627c401c38a4afc164e1ea783adaaa31d4245acfb88c2ebd42b47628d63ecabf345484f0a9f665b63c54c897d5578be2
    AuthCredentialResponseOneOf:
      title: Auth Credential Response
      description: >-
        Discriminated response shape returned from `POST
        /auth/credentials/{id}/challenge`. For `EMAIL_OTP` and `OAUTH`
        credentials the body is a plain `AuthMethod` (wrapped as
        `AuthMethodResponse` to disambiguate the oneOf). For `PASSKEY`
        credentials the body is a `PasskeyAuthChallenge` — the base `AuthMethod`
        fields plus the Grid-issued `challenge`, `requestId`, and `expiresAt`
        that drive the subsequent assertion. Registration responses from `POST
        /auth/credentials` use the simpler `AuthMethodResponse` shape directly
        for all three credential types.
      oneOf:
        - $ref: '#/components/schemas/AuthMethodResponse'
        - $ref: '#/components/schemas/PasskeyAuthChallenge'
      discriminator:
        propertyName: type
        mapping:
          EMAIL_OTP:
            $ref: '#/components/schemas/AuthMethodResponse'
          OAUTH:
            $ref: '#/components/schemas/AuthMethodResponse'
          PASSKEY:
            $ref: '#/components/schemas/PasskeyAuthChallenge'
    Error400:
      type: object
      required:
        - message
        - status
        - code
      properties:
        status:
          type: integer
          enum:
            - 400
          description: HTTP status code
        code:
          type: string
          description: >
            | Error Code | Description |

            |------------|-------------|

            | INVALID_INPUT | Invalid input provided |

            | MISSING_MANDATORY_USER_INFO | Required customer information is
            missing |

            | INVITATION_ALREADY_CLAIMED | Invitation has already been claimed |

            | INVITATIONS_NOT_CONFIGURED | Invitations are not configured |

            | INVALID_UMA_ADDRESS | UMA address format is invalid |

            | INVITATION_CANCELLED | Invitation has been cancelled |

            | QUOTE_REQUEST_FAILED | An issue occurred during the quote process;
            this is retryable |

            | INVALID_PAYREQ_RESPONSE | Counterparty Payreq response was invalid
            |

            | INVALID_RECEIVER | Receiver is invalid |

            | PARSE_PAYREQ_RESPONSE_ERROR | Error parsing receiver PayReq
            response |

            | CERT_CHAIN_INVALID | Counterparty certificate chain is invalid |

            | CERT_CHAIN_EXPIRED | Counterparty certificate chain has expired |

            | INVALID_PUBKEY_FORMAT | Counterparty Public key format is invalid
            |

            | MISSING_REQUIRED_UMA_PARAMETERS | Counterparty required UMA
            parameters are missing |

            | SENDER_NOT_ACCEPTED | Sender is not accepted |

            | AMOUNT_OUT_OF_RANGE | Amount is out of range |

            | INVALID_CURRENCY | Currency is invalid |

            | INVALID_TIMESTAMP | Timestamp is invalid |

            | INVALID_NONCE | Nonce is invalid |

            | INVALID_REQUEST_FORMAT | Request format is invalid |

            | INVALID_BANK_ACCOUNT | Bank account is invalid |

            | SELF_PAYMENT | Self payment not allowed |

            | LOOKUP_REQUEST_FAILED | Lookup request failed |

            | PARSE_LNURLP_RESPONSE_ERROR | Error parsing LNURLP response |

            | INVALID_AMOUNT | Amount is invalid |

            | WEBHOOK_ENDPOINT_NOT_SET | Webhook endpoint is not set |

            | WEBHOOK_DELIVERY_ERROR | Webhook delivery error |

            | LOW_QUALITY | Document quality too low to process |

            | DATA_MISMATCH | Document details don't match provided information
            |

            | EXPIRED | Document has expired |

            | SUSPECTED_FRAUD | Document suspected of being forged or edited |

            | UNSUITABLE_DOCUMENT | Document type is not accepted or not
            supported |

            | INCOMPLETE | Document is missing pages or sides |

            | EMAIL_OTP_CREDENTIAL_ALREADY_EXISTS | An EMAIL_OTP credential is
            already registered on the target internal account; only one email
            OTP credential is supported per internal account at this time |

            | PASSKEY_CREDENTIAL_ALREADY_EXISTS | A PASSKEY credential is
            already registered on the target internal account; only one passkey
            credential is supported per internal account in v1 |
          enum:
            - INVALID_INPUT
            - MISSING_MANDATORY_USER_INFO
            - INVITATION_ALREADY_CLAIMED
            - INVITATIONS_NOT_CONFIGURED
            - INVALID_UMA_ADDRESS
            - INVITATION_CANCELLED
            - QUOTE_REQUEST_FAILED
            - INVALID_PAYREQ_RESPONSE
            - INVALID_RECEIVER
            - PARSE_PAYREQ_RESPONSE_ERROR
            - CERT_CHAIN_INVALID
            - CERT_CHAIN_EXPIRED
            - INVALID_PUBKEY_FORMAT
            - MISSING_REQUIRED_UMA_PARAMETERS
            - SENDER_NOT_ACCEPTED
            - AMOUNT_OUT_OF_RANGE
            - INVALID_CURRENCY
            - INVALID_TIMESTAMP
            - INVALID_NONCE
            - INVALID_REQUEST_FORMAT
            - INVALID_BANK_ACCOUNT
            - SELF_PAYMENT
            - LOOKUP_REQUEST_FAILED
            - PARSE_LNURLP_RESPONSE_ERROR
            - INVALID_AMOUNT
            - WEBHOOK_ENDPOINT_NOT_SET
            - WEBHOOK_DELIVERY_ERROR
            - LOW_QUALITY
            - DATA_MISMATCH
            - EXPIRED
            - SUSPECTED_FRAUD
            - UNSUITABLE_DOCUMENT
            - INCOMPLETE
            - EMAIL_OTP_CREDENTIAL_ALREADY_EXISTS
            - PASSKEY_CREDENTIAL_ALREADY_EXISTS
        message:
          type: string
          description: Error message
        details:
          type: object
          description: Additional error details
          additionalProperties: true
    Error401:
      type: object
      required:
        - message
        - status
        - code
      properties:
        status:
          type: integer
          enum:
            - 401
          description: HTTP status code
        code:
          type: string
          description: |
            | Error Code | Description |
            |------------|-------------|
            | UNAUTHORIZED | Issue with API credentials |
            | INVALID_SIGNATURE | Signature header is invalid |
          enum:
            - UNAUTHORIZED
            - INVALID_SIGNATURE
        message:
          type: string
          description: Error message
        details:
          type: object
          description: Additional error details
          additionalProperties: true
    Error404:
      type: object
      required:
        - message
        - status
        - code
      properties:
        status:
          type: integer
          enum:
            - 404
          description: HTTP status code
        code:
          type: string
          description: |
            | Error Code | Description |
            |------------|-------------|
            | TRANSACTION_NOT_FOUND | Transaction not found |
            | INVITATION_NOT_FOUND | Invitation not found |
            | USER_NOT_FOUND | Customer not found |
            | QUOTE_NOT_FOUND | Quote not found |
            | LOOKUP_REQUEST_NOT_FOUND | Lookup request not found |
            | TOKEN_NOT_FOUND | Token not found |
            | BULK_UPLOAD_JOB_NOT_FOUND | Bulk upload job not found |
            | REFERENCE_NOT_FOUND | Reference not found |
          enum:
            - TRANSACTION_NOT_FOUND
            - INVITATION_NOT_FOUND
            - USER_NOT_FOUND
            - QUOTE_NOT_FOUND
            - LOOKUP_REQUEST_NOT_FOUND
            - TOKEN_NOT_FOUND
            - BULK_UPLOAD_JOB_NOT_FOUND
            - REFERENCE_NOT_FOUND
        message:
          type: string
          description: Error message
        details:
          type: object
          description: Additional error details
          additionalProperties: true
    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
    Error500:
      type: object
      required:
        - message
        - status
        - code
      properties:
        status:
          type: integer
          enum:
            - 500
          description: HTTP status code
        code:
          type: string
          description: |
            | Error Code | Description |
            |------------|-------------|
            | GRID_SWITCH_ERROR | Grid switch error |
            | INTERNAL_ERROR | Internal server or UMA error |
          enum:
            - GRID_SWITCH_ERROR
            - INTERNAL_ERROR
        message:
          type: string
          description: Error message
        details:
          type: object
          description: Additional error details
          additionalProperties: true
    AuthMethodResponse:
      title: Auth Method Response
      description: >-
        Strict wrapper around `AuthMethod`. Used directly as the registration
        response on `POST /auth/credentials` (all three credential types) and
        inside `AuthCredentialResponseOneOf` for the `EMAIL_OTP` and `OAUTH`
        branches of `POST /auth/credentials/{id}/challenge`. The only difference
        from `AuthMethod` is `unevaluatedProperties: false`, which disambiguates
        the oneOf against `PasskeyAuthChallenge` — without the strictness, an
        `AuthMethod` with extra fields would ambiguously match both branches.
      allOf:
        - $ref: '#/components/schemas/AuthMethod'
      unevaluatedProperties: false
    PasskeyAuthChallenge:
      title: Passkey Auth Challenge
      description: >-
        Extended `AuthMethod` shape returned for `PASSKEY` credentials from
        `POST /auth/credentials` (first-authentication case) and `POST
        /auth/credentials/{id}/challenge` (reauthentication case). Adds a
        Grid-issued `challenge`, the corresponding `requestId`, and the
        challenge's `expiresAt` to the base `AuthMethod` fields. The client
        signs the challenge with the passkey to produce the assertion submitted
        to `POST /auth/credentials/{id}/verify`.
      allOf:
        - $ref: '#/components/schemas/AuthMethod'
        - type: object
          required:
            - challenge
            - requestId
            - expiresAt
          properties:
            challenge:
              type: string
              description: >-
                Base64url-encoded challenge issued by Grid for the pending
                passkey authentication. The client passes it into
                `navigator.credentials.get()` as the WebAuthn challenge; the
                resulting assertion is submitted to `POST
                /auth/credentials/{id}/verify`. Single-use; a new challenge is
                issued on the next call to `POST
                /auth/credentials/{id}/challenge`.
              example: VjZ6o8KfE9V3q3LkR2nH5eZ6dM8yA1xW
            requestId:
              type: string
              description: >-
                Unique identifier for this pending passkey authentication
                request. Must be echoed as the `Request-Id` header on the
                subsequent `POST /auth/credentials/{id}/verify` call so Grid can
                correlate the assertion with the issued challenge.
              example: 7c4a8d09-ca37-4e3e-9e0d-8c2b3e9a1f21
            expiresAt:
              type: string
              format: date-time
              description: >-
                Timestamp after which the issued challenge is no longer valid.
                The assertion must reach `POST /auth/credentials/{id}/verify`
                before this time; otherwise the client must request a fresh
                challenge via `POST /auth/credentials/{id}/challenge`.
              example: '2026-04-08T15:35:00Z'
    AuthMethod:
      type: object
      required:
        - id
        - accountId
        - type
        - nickname
        - createdAt
        - updatedAt
      properties:
        id:
          type: string
          description: >-
            System-generated unique identifier for the authentication
            credential.
          example: AuthMethod:019542f5-b3e7-1d02-0000-000000000001
        accountId:
          type: string
          description: >-
            Identifier of the internal account that this credential
            authenticates.
          example: InternalAccount:019542f5-b3e7-1d02-0000-000000000002
        type:
          $ref: '#/components/schemas/AuthMethodType'
        nickname:
          type: string
          description: >-
            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 nickname provided at registration time.
          example: example@lightspark.com
        createdAt:
          type: string
          format: date-time
          description: Creation timestamp.
          example: '2026-04-08T15:30:01Z'
        updatedAt:
          type: string
          format: date-time
          description: Last update timestamp.
          example: '2026-04-08T15:35:00Z'
    AuthMethodType:
      type: string
      enum:
        - OAUTH
        - EMAIL_OTP
        - PASSKEY
      description: >-
        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.
  securitySchemes:
    BasicAuth:
      type: http
      scheme: basic
      description: >-
        API token authentication using format `<api token id>:<api client
        secret>`

````