# TOTP / 2FA API
> Add and test two-factor authentication without wrangling a crypto library. Generate a fresh base32 secret with a ready-to-scan otpauth URI, compute the current time-based one-time code (RFC 6238), verify a code submitted by a user with an adjustable drift window, or build an otpauth:// URI for any secret. Supports SHA-1, SHA-256 and SHA-512, 6 to 8 digits and a custom period, and is fully compatible with Google Authenticator, Authy, 1Password and other authenticator apps. Pure server-side computation with no third-party upstream, so responses are instant and the service is always available. Ideal for adding 2FA to apps, authentication tooling, QA and testing, and no-code automation.

## Authentication
All requests require your oanor API key in the `x-oanor-key` header. Get one at https://www.oanor.com/developer/keys.

```bash
curl -H "x-oanor-key: oanor_live_…" "https://api.oanor.com/totp-api/..."
```

## Pricing
- **Free** (Free) — 1,500 calls/Mo, 3 req/s
- **Basic** ($5/Mo) — 30,000 calls/Mo, 10 req/s
- **Pro** ($17/Mo) — 250,000 calls/Mo, 30 req/s
- **Mega** ($46/Mo) — 1,500,000 calls/Mo, 80 req/s

## Endpoints

### TOTP

#### `GET /v1/code` — Current TOTP code

**Parameters:**
- `secret` (query, required, string) — Base32 secret Example: `GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ`
- `algorithm` (query, optional, string) — SHA1 | SHA256 | SHA512 Example: `SHA1`
- `digits` (query, optional, string) — 6, 7 or 8 Example: `8`
- `period` (query, optional, string) — Seconds (default 30) Example: `30`
- `timestamp` (query, optional, string) — Unix time (default now) Example: `59`

**Example:**
```bash
curl -H "x-oanor-key: $KEY" \
  "https://api.oanor.com/totp-api/v1/code?secret=GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ&algorithm=SHA1&digits=8&period=30&timestamp=59"
```

**Response:**
```json
{
    "data": {
        "code": "94287082",
        "digits": 8,
        "period": 30,
        "algorithm": "SHA1",
        "timestamp": 59,
        "seconds_remaining": 1
    },
    "meta": {
        "timestamp": "2026-05-30T18:16:47.984Z",
        "request_id": "5f4798da-856b-46b1-be3e-a9fa45561607"
    },
    "status": "ok",
    "message": "OK",
    "success": true
}
```

#### `GET /v1/secret` — Generate a secret + otpauth URI

**Parameters:**
- `issuer` (query, optional, string) — Issuer name Example: `oanor`
- `account` (query, optional, string) — Account label Example: `user@example.com`
- `bytes` (query, optional, string) — Secret bytes 10-64 (default 20) Example: `20`

**Example:**
```bash
curl -H "x-oanor-key: $KEY" \
  "https://api.oanor.com/totp-api/v1/secret?issuer=oanor&account=user%40example.com&bytes=20"
```

**Response:**
```json
{
    "data": {
        "hex": "201fae6e22c311a843223e54f30bcf83bc95d1a0",
        "base32": "EAP243RCYMI2QQZCHZKPGC6PQO6JLUNA",
        "issuer": "oanor",
        "secret": "EAP243RCYMI2QQZCHZKPGC6PQO6JLUNA",
        "account": "user@example.com",
        "otpauth_uri": "otpauth://totp/oanor%3Auser%40example.com?secret=EAP243RCYMI2QQZCHZKPGC6PQO6JLUNA&issuer=oanor&algorithm=SHA1&digits=6&period=30"
    },
    "meta": {
        "timestamp": "2026-05-30T18:16:48.035Z",
        "request_id": "24aaf93a-fe32-4f04-8b0f-eabc40655dca"
    },
    "status": "ok",
    "message": "OK",
    "success": true
}
```

#### `GET /v1/uri` — Build an otpauth:// URI

**Parameters:**
- `secret` (query, required, string) — Base32 secret Example: `GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ`
- `issuer` (query, optional, string) — Issuer name Example: `Acme`
- `account` (query, optional, string) — Account label Example: `bob@example.com`
- `digits` (query, optional, string) — 6, 7 or 8 Example: `6`
- `period` (query, optional, string) — Seconds Example: `30`

**Example:**
```bash
curl -H "x-oanor-key: $KEY" \
  "https://api.oanor.com/totp-api/v1/uri?secret=GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ&issuer=Acme&account=bob%40example.com&digits=6&period=30"
```

**Response:**
```json
{
    "data": {
        "digits": 6,
        "issuer": "Acme",
        "period": 30,
        "account": "bob@example.com",
        "algorithm": "SHA1",
        "otpauth_uri": "otpauth://totp/Acme%3Abob%40example.com?secret=GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ&issuer=Acme&algorithm=SHA1&digits=6&period=30"
    },
    "meta": {
        "timestamp": "2026-05-30T18:16:48.112Z",
        "request_id": "e2639b88-9ad5-407b-bc92-5a85d87f03f8"
    },
    "status": "ok",
    "message": "OK",
    "success": true
}
```

#### `GET /v1/verify` — Verify a code

**Parameters:**
- `secret` (query, required, string) — Base32 secret Example: `GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ`
- `code` (query, required, string) — Code to verify Example: `94287082`
- `digits` (query, optional, string) — 6, 7 or 8 Example: `8`
- `period` (query, optional, string) — Seconds Example: `30`
- `window` (query, optional, string) — Drift window 0-10 (default 1) Example: `1`
- `timestamp` (query, optional, string) — Unix time (default now) Example: `59`

**Example:**
```bash
curl -H "x-oanor-key: $KEY" \
  "https://api.oanor.com/totp-api/v1/verify?secret=GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ&code=94287082&digits=8&period=30&window=1&timestamp=59"
```

**Response:**
```json
{
    "data": {
        "delta": 0,
        "valid": true,
        "digits": 8,
        "period": 30,
        "window": 1,
        "algorithm": "SHA1"
    },
    "meta": {
        "timestamp": "2026-05-30T18:16:48.162Z",
        "request_id": "73e92b67-5a1e-4088-95cf-38a3c18ea107"
    },
    "status": "ok",
    "message": "OK",
    "success": true
}
```


---
Marketplace page: https://www.oanor.com/api/totp-api
OpenAPI spec: https://www.oanor.com/api/totp-api/openapi.json
