Skip to main content
The portal is the consumer face of the universal identity. A customer signs in with their email and a one-time code (no password) and lands on a redesigned dashboard that shows — and manages — everything they hold across every Duro merchant: their subscriptions, their wallet, their cards, and their virtual account.

The dashboard

/portal is a minimalist, mobile-responsive dashboard. On desktop it’s a sidebar layout; on mobile it collapses to a bottom-nav with a drawer. Five sections:

Overview

Balance, next charges, and active subscriptions at a glance.

Wallet

The global balance and its transaction history, with a top-up modal that opens the same inline checkout used everywhere.

Subscriptions

Every subscription grouped by merchant, with cancel / pause / resume where the merchant allows.

Cards, transfer & direct debit

Saved cards (add / remove), an optional dedicated bank account for funding by transfer, and direct-debit mandates that let renewals pull straight from a bank account.

Listing across merchants

A customer’s subscriptions live in many tenants (one per merchant they’ve paid). The portal finds them all by the account’s email, then their plans and merchant names — in a fixed number of batched queries, never N+1: Four queries regardless of how many merchants or subscriptions — customers, subscriptions IN, plans IN, tenants IN — then grouped by tenant into per-merchant cards.
Live mode only. Real customers see live. The portal reads exactly the live schema — it never merges test and live data.

Ownership is enforced on every action

Reads are filtered by the account’s email. Actions (cancel, pause, resume, remove card) re-verify ownership before touching anything: A stranger with a valid session for a different email cannot read or mutate someone else’s subscription — the customer’s email is loaded from the subscription and compared against the session subject before any state change.

What the customer can do

  • See every subscription, grouped by merchant, with plan, next charge, and status.
  • Top up the wallet — an arbitrary amount via the inline checkout, funding future renewals in advance.
  • Manage cards — add a card (a ₦100 top-up that saves it), or remove one (blocked if it’s the last card while a subscription is active).
  • Request a virtual account — a dedicated bank account, funded by transfer, crediting the wallet automatically.
  • Authorise a direct-debit mandate, bank-account permission that becomes a fallback rail once activated.
  • Set a transaction PIN and phone number: a self-service PIN (GET/PUT/DELETE /portal/email/pin) and a Nigerian phone on the account, both authenticated by the portal session.
  • Pause / resume / cancel where the merchant allows.
The portal session is a bearer token presented in the x-portal-session header; every authenticated action re-issues a freshly-slid token in the response’s x-portal-session header, so an active session keeps extending as the customer uses it.

Sign-in captures location — for the merchant’s security alert

The dashboard login requests browser geolocation, but only to enrich a security alert — it is capture-only and never blocks. If the customer denies the prompt, the sign-in proceeds exactly the same; the coordinates are simply omitted. That capture feeds the merchant-side security alerts: a sign-in records the IP, the device, and (if granted) the coordinates onto the Session, and the business owner is emailed an alert with a Google-Maps link to the location. See the security model for the full alert set. Next: the wallet that powers the top-up and renewal story.