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
attoken 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 /senderIdthenPOST /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-prototype →
src/api/vertexsms.ts.
8. Open items — [confirm on onboarding]¶
- Access token issuance + rotation; whether a separate UAT/test token
exists (otherwise rely on
testMode). - Sender ID
Kaptlregistration/confirmation on the account. dlrUrldelivery-report contract (payload shape, retries) — verify a stable receiver before go-live.- Encoding for Cyrillic (
coding/ UCS-2) and per-part cost. - OTP policy: TTL, attempt limit, resend rate — align with TurnKey's
document-signing flow (
ResendSmsCode/SignDocument). - Viber fallback: whether OTP/notifications fall back to
POST /viber.