DEV Community

BridgeXAPI
BridgeXAPI

Posted on

OTP flows on programmable SMS routing: a FastAPI implementation

Most OTP examples stop too early.

They show how to generate a code, store it somewhere, and send an SMS through a provider that hides routing behind a black box.

That works for demos.

It breaks down when routing, pricing and delivery behavior matter.

At BridgeXAPI, messaging is approached differently.

Routing is not hidden.

It is part of the application.

To demonstrate that, we built a FastAPI OTP service on top of programmable SMS routing.


This is not just an OTP example

This is an example of what authentication flows look like when routing, pricing and delivery are part of your system — not abstracted away by a provider.


The routing model

Most messaging APIs follow this pattern:

  • you define the message
  • the provider selects the route
  • pricing and delivery behavior are opaque

In this model, routing is a black box.

BridgeXAPI follows a different approach:

  • the developer selects the route (route_id)
  • pricing is tied to that route
  • delivery behavior becomes predictable
  • routing decisions live in application code

This matters for OTP systems.

A login code is not the same as bulk messaging.

The delivery path should be explicit.


The FastAPI service

The service exposes two endpoints:

  • POST /send-otp
  • POST /verify-otp

Example request:

{
  "phone_number": "31651860670",
  "purpose": "login",
  "route_id": 3
}
Enter fullscreen mode Exit fullscreen mode

Example response:

{
  "status": "otp_sent",
  "phone_number": "*******0670",
  "purpose": "login",
  "route_id": 3,
  "expires_in_seconds": 300,
  "cooldown_seconds": 45,
  "debug_code": "816369",
  "bx_message_id": "BX-22229-1d5e5779b1904695",
  "order_id": "22229",
  "delivery_status_url": "https://hi.bridgexapi.io/api/v1/dlr/BX-22229-1d5e5779b1904695"
}
Enter fullscreen mode Exit fullscreen mode

The important part is not just "OTP sent".

The response includes:

  • bx_message_id
  • order_id
  • delivery_status_url

These are infrastructure-level identifiers.

They allow the application to track delivery state, not just submission.


Security and flow

The service implements:

  • OTP hashing using HMAC
  • expiration (TTL)
  • resend cooldown
  • attempt limits
  • masked phone numbers in responses

For development, a debug mode can expose the OTP code in responses.

This should be disabled in production.


Storage model

This example uses an in-memory store.

The goal is to keep the flow clear:

  • generate OTP
  • send via explicit route
  • store hashed state
  • verify

In production, this would be replaced with Redis or another persistent backend.

The API contract remains the same.


Why this approach

Most OTP implementations treat messaging as a side-effect.

This implementation treats messaging as part of the system design.

Routing is explicit.

Delivery is observable.

Pricing is predictable.

The application owns these decisions.


GitHub

https://github.com/bridgexapi-dev/bridgexapi-fastapi-otp


Docs

https://docs.bridgexapi.io

Top comments (1)

Collapse
 
bridgexapi profile image
BridgeXAPI

This is part of a broader direction: exposing messaging infrastructure instead of hiding it behind APIs.