Skip to main content

Use case

OTP for transaction verification and step-up approval

Challenge sensitive actions at the point of risk, while keeping the verification request tied to the original transaction.

3D isometric illustration of a smartphone approving a payment with an OTP code next to a credit card and shield

What the flow must protect

What the OTP shows

  • The person approving currently controls the destination registered for this account.
  • The otpId your application stored on that transaction was validated once, and your application accepts it for no other action.
  • The approval or denial is recorded with the attempts that led to it.

What it does not show

  • Informed consent to the payment. A code entered under pressure or social engineering still verifies.
  • That the transaction is legitimate. Your risk engine decides when a possession check is sufficient.
  • That a generic code is safe. Without binding, a code obtained in one flow can be replayed in another.

Where the flow breaks

  • Generic, context-free messages

    “Your code is 481920” tells the customer nothing about what they are approving, which is exactly what an attacker on the phone with them wants.

  • Codes not bound to the action

    If a code is valid for any pending challenge on the account, an attacker can trigger a harmless challenge and reuse the code against a payout.

  • Unpoliced fallback to a weaker channel

    Silently falling back to email for a wire transfer changes the risk profile of the approval without anyone deciding that it should.

  • Late codes approving stale transactions

    A code that arrives long after the transaction was created can authorise something the customer has already forgotten about, with no audit trail explaining the gap.

Transaction-binding checklist

A step-up code is only as strong as what it is bound to. This is what your application should tie to the challenge before treating it as an approval.

  1. otpId stored on the single transaction record

    How you verify it: the otpId returned by /otp/generate is written to that one transaction row, not to a general account field, so it cannot validate a different action.

  2. Amount, payee or action class

    How you verify it: the value at risk and the action type are captured alongside the otpId so validation can be checked against the transaction it was issued for.

  3. Actor and session

    How you verify it: the authenticated user and session that requested the action are recorded with the challenge, so approval cannot be attributed to the wrong actor.

  4. Expiry window

    How you verify it: a short, transaction-appropriate lifetime is enforced, and /otp/validate is expected to fail once it has passed.

  5. Permitted channels

    How you verify it: the channel policy for this transaction class is checked against what was actually used to deliver the code.

  6. Cancellation on amendment

    How you verify it: if the transaction is edited or withdrawn before approval, the stored otpId is invalidated so a stale code cannot approve a changed transaction.

  7. Recorded outcome

    How you verify it: approval, denial, channel and attempt history are written back to the transaction record for audit and dispute handling.

A production flow

  1. A risk event is raised

    Your payment, banking or workflow system flags an action such as a transfer, payout, beneficiary change or high-value approval.

  2. A transaction-bound challenge is created

    The otpId returned by /otp/generate is stored against that one transaction in your systems, so no other action can be approved with it.

  3. The message carries brand and limited context

    Include the amount, payee or action type where your regulator, channel policy and privacy rules permit.

  4. Route and fallback are applied

    Delivery follows the policy you set for this transaction class, including which channels are allowed at all.

  5. The code is validated against the otpId held on that transaction

    Your application looks up the otpId stored on that transaction and calls /otp/validate with it and the entered code, so a code obtained elsewhere cannot be applied here. Validation also fails after expiry or beyond the attempt limit.

  6. The code is consumed

    A redeemed code is dead, and any earlier live codes for the same transaction are invalidated.

  7. Approval or denial is recorded

    The outcome, the channel used and the attempt history are written to your transaction record for audit and dispute handling.

How Flow2FA fits

  • Binding stays in your own records

    Flow2FA returns an otpId. You store it on the transaction record and validate against it, so delivery data reconciles with the payment record.

  • Per-class channel policy

    Allow a broader set of channels for a card change and restrict a high-value payout to a narrower, approved set.

Controls to define, and what to measure

Controls to define

These are your decisions. Flow2FA carries and verifies the code; the policy stays yours.

  • Application-level binding of each otpId to a single transaction record
  • Short expiry windows appropriate to the transaction class
  • How much amount and payee context appears in the message
  • Attempt limits and lockout behaviour per transaction
  • Which channels are permitted, and whether fallback is allowed at all
  • Cancellation of challenges when the transaction is amended or withdrawn
  • Escalation to manual review or a stronger factor above defined thresholds
  • Retention of approval evidence for audit and dispute periods

What to measure

Measure completed verification, not accepted API calls. Acceptance and delivery receipts are progress indicators, not outcomes.

  • Transaction verification completion rate against challenges issued
  • Time from challenge creation to approval
  • Abandonment rate at the challenge step
  • Resend rate and failed attempts per transaction
  • Completion split by route, channel and market
  • Cost per completed approval, not cost per message sent

Integration options

Payment and core banking platforms often already have an SMPP path, while newer risk and workflow services call REST directly. In both cases the binding to a transaction lives in your own records rather than in a Flow2FA field.

Shared integration detail

REST vs SMPP, the provider model, routing and fallback, and full channel detail are covered once, in full, on the OTP API overview. For how to weigh those choices against your own requirements, see the buyer guide.

Channel availability depends on the setup configured for each account. The current public REST reference documents SMS and email channel values, while configured Flow2FA setups may also include WhatsApp.

Tie approvals to the transaction that triggered them

Bring one high-risk flow — a payout, a beneficiary change, a large transfer — and we will walk through binding, channel policy and the audit trail you would get.