Multi-currency display in Admaxxer — rates you set, applied everywhere
Admaxxer ingests revenue in whatever currency your Shopify store, ad accounts, and revenue connectors emit (PKR, USD, EUR, GBP, INR, …). The display layer lets each user pick how they want to read the dashboard — Native (each tile in its source currency), a specific currency (USD, EUR, GBP, …), or fall through to Unset (native amount + a “Set rate” link). Conversions use rates you set yourself, per workspace. There is no third-party rate API, no auto-fetch, no daily drift — your accountant or finance team owns these rates.
Three display modes
The display-currency picker (top-right of the dashboard) sets a per-user preference. Three values matter:
- Native (default)
- Every tile renders in the currency that the underlying data row carries. A Shopify-PKR store renders
Rs 2,054; a Meta-USD ad account renders$120.00; a Klaviyo-EUR account renders€85.00. No conversion happens. Best for finance teams who want the source-of-truth ledger and compare against the platform’s own reporting. - Specific currency (USD, EUR, GBP, …)
- Every money tile is converted to your chosen currency using the rates you set in Settings › Exchange rates. A Shopify-PKR row of
Rs 2,054renders as$7.30when you’ve set1 USD = 281.45 PKR. Same-currency rows pass through unchanged. Best for cross-platform brand-level summaries when accounts span multiple currencies. - Unset
- When you’ve picked a display currency but no rate is set for a tile’s source-currency pair, the tile shows the native amount plus a small ⚠ badge. The tooltip explains the rate isn’t set and links straight to Settings › Exchange rates so you can fix it in one click.
Why user-set rates (and not an API fetch)
Three reasons we chose this model:
- Accounting convention. Most finance teams pick a single fixed rate per period (quarterly or monthly) and want every report — including Admaxxer — to use that exact rate. Auto-fetched market rates create drift between Admaxxer and your books.
- No external dependency or rate-limit footgun. Rate APIs go down, rate-limit, or change pricing. Removing that dependency means your dashboard’s conversion can never be blocked by a third-party outage. Your rates always apply, instantly.
- Rates always reflect your books, not the market. Reconciliation between Admaxxer and your ledger is exact. No “why does Admaxxer show $7.30 when our books say $7.25?” conversations. The rate you set is the rate the dashboard uses.
How rates apply
Each rate you set is a workspace-scoped (base, target, multiplier) tuple that applies uniformly across:
- All dates. The same rate applies to today’s revenue, last week’s revenue, and historical drill-ins. We do not apply different rates to different dates.
- All tiles. Every tile in every dashboard that renders the (base → target) pair uses the same rate. Updating a rate immediately re-renders every tile.
- All members of the workspace. Rates are workspace-scoped. The display-currency picker is per-user, but the conversion table behind it is shared.
This is a deliberate simplification compared with per-row historical rates. In an accounting context the rate is usually fixed per period anyway — and storing a single multiplier per pair makes audit, reconciliation, and rate updates trivial.
Mixed-currency workspaces
If your data sources span multiple currencies, set rates for every pair you want to display in. Examples:
| Setup | Rates to set | Result |
|---|---|---|
| Meta-USD + Shopify-PKR, viewing in USD | PKR → USD |
Meta tiles pass through; Shopify tiles convert. |
| Above + Klaviyo-EUR, still viewing in USD | PKR → USD + EUR → USD |
All three sources normalize to USD; brand-level sum row renders. |
| Same workspace, viewing in EUR | USD → EUR + PKR → EUR |
Klaviyo tiles pass through; Meta + Shopify convert. |
| Native mode (default) | None needed | Each tile in its source currency. Brand-level sum row is hidden when sources differ. |
Tiles in pairs you haven’t set a rate for fall back to native + a “Set rate” tooltip — the dashboard never blanks out, but you also never see a fabricated value.
Tooltip on every converted tile
When a tile is showing a converted value, hovering reveals the source-of-truth context:
Native: Rs 2,054
Rate: 1 USD = 281.45 PKR
This is more than UI polish — it’s the audit trail. A finance reviewer can spot-check a tile against Shopify’s admin, confirm the source amount matches, then verify the conversion math without leaving the dashboard. If the rate looks wrong, the same workspace member can update it in Settings › Exchange rates and watch the tile re-render. When a rate isn’t set the tooltip shows the native amount plus a “Set rate” link to that settings page.
Tooltips are radix-based, animated with framer-motion, and respect prefers-reduced-motion. They never appear when no conversion is happening (Native mode, or same-currency rows).
How to manage exchange rates
- Add a rate. Open Settings › Exchange rates and click Add rate. Pick the base and target currency, type the rate, and save. The dashboard updates immediately.
- Edit a rate. Click the pencil icon on a row to update the rate. The base/target pair is fixed (changing it would be a different rate); update the number and save.
- Delete a rate. Click the trash icon to remove a rate. Tiles in that currency pair fall back to native display with the “Set rate” tooltip.
Default: new workspaces start with no rates set, so every tile renders in its source currency by default. Single-currency workspaces never need to set a rate.
API: workspace exchange rates
The endpoints under /api/v1/workspaces/:workspaceId/exchange-rates are session-authed and workspace-membership verified. Both the dashboard UI and the AI agent (Maxxer) consume them.
GET /api/v1/workspaces/:workspaceId/exchange-rates
→
{
"rates": [
{
"baseCurrency": "PKR",
"targetCurrency": "USD",
"rate": 0.00355,
"updatedAt": "2026-04-29T14:00:00Z",
"updatedByUserId": "u_…"
}
]
}
PUT /api/v1/workspaces/:workspaceId/exchange-rates
body: { "baseCurrency": "PKR", "targetCurrency": "USD", "rate": 0.00355 }
→ { "ok": true, "rate": { … } }
DELETE /api/v1/workspaces/:workspaceId/exchange-rates/:base/:target
→ 204 No Content
FAQ
Why doesn’t Admaxxer auto-fetch rates from an API?
Three reasons: (1) accounting convention — most finance teams pick a single fixed rate per period and want their reporting to match that; (2) no external dependency or rate-limit footgun — a third-party rate API outage can never blank your dashboard; (3) rates always reflect your books, not the market, so reconciliation between Admaxxer and your ledger is exact.
Do conversions affect what I’m billed for?
No. Display currency is a UI preference. Stripe still bills in the currency tied to your subscription, and Tinybird still stores the source amount and source currency unchanged. Conversion happens at render time only.
Can the AI agent (Maxxer) read converted values?
The agent reads the underlying source-currency data via Tinybird pipes. When it composes a response (e.g. “your Meta spend was $4,200 last week”), it formats in your display currency for readability — using the same rates you’ve set in Exchange rates as the dashboard.
What happens for currencies I haven’t set a rate for?
The tile falls back to native display with a small ⚠ badge. Hover for a tooltip explaining the rate isn’t set, with a “Set rate” link to /settings/exchange-rates. The dashboard never goes blank on a missing rate.
How often should I update rates?
Match your accounting cadence. Most finance teams pick a quarterly or monthly rate. There’s no penalty for changing it — every tile re-renders on the new rate immediately. We don’t track historical rate edits; if you need that audit trail, capture it in your accounting system.
Can different members of the workspace see different rates?
No. Rates are workspace-scoped — one rate per (base, target) pair. The display-currency picker is per-user, but the conversion table behind it is shared.
Related documentation
Settings → Exchange rates (set rates) · Tinybird auth model · Bring your own Anthropic key · Analytics deep dive · Marketing Acquisition dashboard · Documentation home