Embedded merchant panel
Drop the merchant's full NexusPay panel into your own app — one iframe, six tabs — without building any of the UI yourself. One backend call mints a short-lived token, one <iframe> renders the shell with Payments, Payouts, Balance, Invoices, Customers, and Events tabs.
How it works
Your backend (using your sk_* key) calls POST /v1/embed_tokens with surface="panel" and the project the iframe should show. We return a signed token that expires in 30 minutes by default. You drop that token into an <iframe> URL pointing at /embed/panel/<uuid> and the full tab-strip panel renders. The optional tabs array lets you restrict which tabs are available — useful if you want to show only Payments and Balance on a partner dashboard, for example.
Each token is bound to one project and one surface. A panel token cannot unlock the standalone /embed/payments route, and a payments token cannot unlock the panel. A token minted for project A cannot render at project B's URL.
1. Mint a token (backend)
Server-side, from any language. With your live or test secret key. The tabs array is optional — omit it to grant all six tabs.
curl -X POST "https://nexuspayph.com/v1/embed_tokens" \
-H "Authorization: Bearer sk_live_..." \
-H "Content-Type: application/json" \
-d '{
"project_uuid": "<YOUR_PROJECT_UUID>",
"surface": "panel",
"audience": "merchant",
"tabs": ["payments", "payouts", "balance"]
}'Response (201):
{
"token": "eyJ2IjoyLC...",
"expires_at": "2026-05-30T14:42:18.000Z",
"project_uuid": "<YOUR_PROJECT_UUID>",
"surface": "panel",
"audience": "merchant",
"scope_field": null,
"tabs": ["payments", "payouts", "balance"],
"ttl_seconds": 1800
}When tabs is omitted from the request, the response returns “tabs”: null and the panel renders all six tabs.
2. Render the iframe (frontend)
Drop the token into the src URL and load /embed.js on the host page so the iframe auto-sizes to its content.
<iframe id="nxp-panel"
src="https://nexuspayph.com/embed/panel/<YOUR_PROJECT_UUID>?token=<TOKEN>"
style="width: 100%; height: 400px; border: 0"></iframe>
<script src="https://nexuspayph.com/embed.js"></script>Optional query params:
?tab=<tab>— sets the initially active tab (e.g.?tab=balance). Defaults topayments. If the requested tab is not in the token's granted set it renders an “unavailable” stub.?theme=dark— dark colour palette. Default islight.
Tabs
The panel includes six tabs. All six are merchant-audience only (see Audience below).
| Tab | What it shows |
|---|---|
payments | Incoming payments for the project, newest 50, with status, amount, method, and customer. |
payouts | Outbound payouts for the project — date, status, amount, and reference. |
balance | Merchant's settlement balance (credited by payments, debited by payouts). This is the merchant's own available balance, not a shared treasury float. |
invoices | Invoices issued under the project — number, status, amount, recipient, and due date. |
customers | Customer directory for the project — cus_* IDs, names, emails, and created dates. |
events | Webhook event log — event type, summary, and timestamp for the newest 50 events. |
Audience
The panel surface is merchant-audience only. Every tab (including Payments) shows account-wide data scoped to the project — not filtered to a single end-user. Requesting surface="panel" with audience="customer" returns a 400 unsupported_combo error at mint time.
If you want to show a single end-user their own payment history, use the standalone payments embed (surface="payments",audience="customer") documented in Embedded payments view. The customer audience is for that surface, not this one.
Token lifecycle
- TTL: 30 minutes by default. Override with
ttl_secondson the mint call (range: 60 – 86400). - One-shot rendering: mint a fresh token each time your backend serves the page. Don't cache or share tokens across sessions.
- Expiry: once expired the iframe shows an “invalid or expired” card. Refresh the page to mint a new one.
Security model
- HMAC-signed: tokens are signed with our embed secret. Tampered tokens are rejected.
- Surface-locked: a panel token can only unlock
/embed/panel/<uuid>. It cannot be used to render the payments embed or any other surface. - Bound to one project: a token minted for project A only renders at
/embed/panel/<A-uuid>. Using it at a different UUID returns 401. - Iframe allowlist (frame-ancestors CSP): each project can be locked to a specific set of parent origins so a leaked token can't be rendered inside an arbitrary site. Email us with the origins you want allowed for your project.
- No Referer leak: embed pages emit
Referrer-Policy: no-referrerso the token in the URL never crosses the embed to a third-party resource via the Referer header. - Read-only: embed tokens can't mutate anything; they only unlock the panel view for one project.
Errors
From POST /v1/embed_tokens:
401 unauthenticated // missing/invalid sk_* 404 project_not_found // project doesn't exist OR isn't yours 403 project_disabled // project exists but is disabled 400 unsupported_combo // surface=panel with audience=customer 400 unexpected_scope // audience=merchant with stray scope_field/scope_value 400 invalid_tabs // non-empty tabs array with no valid tab name 400 invalid_request // zod body validation (bad uuid, ttl out of range, ...)
From GET /embed/panel/<uuid> the iframe shows a small error card — the underlying HTTP status is 401 for token problems, 404 when the project is gone.
Example: teamjeco
teamjeco (747jeco.live) is already provisioned — https://747jeco.live is allowlisted as an embed origin and webhooks are live. No additional setup is needed.
Their backend mints a token with their own sk_* key:
curl -X POST "https://nexuspayph.com/v1/embed_tokens" \
-H "Authorization: Bearer <sk_live_teamjeco...>" \
-H "Content-Type: application/json" \
-d '{
"project_uuid": "e6712b65-46de-4b0d-8ea1-7dfe3a3d0282",
"surface": "panel",
"audience": "merchant"
}'Then the iframe on 747jeco.live uses the returned token:
<iframe src="https://nexuspayph.com/embed/panel/e6712b65-46de-4b0d-8ea1-7dfe3a3d0282?token=<TOKEN>" style="width: 100%; height: 500px; border: 0"></iframe> <script src="https://nexuspayph.com/embed.js"></script>
Omitting tabs grants all six tabs. teamjeco can narrow the grant at any time by adding a tabs array to the mint request — no platform-side change required.