The webview is a single-page React app you embed inside your native app via
a WebView / Custom Tab. The URL is:
https://voucher.example.com/consumer#token=<JWT>
We also accept #access_token=<JWT> as a synonym, so partners that already
mint OAuth-style fragments don’t need to special-case our handler.
Use the URL hash, not a query string. Query strings end up in server
access logs and analytics; the hash fragment never leaves the user’s device.
What happens when the webview loads
- The page reads the JWT from
location.hash (#token= or #access_token=).
- It calls
GET /me with Authorization: Bearer <jwt> to bootstrap the
user and your brand block (logo, displayName).
- The catalog renders, scoped to your partner’s allowlist (if configured).
- The same JWT authenticates every subsequent
/me/* request.
Brand rendering
GET /me returns a partner object containing your brand assets. The
webview swaps its default chrome (e.g. GPS pill) for your logo when this is
present, so the embedded UI feels native to your app.
To change the logo, update it in our admin UI — the webview reads current
state on every page load, no deploy needed.
Token lifetime
- JWTs should be short-lived (≤ 1 hour
exp).
- If the JWT expires while the user is in the webview, the next API call
returns
401 invalid_token. The webview will show a “session expired”
state and your app should re-mint a fresh JWT and reload.
- There is no refresh-token flow between partner and us — the partner
app is the identity source and re-mints on demand.
Building your own UI instead
If you’d rather render the voucher list in your own native UI, skip the
webview entirely and call the Consumer API
directly with the same JWT.
You’ll still want to receive webhooks for redemption
events.