Developer API

2faco API

Generate TOTP codes, validate 2FA tokens, and create secrets programmatically. Free for non-commercial use with a self-service API key.

Base URL

https://2faco.com/api/v1

Authentication

Include your API key in the Authorization header on every request except /health and /signup.

Authorization: Bearer <your-api-key>

Endpoints

POST /signup
Create a new API key. No authentication required.

ParameterTypeDescription
labelstringoptionalFriendly name to identify the key owner
Example request
curl -X POST https://2faco.com/api/v1/signup \ -H "Content-Type: application/json" \ -d '{"label": "my-script"}'
Response
{
  "api_key": "2faco_0e25779c6dab43f390938beffe8812a3dffefb36feb68b1c",
  "label": "my-script",
  "message": "Store this key securely. It will not be shown again."
}
GET /health
Health check — no auth required.
Response
{"status": "ok", "service": "2faco-api"}
POST /totp
Generate a TOTP code from a secret key.
ParameterTypeDescription
secretstringrequiredBase32-encoded secret key
digitsnumberoptionalCode length (default: 6)
periodnumberoptionalTime window in seconds (default: 30)
algorithmstringoptionalSHA1, SHA256, or SHA512 (default: SHA1)
Example
curl -X POST https://2faco.com/api/v1/totp \ -H "Authorization: Bearer <key>" \ -H "Content-Type: application/json" \ -d '{"secret": "JBSWY3DPEHPK3PXP"}'
Response
{
  "code": "341595",
  "period": 30,
  "digits": 6,
  "algorithm": "SHA1",
  "expires_in": 12
}
POST /validate
Check if a TOTP code is valid for a given secret. Uses a window of ±1 interval.
ParameterTypeDescription
secretstringrequiredBase32-encoded secret key
codestringrequired6-digit TOTP code to validate
windownumberoptionalIntervals before/after current (default: 1)
Example
curl -X POST https://2faco.com/api/v1/validate \ -H "Authorization: Bearer <key>" \ -H "Content-Type: application/json" \ -d '{"secret": "JBSWY3DPEHPK3PXP", "code": "341595"}'
Response
{"valid": true}
GET /generate-secret
Generate a cryptographically random Base32 secret key for TOTP setup.
Example
curl -X GET https://2faco.com/api/v1/generate-secret \ -H "Authorization: Bearer <key>"
Response
{"secret": "4XR5VVSMUGBFFVH4CTMRSJK6VU6HLOPF"}

Rate Limits

Signup is limited to 3 requests per hour per IP address. Authenticated endpoints currently have no rate limit, but may be throttled if abused.

Why Use the 2faco API?

Most developers need TOTP generation for one of three scenarios:

  • Automated testing — CI/CD pipelines that need to verify 2FA login flows without a physical device.
  • Internal tools — admin dashboards, ops scripts, or backup automation where generating codes programmatically saves time.
  • Integration prototypes — building a 2FA feature and needing a reliable TOTP source before implementing your own RFC 6238 logic.

The API is free for non-commercial use, requires no account creation, and runs on the same audited cryptographic primitives as our browser tools.

Common Use Cases

Validate User-Submitted Codes

Your app receives a TOTP code from a user. Call /validate with the stored secret and the submitted code to verify it matches the current (or previous/next) time window.

Generate Codes for End-to-End Tests

In your test suite, call /totp with the test account's secret to produce a valid code, then submit it through your login flow.

Provision New User Secrets

Call /generate-secret during user onboarding, display the secret as a QR code (using the OTPAuth URI Builder), and store the secret encrypted in your database.

Error Handling

All error responses follow a consistent format:

{ "error": "invalid_secret", "message": "Secret must be valid Base32" }

Common error codes:

CodeHTTP StatusCause
invalid_secret400Base32 decode failed or wrong length
missing_secret400Required secret parameter omitted
missing_code400Required code parameter omitted
unauthorized401Invalid or missing API key
rate_limited429Signup limit exceeded (3/hr per IP)
internal_error500Server-side failure — retry with backoff

Best Practices

  • Store secrets encrypted. Use AES-256-GCM with a key from your secrets manager. Never log raw secrets.
  • Accept a ±1 window. The /validate endpoint defaults to window=1 (90 seconds total). This accommodates clock drift and network latency.
  • Prefer SHA256 or SHA512. SHA1 is supported for compatibility but SHA256 is recommended for new implementations.
  • Rotate keys periodically. Generate a new API key every 90 days via /signup and update your deployments.
  • Monitor /health. Use it in uptime checks; it requires no auth and returns {"status":"ok"}.

JavaScript Example

const API_KEY = "2faco_your_key_here"; const BASE = "https://2faco.com/api/v1"; async function getTOTP(secret) { const res = await fetch(`${BASE}/totp`, { method: "POST", headers: { "Authorization": `Bearer ${API_KEY}`, "Content-Type": "application/json" }, body: JSON.stringify({ secret }) }); return res.json(); } getTOTP("JBSWY3DPEHPK3PXP").then(console.log); // { code: "341595", period: 30, digits: 6, algorithm: "SHA1", expires_in: 12 }

FAQ

Is the API really free?

Yes, for non-commercial use. Commercial applications or high-volume usage require a custom agreement — contact support@2faco.com.

Can I use this for production 2FA?

The API is suitable for development, testing, and internal tools. For user-facing production 2FA, we recommend implementing RFC 6238 directly in your backend to avoid external dependencies and latency.

What happens if I lose my API key?

Keys cannot be recovered. Generate a new one via /signup and update your application. The old key is automatically invalidated.

Does the API log submitted secrets?

No. Secrets are used only to compute the TOTP code or validation result and are never written to logs or persistent storage.

Can I call the API from a browser?

CORS is configured to allow requests from any origin. However, exposing your API key in client-side code is not recommended — use a backend proxy instead.

Are there SDKs or client libraries?

Not officially. The HTTP interface is simple enough that most teams wrap it in a few lines of code. See the JavaScript example above for a minimal fetch wrapper.