NexusPay· Embedded panel

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 to payments. If the requested tab is not in the token's granted set it renders an “unavailable” stub.
  • ?theme=dark — dark colour palette. Default is light.

Tabs

The panel includes six tabs. All six are merchant-audience only (see Audience below).

TabWhat it shows
paymentsIncoming payments for the project, newest 50, with status, amount, method, and customer.
payoutsOutbound payouts for the project — date, status, amount, and reference.
balanceMerchant's settlement balance (credited by payments, debited by payouts). This is the merchant's own available balance, not a shared treasury float.
invoicesInvoices issued under the project — number, status, amount, recipient, and due date.
customersCustomer directory for the project — cus_* IDs, names, emails, and created dates.
eventsWebhook 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_seconds on 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-referrer so 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.