One-Time Passwords (OTPs)

One-Time Passwords (OTPs) enable secure verification flows where you need to confirm user identity or authorize sensitive actions. Generate time-limited tokens, deliver them to recipients, and verify submissions with built-in protection against brute-force attacks and token reuse.

The OTP transaction object

An OTP transaction represents a complete verification session from token generation through delivery and verification. Each transaction tracks delivery status, expiration time, and verification attempts.

Properties

  • Name
    cancel_reason
    Type
    string|null
    Description

    Human-readable explanation for why this transaction was canceled. Present only when status is canceled.

  • Name
    canceled_at
    Type
    timestamp|null
    Description

    When this transaction was explicitly canceled. Present only when status is canceled.

  • Name
    expires_at
    Type
    timestamp
    Description

    When this token expires and can no longer be verified.

  • Name
    full_message
    Type
    string
    Description

    The message template with service name substituted but token placeholder preserved as {token}. The actual token value is never included in this field for security—only the recipient receives the token via their delivery channel (SMS, WhatsApp, or email).

  • Name
    id
    Type
    string
    Description

    Unique identifier for this transaction—use it to verify tokens and lookup transaction status.

  • Name
    initiated_at
    Type
    timestamp
    Description

    When this transaction was created and token generation began.

  • Name
    status
    Type
    string
    Description

    Current transaction status. Possible values: pending, verified, expired, canceled.

  • transmissionobjectDelivery details for the OTP message. Present only after delivery attempt begins.Click or tap to expand
    • Name
      recipient
      Type
      string
      Description
      Recipient identifier where the OTP was sent (e.g., +233241234567 for phone numbers, user@example.com for email addresses).
    • Name
      sender_id
      Type
      string
      Description
      Sender identifier shown to the recipient—alphanumeric sender ID or short code.
    • Name
      sent_at
      Type
      timestamp|null
      Description
      When the message was sent. Present only after delivery attempt.
    • Name
      sent_via
      Type
      string|null
      Description
      How the OTP was delivered: sms, whatsapp, or email depending on recipient type. Phone numbers use SMS or WhatsApp, email addresses use email. Present only after delivery attempt.
    • Name
      status
      Type
      string|null
      Description
      Delivery status: submitted, delivered, or failed. Present only after delivery attempt.

POST/otp/initiate

Initiate OTP transaction

Generate a one-time password, deliver it to the recipient, and return a transaction ID for verification. The token is securely generated and never stored in plain text. Supports custom message templates and idempotency to prevent duplicate sends.

Required attributes

  • Name
    idempotency_key
    Type
    string
    Description

    Unique key to prevent duplicate OTP sends during retries. If a transaction with this key already exists, that transaction is returned instead of creating a new one. Length: 16-128 characters. Use UUIDs, timestamps with random suffixes, or request IDs from your system.

  • Name
    recipient
    Type
    string
    Description

    Recipient identifier where the OTP will be delivered. For phone numbers, use international format (e.g., +233241234567, +12065551234). For email addresses, use standard email format (e.g., user@example.com). Delivery method is automatically determined by recipient type—phone numbers receive SMS or WhatsApp, email addresses receive email. Invalid formats are rejected with clear error messages.

  • Name
    sender
    Type
    string
    Description

    Sender identifier shown to the recipient. Alphanumeric sender ID (e.g., YourApp, ACME) or short code. Length: 3-11 characters.

  • Name
    service_name
    Type
    string
    Description

    Your service or application name shown in the message. Substituted for the {service} placeholder in message templates. Length: 3-30 characters. Example: Acme Bank, ShopFast, MyHealth.

Optional attributes

  • Name
    message_template
    Type
    string
    Description

    Custom message template for the OTP. Must include {token} placeholder for token substitution and optionally {service} for service name. Example: Your {service} verification code is {token}. Valid for 10 minutes. If not provided, uses system default template. Max length after substitution: 160 characters (SMS limit).

  • Name
    purpose
    Type
    string
    Description

    Purpose of this OTP for your own analytics and filtering. Example values: login, passwor_reset, transaction_confirm, 2fa, account_recovery.

  • Name
    token_alphabet
    Type
    string
    Description

    Custom alphabet for token generation. Pass a string of characters to use (e.g., 0123456789ABCDEF for hexadecimal tokens). Mutually exclusive with token_alphabet_type—use one or the other, not both.

  • Name
    token_alphabet_type
    Type
    enum
    Description

    Predefined alphabet type for token generation. Supported values: numeric (0-9 only, most user-friendly), alpha (A-Z and a-z, case-sensitive), alphanumeric (0-9, A-Z, a-z). Defaults to numeric. Mutually exclusive with token_alphabet.

  • Name
    token_size
    Type
    integer
    Description

    Length of the generated token in characters. Must be between 4 and 10. Shorter tokens are easier to type but less secure. Recommended: 6 for most use cases, 8 for high-security scenarios.

  • Name
    validity_duration_in_minutes
    Type
    integer
    Description

    How long the token remains valid in minutes. Must be between 1 and 60. Shorter durations are more secure but may increase user friction. Typical: 5-15 minutes.

Request

