Skip to main content

Endpoint

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

Authentication

HeaderRequiredValue
X-API-KeyYesYour API key (bun_...)
Content-TypeYesapplication/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

FieldTypeRequiredDescription
secretstringNoExisting Base32 TOTP secret to generate an OTP for
new_secretbooleanNoSet to true to generate a brand-new Base32 secret
issuerstringNoIssuer label for new secret provisioning (default: "Bunny")
accountstringNoAccount label for new secret provisioning (default: "user@example.com")
digitsintegerNoNumber of OTP digits: 6 or 8 (default: 6)
stepintegerNoTime step in seconds (default: 30)
At least one of secret or new_secret: true must be provided.

Example — generate OTP from existing secret

{
  "secret": "JBSWY3DPEHPK3PXP"
}

Example — provision new secret

{
  "new_secret": true,
  "issuer": "MyApp",
  "account": "jane@example.com"
}

Response

200 OK — generate OTP from existing secret

FieldTypeDescription
codestringCurrent OTP code (zero-padded to digits length)
valid_for_secondsintegerSeconds remaining until this OTP expires
stepintegerTime step used in seconds
digitsintegerNumber of digits in the OTP
Example
{
  "code": "482910",
  "valid_for_seconds": 18,
  "step": 30,
  "digits": 6
}

200 OK — provision new secret (new_secret: true)

FieldTypeDescription
secretstringNew Base32-encoded TOTP secret to store and enroll in an authenticator app
issuerstringIssuer label (echoed from request, or "Bunny" by default)
accountstringAccount label (echoed from request, or "user@example.com" by default)
Example
{
  "secret": "N5XGIY3SMFZHK3DMN5XGIY3SMFZHK3D",
  "issuer": "MyApp",
  "account": "jane@example.com"
}

401 Unauthorized

{
  "detail": "Missing API key. Include X-API-Key header."
}

402 Payment Required

{
  "detail": "Monthly quota exceeded. Upgrade your plan."
}

422 Unprocessable Entity

{
  "detail": "Provide either 'secret' or 'new_secret: true'"
}

429 Too Many Requests

{
  "detail": "Rate limit exceeded. Try again in 60 seconds."
}

cURL example

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

FieldTypeRequiredDescription
secretstringYesBase32 TOTP secret for the user
codestringYesOTP code submitted by the user
stepintegerNoTime step in seconds (default: 30)
digitsintegerNoNumber of OTP digits (default: 6)
windowintegerNoNumber of time steps to check on each side of the current time for clock drift tolerance (default: 1)

Example

{
  "secret": "JBSWY3DPEHPK3PXP",
  "code": "482910"
}

Response

200 OK — valid code

FieldTypeDescription
validbooleantrue if the code matched
driftintegerNumber of time steps offset from current time where the match was found (0 = current window, -1 = previous, etc.)
Example
{
  "valid": true,
  "drift": 0
}

200 OK — invalid code

{
  "valid": false
}

cURL example

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"}'