Embedded apps
Render your app inside the merchant dashboard
Your app can render its own UI inside the Southbill merchant dashboard, so merchants never leave Southbill to configure or use it.
1. Enable the embedded surface
In your app detail page (Developer Dashboard → Apps → your app → Embedded app) set:
| Field | Notes |
|---|---|
embedded |
Turns the surface on |
embedded_url |
HTTPS only. The page Southbill loads in the iframe |
embedded_nav_label |
Optional label shown to the merchant (defaults to the app name) |
embedded_height |
Optional initial height, clamped to 400–4000 px |
Merchants then see an Open button next to your app in Dashboard → Apps, which opens /dashboard/apps/{installation_id}.
2. Bootstrap parameters
Southbill loads your embedded_url with:
?session_token=<JWT>&installation_id=insta_...&environment=test|live&host=https://southbill.com
Treat session_token as a one-time bootstrap value: exchange it for your own session server-side and drop it from the URL. Never store it in logs.
3. Verify the session token
The token is an HS256 JWT signed with your per-app signing secret (reveal it in the Embedded app card). It is an identity assertion only — it grants no API access.
{
"iss": "https://southbill.com",
"aud": "<your public app id>",
"sub": "<installation public id>",
"iat": 1730000000,
"nbf": 1729999995,
"exp": 1730000300,
"jti": "…",
"merchant_id": "…",
"merchant_name": "Acme GmbH",
"merchant_country": "DE",
"installation_id": "insta_…",
"environment": "test",
"scopes": ["store:read", "orders:write"]
}
Always verify server-side: signature, aud equals your app id, iss, exp/nbf, and that the installation belongs to the merchant you are about to act on. Lifetime is 300 seconds.
To call the Southbill API, keep using the OAuth access token you received at install time — the session token is not accepted by the API.
4. The postMessage bridge
Southbill only accepts messages from your exact embedded_url origin, and only these types:
| Message | Payload | Effect |
|---|---|---|
southbill:resize |
{ height: number } |
Resizes the iframe (400–4000 px) |
southbill:toast |
{ message: string, variant?: "error" } |
Shows a toast (max 200 chars) |
southbill:navigate |
{ path: "/dashboard/..." } |
Navigates the dashboard; other paths are ignored |
southbill:session-token |
– | Issues a fresh token, answered with southbill:session-token:result or southbill:session-token:error |
const host = new URLSearchParams(location.search).get("host");
parent.postMessage({ type: "southbill:resize", height: document.body.scrollHeight }, host);
5. Requirements
- HTTPS with a valid certificate; the page must be frameable by Southbill (do not send
X-Frame-Options: DENY; useContent-Security-Policy: frame-ancestors https://southbill.com). - The iframe is sandboxed. Third-party cookies are unreliable — keep state on your backend keyed by
installation_id. - Handle
environmentexplicitly: sandbox installs must never touch live data. - Revoked or uninstalled installations stop receiving tokens (
409 installation_inactive); fail gracefully.