Skip to content

TurnKey ← VertexSMS — OTP / SMS Integration Brief

Integration instructions for TurnKey Lender, who owns the OTP / SMS / notification-provider integration under the Kaptl × TurnKey contract. Prepared by Kaptl, 16 July 2026.

1. Scope & ownership

The signed SOW lists "OTP / SMS / email provider" among the custom integrations TurnKey delivers. VertexSMS is Kaptl's SMS / Viber gateway. TurnKey integrates it server-side, inside its notification engine, and drives it from the events it already models:

  • OTP — phone verification at onboarding, and loan-document signing (POST /Customer/Loans/{loanId}/ResendSmsCode → borrower enters code → POST /Customer/Loans/{loanId}/SignDocument).
  • Transactional SMS — the 30+ notification triggers (approval, disbursement, due-date reminders, past-due, etc.).

The LOS front office never calls VertexSMS directly. The access token authorises spend on the account balance and must stay server-side.

2. Authentication

VertexSMS uses a single access token passed as the at query parameter on every request — no OAuth/bearer (auth model):

POST https://api.vertexsms.com/sms?at=<ACCESS_TOKEN>
  • Secret. The at token must live only in TurnKey's server config / secret store — never in a client, URL log, or repo.
  • Register at least one Sender ID (POST /senderId then POST /senderId/confirm/{id}) before sending — value [confirm on onboarding].
  • [confirm on onboarding]: token issuance/rotation, IP allow-listing, per-route balance/limits, and whether a separate test token is issued for UAT.

3. Sending — POST /sms

Body is application/x-www-form-urlencoded:

Field Notes
to Recipient MSISDN (international). Normalise first — see POST /numberCorrection.
from Sender ID (registered), e.g. Kaptl.
message Body. Mind GSM-7 vs UCS-2 (coding) for Cyrillic.
dlrUrl Delivery-report callback URL — a stable TurnKey endpoint.
testMode Intended to accept the request without sending — but the KB flags whether testMode is enabled, and its accepted value, as [confirm on onboarding]. Don't assume UAT is free until confirmed.
coding Message encoding (integer). Cyrillic (BG) copy needs UCS-2 — set this; GSM-7 default will mangle it and change per-part cost.
scheduled Send at a UTC time (optional).
expireIn Seconds until the message expires (optional).
correctBy Fix the recipient number by country (optional).

A 200 acknowledges acceptance; final delivery arrives asynchronously on dlrUrl (register and verify a DLR handler before go-live). Viber is available via POST /viber (fallback strategy is a TurnKey config choice).

4. OTP flow

VertexSMS has no dedicated OTP endpoint — OTP is an SMS carrying a code that TurnKey generates, stores with a TTL, and verifies:

sequenceDiagram
    participant BO as Borrower (Front Office)
    participant TK as TurnKey Server
    participant VX as VertexSMS

    BO->>TK: trigger (verify phone / sign document)
    Note over TK: generate code, store with 5-min TTL
    TK->>VX: POST /sms?at=•••  (to, from=<senderId>, message="code …")
    VX-->>TK: 200 accepted
    VX-->>BO: SMS with code
    BO->>TK: submit code (e.g. SignDocument / verify)
    Note over TK: compare + expiry (e.g. 5 min) + attempt-limit → pass/fail
    VX-->>TK: DLR callback → dlrUrl (delivered/failed)

TurnKey owns: code generation (cryptographically random), TTL/expiry, attempt throttling / lockout, resend (ResendSmsCode rate-limited), and idempotency so a resend doesn't invalidate a still-valid code prematurely.

5. Number handling & housekeeping

  • POST /numberCorrection (Number, country) — normalise/validate before sending; store the corrected MSISDN on the customer.
  • POST /hlr — async HLR lookup (subscriber/operator) with callback, if used for deliverability screening.
  • GET /rates/, /prefixes/{country}, /operators/{id}, /mccmnc/{country} — operational/reporting.

6. What Kaptl provides vs. what TurnKey builds

Kaptl provides TurnKey builds
VertexSMS access token (secret) + confirmed Sender ID Kaptl Server-side send via POST /sms (token injected, never exposed)
Message copy / templates (per trigger, BG/EN) OTP lifecycle: generate, TTL, verify, throttle, resend
DLR endpoint host + go-live sign-off A stable, verified dlrUrl receiver + delivery reconciliation
Sign-off on trigger list & rate limits Number correction before send; testMode in UAT

7. Reference (prototype)

The Kaptl LOS prototype's Tools → Notifications (SMS/OTP) console demonstrates the borrower OTP round-trip and shows the exact POST /sms request TurnKey issues. It is deliberately backend-agnostic: the token is never bundled, and real sends only happen through a server-side proxy — the same boundary TurnKey enforces in production. See kaptl-los-prototypesrc/api/vertexsms.ts.

8. Open items — [confirm on onboarding]

  1. Access token issuance + rotation; whether a separate UAT/test token exists (otherwise rely on testMode).
  2. Sender ID Kaptl registration/confirmation on the account.
  3. dlrUrl delivery-report contract (payload shape, retries) — verify a stable receiver before go-live.
  4. Encoding for Cyrillic (coding / UCS-2) and per-part cost.
  5. OTP policy: TTL, attempt limit, resend rate — align with TurnKey's document-signing flow (ResendSmsCode / SignDocument).
  6. Viber fallback: whether OTP/notifications fall back to POST /viber.