DT One (Top-up)
Direct-topup vendor adapter — mobile recharge over DT One DVS, Basic auth, async transactions, poll-driven (no webhook by default), reference min/max/discount mapping.
Quick facts
Code DTONE (service_id=1, Mobile) · Line direct-topup (mobile recharge) · Auth HTTP Basic · Model async (/v1/async/transactions, auto-confirm) · Webhook supported but not seeded (poll-driven by default) · Lookup yes · Adapter services/external_vendors/direct_topup/dtone/
DT One DVS mobile recharge. The eSIM sibling is a separate adapter — see DT One eSIM. DT One is the reference implementation for min/max/discount mapping. Registered direct_topup/factory.go:178. See Order Lifecycle.
Auth
HTTP Basic (username/password). Credentials: host, username, password, optional service_id (defaults "1"). Prod host https://dvs-api.dtone.com. Default timeout 30s.
Catalog
GetCategories—GET /v1/operators?service_id=1&per_page=100→ oneCategoryper operator; each carries a requiredmobile_numberphone input (regex^[0-9]{7,15}$, "without country code"). Image fromoperator-logo.dtone.com/logo-%d-2.png.GetProducts(operatorID)—GET /v1/products?operator_id=....mapProduct(the reference):IsFixedAmount = HasPrefix(Type, "FIXED_VALUE_"); when fixed,MinAmount = MaxAmount = Destination.Amount;VendorDiscount = ((retail − wholesale)/retail)×100;Price = Wholesale.Amount. RichbuildVariantFieldsmetadata (benefits, validity, pricing, fx_rate, DT-One ids).ShouldSyncVariants()=false(lazy);SupportsExternalOrderRef()=true.- Lookup:
SupportsLookup()=true—POST /v1/lookup/mobile-numberreturns operators (first flaggedIdentified).
Order create
POST /v1/async/transactions {ExternalID: merchantOrderID, ProductID, AutoConfirm:true, CreditPartyIdentifier: InputData} (+ CallbackURL only if configured). Error decision tree: 1007001 duplicate → ErrDuplicateMerchantRef; transient 408/429/5xx → leave status empty (stay PENDING, don't burn the order/refund on a blip); parseable error → FAILED with failure fields; network → PENDING.
Order status / poll
GET /v1/transactions/?external_id={merchantOrderID}. 1008004 not-found → ErrOrderNotFound; empty array → ErrOrderNotFound; CompletedAt from ConfirmationDate. Poll driver: jobs/topup_order_retry_job.go.
Webhook
No default webhook. The topup seeder omits callback_url, so recharges are poll-driven out of the box. VerifyWebhookSignature always returns true — DT One documents no signature; defence is a per-merchant secret URL + IP allowlist. Route POST /webhooks/direct-topups/:vendor_code.
Two webhook persistence paths. The active path writes to vendor_webhook_logs (idempotency key vendorOrderID:merchantOrderID:status). The direct_topup_webhooks table + repo appears to be legacy/dead code — no non-repo callers found. Confirm with the team before relying on it.
Delivery / balance
Recharge lands directly on the subscriber's mobile_number — no PIN/QR; delivery is expressed purely via status + ConfirmationDate. GetBalance = GET /v1/balances ([0].Available); Ping = GET /v1/services/1.
Failure taxonomy & INSUFFICIENT-BALANCE
mapStatus treats REJECTED/DECLINED-INSUFFICIENT-BALANCE, -OPERATOR-CURRENTLY-UNAVAILABLE, and -DUPLICATED-TRANSACTION as transient → PENDING (matched before the generic REJECTED/DECLINED fallback), so the retry loop keeps polling and no failure_code is written. HTTP code 1006001 (float low) → FailureUnknown (pages ops rather than hard-failing the customer). Sub-status table maps INVALID/BARRED/INELIGIBLE-CREDIT-PARTY and limit codes to canonical failures. Sentinels 1007001/1008004 excluded from the HTTP map and handled specially; 5xx/429/408 entries are effectively dead code (short-circuited by isTransientHTTPStatus).
Tests, mock, docs
Contract (dtone_contract_test.go, build tag contract) + error-mapping unit test, against mocky (frontend/mocky-balboa/src/routes/dtone.ts, serves both services). Docs under docs/dtone/. Live docs: dvs-api-doc.dtone.com.
SEAGM
Direct-topup vendor adapter — gaming recharge, HMAC-SHA256 query-string signing, async with signed inbound webhook and a rich failure taxonomy.
Wupex — WPX (top-up)
Direct-topup vendor adapter — static API-key, gaming/game-account recharge with server/zone lookup, rich HTTP-status failure mapping.