OctoWiki
Vendor AdaptersVoucher Vendors

iRewardify — IRW

Voucher vendor adapter — lazy bearer login, custom unsigned webhook, two-phase async delivery with dual code/link formats.

Quick facts

Code IRW · Line voucher · Auth bearer (login → 23h in-memory token) · Model async (create → poll → deliver) · Webhook custom, unsigned · Delivery card code+pin or claim link+challenge · Adapter services/external_vendors/vouchers/irewardify_vendor.go · Tests orchestration + mocky (no contract test)

IRewardifyVendor embeds BaseVendor + auth state (irewardify_vendor.go:22); registered in factory.go:58. Seeded IsAsync:true, HasWebhook:true, MaxQuantity:1. Host already includes /api/v1.

Auth

AuthPOST {Host}/customer/login {email:username, password}token stored in memory with a synthetic now+23h expiry (the vendor gives no expiry). getAuthConfig refreshes lazily when the token is empty/expired and returns a bearer config. RedoAuth clears memory + removes a Valkey key, then re-auths.

The "cached auth token" is aspirational. The Valkey key irewardify:auth_token:<username> is removed in RedoAuth but never written anywhere — real caching is in-process only, so each new instance re-authenticates. Don't rely on cross-pod token sharing.

vendor_attributes: host, username (used as email), password. No api_key/timeout/delay.

Catalog

GetCatalogBatched only. Two-step: GET /customer/products (listing) → a 10-worker pool fetches GET /customer/products/{_id} per product. Each product's variants[] → one Product with fixed denomination (min==max==variant_price). CreateOrder needs both VendorProductID (Mongo _id) and SKU (variant.item_id).

Discount/markup come from the listing API, not the detail (detail returns 0) — the code carries them forward. discounted && discount>0 → use discount; else markup>0negative discount = markup/premium.

Order create

POST {Host}/checkout — a single-item order with hard-coded N/A shipping/billing filler (digital). Async: returns no vouchers, StatusAccepted + ShouldRetry; captures orderId for polling. Create errors inspect the message: "external ID already exists" → duplicate, no retry; "Insufficient funds" → retry.

Order status / poll

GET {Host}/order-details/{orderId}. 404/400 or body "not found" → ErrShouldReCreate (orchestrator re-creates). Status map: Rewards Delivered→complete; Partial Rewards Delivered→partial; Funding Received/Processing→processing; Failed→failed + ShouldReCreate; anything else→processing (keep polling). Vouchers are not returned here.

Webhook

Overrides NormalizeWebhookPayload for the custom shape {orderId, event, status, message}. Delivered to POST /webhooks/vendor/IRW.

Unsigned. Production webhooks carry no signature; with no webhook_secret the factory uses a NoopWebhookVerifier. Idempotency key = orderId:status (one webhook per status transition is deduped).

Delivery

GET {Host}/order/delivery/{orderId}; message "not ready yet" → keep polling (no error). parseDeliveryItem auto-detects two formats:

  • Card (cardCode present): Code=cardCode, Pin=pin (polymorphic string/number), expiry 2006-01-02 or now+365d default.
  • Link (ClaimLink/Id present): Code=ClaimLinkChallengeAnswer, ClaimURL=ClaimLink, expiry now+1yr.

Reference numbers are IRW_<id>.

Balance

GET {Host}/customer/wallet → three named floats (walletOne/Two/Three) → three BalanceResponse rows (VendorWalletID = "WalletOne"…). No vendor currency — uses the passed currencyCode or defaults USD.

Quirks

  • Two-phase async delivery: create → /order-details (poll) → /order/delivery (codes).
  • ErrShouldReCreate on 404/400/"not found"/vendor Failed.
  • Dual delivery formats auto-detected in one endpoint.
  • CancelVoucher posts to /order/{id}/cancel (or /order/cancel by reference); ProductAvailability stubbed to true.
  • Reference codes IRW-<base>-<unix> (uniqueness matters — duplicate external ID is non-retryable).

Tests, mock, docs

Mocky route frontend/mocky-balboa/src/routes/irewardify.ts (login/products/checkout/order-details/delivery/wallet + _mock/complete|auto-fulfill|webhook-url|refund-balance). Orchestration test test/clientapi/irewardify_orchestration_test.go covers create→poll→deliver, retries, invalid-creds, insufficient-funds, out-of-stock, and the unsigned webhook POST. No dedicated Go contract test. Postman collection under docs/iRewardify/.

On this page