The referral dashboard is the fully featured partner view from partners.revroute.ru — link, share buttons, click and conversion stats, commission history, payout balance — rendered inline in your app.
Prerequisites
- Workspace API key with
partners.readpermission - A program created in your workspace
- The user has already been enrolled as a partner in that program (manually, via the application form, or by API)
@dub/embed-reactinstalled — see Installation
Mint the token
curl -X POST https://api.revroute.ru/tokens/embed/referrals \
-H "Authorization: Bearer $REVROUTE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"partnerId": "pn_5MhYz",
"programId": "prog_CYCu7IMAapjkRpTnr8F1azjN"
}'| Body field | Required | Description |
|---|---|---|
partnerId | one of these two | RevRoute partner id (pn_...) |
tenantId | one of these two | The partner’s external id in your system, if you mapped one when enrolling |
programId | yes | Which program’s dashboard to render |
Response:
{
"publicToken": "dub_embed_eyJhbGc...",
"expires": "2026-05-15T13:34:56.789Z"
}The token is valid for ~1 hour and is scoped to a single partner. Re-mint it on every page load — never cache across users.
Mount the component
import { DubEmbed } from "@dub/embed-react";
<DubEmbed
data="referrals"
token={publicToken}
style={{ width: "100%", height: "720px", border: 0, borderRadius: 12 }}
/>| Prop | Type | Required | Description |
|---|---|---|---|
token | string | yes | The publicToken from the embed-token endpoint |
data | "referrals" | yes | Selects which embed to render |
options | object | no | Theming and locale, see Theming |
style | CSSProperties | no | Inline styles applied to the wrapping <div> |
className | string | no | Class name applied to the wrapping <div> |
All other HTML props (id, data-*, aria-*, etc.) are forwarded to the wrapping <div>.
What the partner sees
The component shows tabs for:
- Overview — referral link, copy / share buttons, click + conversion stats, top countries
- Earnings — pending and paid commissions, with filters by status and date
- Payouts — confirmed payouts, current balance, expected next payout
- Resources — any landing pages or creatives uploaded to the program
Partners can copy their unique link, generate UTM-tagged variants, share via deep links, and view all their conversion history — without leaving your product.
Auto-enrolling new partners
A common pattern is to enroll users into the program lazily — i.e. mint the token on demand and pass a tenantId matching your internal user id; if no partner exists yet, RevRoute creates one and returns the new id.
const res = await fetch("https://api.revroute.ru/tokens/embed/referrals", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.REVROUTE_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
tenantId: user.id, // your internal id
programId: process.env.REVROUTE_PROGRAM_ID,
partner: { name: user.name, email: user.email }, // sent on first call
}),
});tenantId is unique within a workspace — subsequent calls return the same partner.
Resizing and layout
The embed has an internal scroll if its container is too small. Pick the height that fits your design and let the component scroll inside it. Avoid position: fixed parents — the iframe may misreport its size during reflows.
For responsive layouts, set height: 100% on a flex parent rather than relying on viewport units, which jump on mobile.
Listening to events (advanced)
The embed posts events to the parent window via postMessage. You can listen for them to drive your own analytics:
useEffect(() => {
function onMessage(e: MessageEvent) {
if (e.origin !== "https://app.revroute.ru") return;
if (e.data?.source !== "dub-embed") return;
// e.data.event: "link.copied" | "tab.changed" | "share.clicked" ...
track("embed_" + e.data.event, e.data.payload);
}
window.addEventListener("message", onMessage);
return () => window.removeEventListener("message", onMessage);
}, []);Only listen for events from https://app.revroute.ru — never trust untrusted origins.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Blank iframe, no errors | CSP blocks frame-src | Add frame-src https://app.revroute.ru to your CSP |
401 on token mint | Wrong / missing API key | Check Authorization: Bearer ... header |
404 partner not found | Wrong partnerId / tenantId | Verify the partner exists in this program |
| Component renders but shows “Session expired” | Token expired | Refetch the token, pass the new value to token= |
| Dark theme not applied | Theme set after first mount | Pass theme through options before mount; do not toggle CSS variables on the iframe wrapper |
See also: Theming and Installation.