Documentation
Flow2FA OTP API
Generate and validate one-time passcodes with two endpoints. Every request is authenticated with an API key, delivery runs over the providers configured for your account, and the OTP value is not returned by the API.

Introduction
Welcome to the Flow2FA public API documentation. Below you will find every public endpoint for generating and validating One-Time Passcodes (OTPs), including required headers, body format, examples and possible error messages.
| Endpoint | Purpose |
|---|---|
| POST /otp/generate | Create an OTP and queue it for delivery. |
| POST /otp/validate | Verify a user-entered OTP and consume it. |
Website and API use separate origins
- REST API base URL:
https://api.flow2fa.com- Website:
https://flow2fa.com
This website is served from https://flow2fa.com and the REST API from https://api.flow2fa.com. Send API requests to the API origin only. Production API access, API keys and the permitted provider values for your account are provisioned during account setup.
OpenAPI specification
The endpoints on this page are also published as a machine-readable OpenAPI 3.1 document. Use it to generate client SDKs, import the API into Postman or Insomnia, or drive contract tests. It describes only the public REST surface documented here — SMPP v3.4 connections are provisioned separately during account setup.
Specification URL
https://flow2fa.com/openapi.jsonImport it directly, or fetch it from the command line:
curl -sS https://flow2fa.com/openapi.json -o flow2fa-openapi.jsonAuthentication
Both endpoints require your API key in the request headers. Keep the key server-side — never ship it to a browser or mobile client.
x-api-key: YOUR_API_KEY
Content-Type: application/jsonSMPP v3.4 connection setup
SMPP connections are provisioned during account setup. To begin, request and complete the Flow2FA SMPP connection form by emailing devs@flow2fa.com. If your deployment requires a VPN, we may also ask you to complete our VPN form. VPN setup may incur an additional setup charge and will be subject to implementation lead times. Connection details, security requirements, networking arrangements and applicable commercial terms will be confirmed during account setup.
How to start an SMPP connection
- 1Email devs@flow2fa.com to request the SMPP connection form.
- 2Complete the Flow2FA SMPP connection form and return it.
- 3Complete the Flow2FA VPN form if your deployment requires a VPN tunnel.
- 4Flow2FA confirms connection details, any VPN setup charge, implementation lead times and the remaining account setup steps.
An SMPP connection is provisioned as part of your account setup — it is not created automatically from this public REST documentation. A VPN is not required for every connection; where one is needed, a setup charge and lead times may apply.
https://api.flow2fa.com/otp/generateGenerates a One-Time Passcode and queues it for delivery via the selected channel. For security, the OTP value is never returned — only metadata and the otpId.
Request body (JSON)
| Field | Type | Description |
|---|---|---|
| channel | string | Delivery channel. Allowed values: "email", "sms". |
| provider | string | Required. The account-configured provider or delivery-profile value issued to you during onboarding for that channel. Credentials are managed server-side and are never sent in the request. Values such as "generic", "twilio" or "sendgrid" are examples only — use the values issued for your account. Whether a permitted value maps to one underlying vendor or to an account-specific managed routing arrangement depends on your provisioned configuration and is confirmed during setup. A value that is not configured for your account and channel returns 400. |
| destination | string | Recipient: an email address (for email) or an E.164 phone number (for sms). |
| type | string | OTP type. Allowed values: "numeric", "alphanumeric". |
| length | number | OTP length between 4 and 12 (e.g. 6 or 8). |
| expiresInSeconds | number | OTP time-to-live in seconds (e.g. 300). |
| templateId | string (optional) | Message template to render, e.g. "otp-default-a1562ab2". |
About the required provider field
The current public REST request requires a `provider` value. It is the account-configured provider or delivery-profile value issued to you during onboarding for that channel — credentials stay server-side and are never sent in the request. Whether a permitted value maps to one underlying vendor or to an account-specific managed routing arrangement depends on the configuration provisioned for your account, and is confirmed during setup. Values shown in this documentation are examples only; use the values issued for your account.
Flow2FA does not document automatic switching between providers, overriding of the value you submit, or a universal fallback. Any retry, fallback or routing behaviour applies only where it is configured for your account. On SMPP v3.4, routing takes place behind the agreed bind and configuration, subject to the integration design.
Example request (illustrative values)
curl --location 'https://api.flow2fa.com/otp/generate' \
--header 'x-api-key: YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data-raw '{
"channel": "email",
"provider": "YOUR_CONFIGURED_PROVIDER",
"destination": "test@email.com",
"type": "alphanumeric",
"length": 8,
"expiresInSeconds": 300,
"templateId": "otp-default-a1562ab2"
}'Successful response
{
"otpId": "51a6fcc7-efc8-4e69-8bc1-ebb999befb2c",
"destination": "test@email.com",
"createdAt": "2025-09-10T14:05:41.5251815Z",
"expiresAt": "2025-09-10T14:10:41.5251815Z"
}| Field | Type | Description |
|---|---|---|
| otpId | string | Unique identifier for the OTP. Use it later to validate the code. |
| destination | string | Target email address or phone number. |
| createdAt | datetime | UTC timestamp when the OTP was created. |
| expiresAt | datetime | UTC timestamp when the OTP expires. |
Error messages
| Case | Response |
|---|---|
| Missing channel | OTP channel is required and must be either 'Email' or 'Sms'. |
| Missing destination | Destination (email or phone number) is required. |
| Missing type | OTP type is required. |
| Missing length | OTP length is required. |
| Missing expiresInSeconds | ExpiresInSeconds is required. |
| Invalid email format | Invalid email format. It must be like name@example.com. |
| Invalid phone format (SMS) | Invalid phone number format. Must start with country code. |
| Provider value not configured for the account and channel | Provider not found for this client and channel. |
| OTP length out of range (4–12) | OTP length must be between 4 and 12. |
| Non-positive expiration | ExpiresInSeconds must be greater than zero. |
https://api.flow2fa.com/otp/validateValidates a previously generated OTP using the otpId and the user-entered otp. On success the OTP is consumed (single use) and cannot be reused.
Request body (JSON)
| Field | Type | Description |
|---|---|---|
| otpId | string | The identifier returned by /otp/generate. |
| otp | string | The OTP code entered by the user. |
Example request (illustrative values)
curl --location 'https://api.flow2fa.com/otp/validate' \
--header 'x-api-key: YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data '{
"otpId": "c4f8814c-7a9d-4e13-b7d8-d4e66d272611",
"otp": "z4dGyBPQ"
}'Successful response (200)
{
"success": true,
"message": "OTP validated successfully."
}| Field | Type | Description |
|---|---|---|
| success | boolean | true when the OTP is valid and accepted. |
| message | string | Human-readable confirmation message. |
Error messages
| Case | Response |
|---|---|
| Missing otpId | OtpId is required. |
| Missing otp | Otp is required. |
| Incorrect or expired OTP | Invalid OTP or expired. |
| Too many failed attempts (temporary lock) | Too many failed attempts. Try again later. |
If the allowed attempt count configured for your account and provider value is exceeded, further validations return Too many failed attempts. Try again later. — even when the OTP is correct — until the lock duration elapses.
Notes & best practices
- The OTP value is not returned by the API. How code values are stored, hashed and retained is confirmed during security review rather than stated here.
- For
sms, use E.164 format (e.g.+573001112233). - A successful validation invalidates the OTP immediately; codes are single use.
- You do not need to send
destinationwhen validating — theotpIdcarries the context. - Call both endpoints from your backend so the API key is never exposed.