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

# POST /otp-totp/generate

> Generate TOTP one-time passwords or provision new TOTP secrets for two-factor authentication flows.

## Endpoint

```
POST https://api.bunny.build/api/v1/otp-totp/generate
```

## Authentication

| Header         | Required | Value                    |
| -------------- | -------- | ------------------------ |
| `X-API-Key`    | Yes      | Your API key (`bun_...`) |
| `Content-Type` | Yes      | `application/json`       |

## Overview

Generate time-based one-time passwords (TOTP per RFC 6238) for two-factor authentication flows, or provision brand-new TOTP secrets ready to be enrolled in an authenticator app. Pass an existing `secret` to get the current OTP code, or set `new_secret: true` to receive a fresh Base32 secret. Use the `/verify` endpoint to validate a user-submitted code against a known secret.

## Use cases

* Generate the current OTP for a user's registered secret server-side
* Provision new 2FA secrets during user enrollment
* Verify that an authenticator app is correctly configured
* Build custom 2FA flows without a third-party auth service

## Details

OTPs default to 6 digits rotating every 30 seconds (standard TOTP window). Both `digits` and `step` are configurable to support non-standard authenticator setups. When provisioning a new secret with `new_secret: true`, the response includes only the Base32 secret, issuer, and account — no OTP is generated in that flow.

## Request body

| Field        | Type    | Required | Description                                                               |
| ------------ | ------- | -------- | ------------------------------------------------------------------------- |
| `secret`     | string  | No       | Existing Base32 TOTP secret to generate an OTP for                        |
| `new_secret` | boolean | No       | Set to `true` to generate a brand-new Base32 secret                       |
| `issuer`     | string  | No       | Issuer label for new secret provisioning (default: `"Bunny"`)             |
| `account`    | string  | No       | Account label for new secret provisioning (default: `"user@example.com"`) |
| `digits`     | integer | No       | Number of OTP digits: `6` or `8` (default: `6`)                           |
| `step`       | integer | No       | Time step in seconds (default: `30`)                                      |

At least one of `secret` or `new_secret: true` must be provided.

### Example — generate OTP from existing secret

```json theme={null}
{
  "secret": "JBSWY3DPEHPK3PXP"
}
```

### Example — provision new secret

```json theme={null}
{
  "new_secret": true,
  "issuer": "MyApp",
  "account": "jane@example.com"
}
```

## Response

### 200 OK — generate OTP from existing secret

| Field               | Type    | Description                                       |
| ------------------- | ------- | ------------------------------------------------- |
| `code`              | string  | Current OTP code (zero-padded to `digits` length) |
| `valid_for_seconds` | integer | Seconds remaining until this OTP expires          |
| `step`              | integer | Time step used in seconds                         |
| `digits`            | integer | Number of digits in the OTP                       |

**Example**

```json theme={null}
{
  "code": "482910",
  "valid_for_seconds": 18,
  "step": 30,
  "digits": 6
}
```

### 200 OK — provision new secret (`new_secret: true`)

| Field     | Type   | Description                                                                |
| --------- | ------ | -------------------------------------------------------------------------- |
| `secret`  | string | New Base32-encoded TOTP secret to store and enroll in an authenticator app |
| `issuer`  | string | Issuer label (echoed from request, or `"Bunny"` by default)                |
| `account` | string | Account label (echoed from request, or `"user@example.com"` by default)    |

**Example**

```json theme={null}
{
  "secret": "N5XGIY3SMFZHK3DMN5XGIY3SMFZHK3D",
  "issuer": "MyApp",
  "account": "jane@example.com"
}
```

### 401 Unauthorized

```json theme={null}
{
  "detail": "Missing API key. Include X-API-Key header."
}
```

### 402 Payment Required

```json theme={null}
{
  "detail": "Monthly quota exceeded. Upgrade your plan."
}
```

### 422 Unprocessable Entity

```json theme={null}
{
  "detail": "Provide either 'secret' or 'new_secret: true'"
}
```

### 429 Too Many Requests

```json theme={null}
{
  "detail": "Rate limit exceeded. Try again in 60 seconds."
}
```

## cURL example

```bash theme={null}
curl -X POST https://api.bunny.build/api/v1/otp-totp/generate \
  -H "X-API-Key: bun_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"secret": "JBSWY3DPEHPK3PXP"}'
```

***

## Verify endpoint

```
POST https://api.bunny.build/api/v1/otp-totp/verify
```

Validate a user-submitted OTP code against a known Base32 secret. Supports a configurable drift window to account for clock skew between server and authenticator app.

### Request body

| Field    | Type    | Required | Description                                                                                             |
| -------- | ------- | -------- | ------------------------------------------------------------------------------------------------------- |
| `secret` | string  | Yes      | Base32 TOTP secret for the user                                                                         |
| `code`   | string  | Yes      | OTP code submitted by the user                                                                          |
| `step`   | integer | No       | Time step in seconds (default: `30`)                                                                    |
| `digits` | integer | No       | Number of OTP digits (default: `6`)                                                                     |
| `window` | integer | No       | Number of time steps to check on each side of the current time for clock drift tolerance (default: `1`) |

#### Example

```json theme={null}
{
  "secret": "JBSWY3DPEHPK3PXP",
  "code": "482910"
}
```

### Response

#### 200 OK — valid code

| Field   | Type    | Description                                                                                                       |
| ------- | ------- | ----------------------------------------------------------------------------------------------------------------- |
| `valid` | boolean | `true` if the code matched                                                                                        |
| `drift` | integer | Number of time steps offset from current time where the match was found (0 = current window, -1 = previous, etc.) |

**Example**

```json theme={null}
{
  "valid": true,
  "drift": 0
}
```

#### 200 OK — invalid code

```json theme={null}
{
  "valid": false
}
```

### cURL example

```bash theme={null}
curl -X POST https://api.bunny.build/api/v1/otp-totp/verify \
  -H "X-API-Key: bun_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"secret": "JBSWY3DPEHPK3PXP", "code": "482910"}'
```