POST
/otp/initiate
curl https://api.zebo.dev/otp/initiate \
  -H "Authorization: Bearer {api_key}" \
  -H "Content-Type: application/json" \
  -d '{
    "idempotency_key": "txn_67890_otp_20231215",
    "recipient": "+233241234567",
    "sender": "Acme",
    "service_name": "Acme Bank",
    "message_template": "Your {service} code is {token}. Valid for 10 minutes.",
    "token_alphabet_type": "numeric",
    "token_size": 6,
    "validity_duration_in_minutes": 10,
    "purpose": "transaction_confirm"
  }'

Response

{
  "transaction": {
    "id": "3f8a9c7e2d1b4a6f",
    "status": "pending",
    "full_message": "Your Acme Bank code is {token}. Valid for 10 minutes.",
    "initiated_at": 1702656000,
    "expires_at": 1702656600,
    "canceled_at": null,
    "cancel_reason": null,
    "transmission": {
      "recipient": "+233241234567",
      "sender_id": "Acme",
      "sent_via": "sms",
      "status": "submitted",
      "sent_at": 1702656001
    }
  }
}

POST/otp/verify

Verify OTP

Verify a one-time password by comparing the user-submitted token against the transaction. Enforces attempt limits to prevent brute-force attacks. Expired or canceled transactions are rejected immediately.

Required attributes

  • Name
    recipient
    Type
    string
    Description

    Phone number that received the OTP. Must match the recipient from the initiation request.

  • Name
    token
    Type
    string
    Description

    The OTP token submitted by the user. This is the code they received via SMS. Cannot be blank or whitespace-only.

  • Name
    transaction_id
    Type
    string
    Description

    ID of the OTP transaction returned from /otp/initiate.

Request

POST
/otp/verify
curl https://api.zebo.dev/otp/verify \
  -H "Authorization: Bearer {api_key}" \
  -H "Content-Type: application/json" \
  -d '{
    "transaction_id": "3f8a9c7e2d1b4a6f",
    "recipient": "+233241234567",
    "token": "847293"
  }'

Response (Success)

{
  "transaction": {
    "id": "3f8a9c7e2d1b4a6f",
    "status": "verified",
    "full_message": "Your Acme Bank code is {token}. Valid for 10 minutes.",
    "initiated_at": 1702656000,
    "expires_at": 1702656600,
    "canceled_at": null,
    "cancel_reason": null,
    "transmission": {
      "recipient": "+233241234567",
      "sender_id": "Acme",
      "sent_via": "sms",
      "status": "delivered",
      "sent_at": 1702656001
    }
  }
}

POST/otp/lookup

Lookup OTP transaction

Retrieve details of an existing OTP transaction by its ID. Check transaction status, delivery state, and verification status.

Required attributes

  • Name
    transaction_id
    Type
    string
    Description

    ID of the OTP transaction to lookup. Must belong to your application.

Request

POST
/otp/lookup
curl https://api.zebo.dev/otp/lookup \
  -H "Authorization: Bearer {api_key}" \
  -H "Content-Type: application/json" \
  -d '{
    "transaction_id": "3f8a9c7e2d1b4a6f"
  }'

Response

{
  "transaction": {
    "id": "3f8a9c7e2d1b4a6f",
    "status": "pending",
    "full_message": "Your Acme Bank code is {token}. Valid for 10 minutes.",
    "initiated_at": 1702656000,
    "expires_at": 1702656600,
    "canceled_at": null,
    "cancel_reason": null,
    "transmission": {
      "recipient": "+233241234567",
      "sender_id": "Acme",
      "sent_via": "sms",
      "status": "delivered",
      "sent_at": 1702656001
    }
  }
}

POST/otp/cancel

Cancel OTP transaction

Cancel an active OTP transaction to prevent further verification attempts. Cancel when a user requests a new OTP, when suspicious activity is detected, or when the authentication flow is abandoned. Canceled transactions cannot be verified even if the token hasn't expired.

Required attributes

  • Name
    reason
    Type
    string
    Description

    Human-readable explanation for cancellation. Example: user_requested_new_code, suspicious_activity, session_expired, user_abandoned_flow.

  • Name
    transaction_id
    Type
    string
    Description

    ID of the OTP transaction to cancel.

Request

POST
/otp/cancel
curl https://api.zebo.dev/otp/cancel \
  -H "Authorization: Bearer {api_key}" \
  -H "Content-Type: application/json" \
  -d '{
    "transaction_id": "3f8a9c7e2d1b4a6f",
    "reason": "user_requested_new_code"
  }'

Response

{
  "transaction": {
    "id": "3f8a9c7e2d1b4a6f",
    "status": "canceled",
    "full_message": "Your Acme Bank code is {token}. Valid for 10 minutes.",
    "initiated_at": 1702656000,
    "expires_at": 1702656600,
    "canceled_at": 1702656120,
    "cancel_reason": "user_requested_new_code",
    "transmission": {
      "recipient": "+233241234567",
      "sender_id": "Acme",
      "sent_via": "sms",
      "status": "delivered",
      "sent_at": 1702656001
    }
  }
}

Was this page helpful?