OctoWiki
Vendor AdaptersTop-up Vendors

Wupex — WPX (top-up)

Direct-topup vendor adapter — static API-key, gaming/game-account recharge with server/zone lookup, rich HTTP-status failure mapping.

Quick facts

Code WPX · Line direct-topup · Auth static x-api-key (via CustomHeaderAuth) · Model synchronous, terminal-on-success · Webhook explicitly unsupported · Adapter services/external_vendors/direct_topup/wupex/

The top-up half of Wupex — a separate adapter from the voucher one, sharing only the upstream API + the WPX DB row. Registered direct_topup/factory.go:180. See Order Lifecycle.

Auth

Static x-api-key header via CustomHeaderAuth. Requires api_key and merchant_code in Credentials (errors if absent — stricter than the voucher adapter's Username fallback), plus host.

Catalog

Both methods back onto POST /api/product/merchant/invited/list {page, pageSize:100, search:[cardType=topup]}. No Cloudflare/429 backoff here (unlike the voucher adapter).

  • GetCategories — groups topup products by productType; builds a required userId field, and probes each SKU via POST /api/order/topup-listservers?sku=X to optionally add a serverId select field.
  • GetProducts(categoryID) — filters cardType=topup AND productType=categoryID; CurrencyCode:"USD" hardcoded, MinAmount=MaxAmount=FaceValue, IsFixedAmount:true, AutoDelivery:true, VendorDiscount:DiscountRate. ShouldSyncVariants()=true (small catalog).

Server-list shape mismatch: the adapter parses JSON-RPC data.result.servers[].{id,name}, but the mocky route returns [{serverId, serverName, region}] — the mock shape would parse to zero servers. Worth reconciling.

Order create

POST /api/order/topup {merchant, sku, quantity:1, userAccount} — quantity hardcoded 1; userAccount built from non-empty userId/serverId/zoneId. Synchronous: status:trueTopUpStatusProcessing + VendorOrderID = orderName.

Error handling (its biggest differentiator, error_messages.go): transient status (408/429/5xx) → leave Status="" (PENDING for retry); non-transient 4xx → failureFromHTTPStatus → terminal FAILED (400→InvalidRecipient, 422→AmountOutOfRange, 401/403/409/413→Unknown); 2xx with status:falseUNKNOWN (Wupex's error.code catalog is undocumented, so it carries error.message as the reason); unparseable 2xx → poll rather than burn.

Order status / poll

GET /api/order/detail?orderName=<id> — status inferred: status:true + data → complete (parses orderDateCompletedAt); else → ErrOrderNotFound. SupportsExternalOrderRef()=false (needs the vendor orderName).

Webhook

Explicitly unsupportedVerifyWebhookSignature returns false; ParseWebhook errors "wupex does not support webhooks".

Delivery / balance

Topups are account credits — no serials; success yields VendorOrderID + a message. GetBalance = GET /api/customer/balancecreditBalance, USD (Ping reuses it). SupportsLookup()=false.

Tests, docs

Only error_messages_test.go (unit) — no topup orchestration/contract test. Mocky route frontend/mocky-balboa/src/routes/wupex.ts (shared with voucher). Docs docs/wupex/.

On this page