> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/supertokens/supertokens-core/llms.txt
> Use this file to discover all available pages before exploring further.

# Verify TOTP Device

> Verify a newly created TOTP device with a valid code

## Endpoint

```
POST /recipe/totp/device/verify
```

This is a tenant-specific API that verifies a newly created TOTP device by checking if the provided code is valid. Once verified, the device can be used for authentication.

## Request Body

<ParamField body="userId" type="string" required>
  The ID of the user who owns the device. Cannot be empty.
</ParamField>

<ParamField body="deviceName" type="string" required>
  The name of the device to verify. Cannot be empty.
</ParamField>

<ParamField body="totp" type="string" required>
  The TOTP code generated by the authenticator app.
</ParamField>

## Request Example

```bash theme={null}
curl -X POST https://your-api-domain.com/recipe/totp/device/verify \
  -H "Content-Type: application/json" \
  -d '{
    "userId": "user123",
    "deviceName": "Google Authenticator",
    "totp": "123456"
  }'
```

## Response

### Success Response

<ResponseField name="status" type="string">
  Returns `"OK"` when the device is successfully verified
</ResponseField>

<ResponseField name="wasAlreadyVerified" type="boolean">
  * `true` if the device was already verified before this call
  * `false` if this call newly verified the device
</ResponseField>

```json theme={null}
{
  "status": "OK",
  "wasAlreadyVerified": false
}
```

### Error Responses

#### Unknown Device

<ResponseField name="status" type="string">
  Returns `"UNKNOWN_DEVICE_ERROR"` when the specified device does not exist
</ResponseField>

```json theme={null}
{
  "status": "UNKNOWN_DEVICE_ERROR"
}
```

#### Invalid TOTP Code

<ResponseField name="status" type="string">
  Returns `"INVALID_TOTP_ERROR"` when the provided code is incorrect
</ResponseField>

<ResponseField name="currentNumberOfFailedAttempts" type="number">
  The number of failed attempts so far (available in v5.0+)
</ResponseField>

<ResponseField name="maxNumberOfFailedAttempts" type="number">
  The maximum number of failed attempts allowed (available in v5.0+)
</ResponseField>

```json theme={null}
{
  "status": "INVALID_TOTP_ERROR",
  "currentNumberOfFailedAttempts": 2,
  "maxNumberOfFailedAttempts": 5
}
```

#### Rate Limit Reached

<ResponseField name="status" type="string">
  Returns `"LIMIT_REACHED_ERROR"` when too many failed attempts have occurred
</ResponseField>

<ResponseField name="retryAfterMs" type="number">
  The number of milliseconds to wait before retrying
</ResponseField>

<ResponseField name="currentNumberOfFailedAttempts" type="number">
  The number of failed attempts (available in v5.0+)
</ResponseField>

<ResponseField name="maxNumberOfFailedAttempts" type="number">
  The maximum allowed failed attempts (available in v5.0+)
</ResponseField>

```json theme={null}
{
  "status": "LIMIT_REACHED_ERROR",
  "retryAfterMs": 300000,
  "currentNumberOfFailedAttempts": 5,
  "maxNumberOfFailedAttempts": 5
}
```

## Implementation Details

**Source**: [View source](https://github.com/supertokens/supertokens-core/blob/master/src/main/java/io/supertokens/webserver/api/totp/VerifyTotpDeviceAPI.java#L26)

* Verification is tenant-specific
* Failed attempts are tracked to prevent brute force attacks
* After reaching the maximum failed attempts, users must wait before retrying
* Once verified, a device can be used for authentication
* Verifying an already-verified device is not an error - returns success with `wasAlreadyVerified: true`

## Workflow

1. User creates a TOTP device using [Create Device](/api/totp/create-device)
2. User scans QR code with authenticator app
3. User enters the 6-digit code from their app
4. Your application calls this endpoint to verify the code
5. If successful, the device is now verified and can be used for authentication

## Next Steps

<Card title="Verify TOTP Code" href="/api/totp/verify-totp">
  Use the verified device for authentication
</Card>

## Error Handling

<ResponseField name="error" type="BadRequestException">
  Returned when:

  * `userId` is empty
  * `deviceName` is empty
</ResponseField>
