Skip to main content

Portal Sessions

A portal session is a temporary, customer-scoped access pass that lets one of YOUR customers log into a MarginFront-hosted page to see their own billing information. Think of it like Stripe’s customer portal: you generate a short-lived URL on the backend, hand it to your customer, and they click through to a MarginFront page that shows their invoices, usage, subscription status, etc. You never share your API key with your customers. Instead, the portal session is the safe, scoped way to show them their data without giving them keys to the kingdom.
Heads up: Portal sessions are a newer feature and the exact UI that customers land on is still evolving. The API shape described here is current, but the rendered portal experience will keep improving. If you’re building a customer-facing integration, check in with the team about what’s live before committing to the UX.

How portal sessions work, in 30 seconds

  1. Your customer clicks “View billing” inside your app
  2. Your backend calls POST /v1/portal-sessions with the customer’s external ID
  3. MarginFront returns a short-lived URL
  4. Your backend redirects the customer to that URL (or embeds it in an iframe)
  5. The customer lands on a MarginFront page showing their billing info
  6. The session expires after a configurable time window (usually 15-60 minutes)
  7. If they try to use the URL after expiry, they’re bounced out
The point is: your customer never sees your API key, never has a login to MarginFront, and gets a tightly-scoped view that only shows their own data.

The endpoints

Create a portal session

Method & URL:
POST /v1/portal-sessions
Request body (typical):
{
  "customerExternalId": "acme-001",
  "returnUrl": "https://your-app.com/billing"
}
  • customerExternalId (string) — Which of your customers this portal session is for. Scoped data — they’ll only see their own invoices, usage, etc.
  • returnUrl (string) — Where to send the customer after they close the portal. Usually back to your app.
There may be additional optional fields for configuring the portal’s features (which pages to show, which tabs to hide, theming). Check the SDK DTO in apps/api-nest/src/modules/sdk/dto/ for the current full list. What you get back (201 Created):
{
  "id": "ps_xyz789",
  "url": "https://portal.marginfront.com/sessions/xyz789...",
  "expiresAt": "2026-04-10T15:30:00.000Z",
  "customerExternalId": "acme-001"
}
Common errors:
  • 404 Not Found — The customerExternalId doesn’t match any customer in your org.
  • 400 Bad Request — Missing required field.
Example curl:
curl -X POST https://api.marginfront.com/v1/portal-sessions \
  -H "x-api-key: mf_sk_test_..." \
  -H "Content-Type: application/json" \
  -d '{
    "customerExternalId": "acme-001",
    "returnUrl": "https://acme.your-product.com/billing"
  }'

List portal sessions

Method & URL:
GET /v1/portal-sessions
What it returns: All portal sessions your org has ever created. Useful for debugging or audit purposes. Most integrations won’t need this — you create a session, hand over the URL, and don’t look at it again.

Read one portal session

Method & URL:
GET /v1/portal-sessions/{sessionId}
Returns: The session object, including its URL and expiry. Doesn’t extend the session.

Delete (revoke) a portal session

Method & URL:
DELETE /v1/portal-sessions/{sessionId}
What it does: Immediately invalidates the session URL. Use this if you need to kick a customer out of the portal (security concern, support request, etc.).

Using the Node SDK

// Create a session right before redirecting the customer
const session = await mf.portalSessions.create({
  customerExternalId: "acme-001",
  returnUrl: "https://your-app.com/billing",
});

// Redirect them (in an Express handler)
res.redirect(session.url);
// Or, if you need to revoke a session
await mf.portalSessions.delete("ps_xyz789");

Security notes

  • Portal session URLs are one-time-ish: they work for as long as the session is valid, but each URL is tied to exactly one customer. Don’t share them across customers.
  • Sessions expire automatically. You don’t need to clean them up yourself.
  • Never return your API key from your own backend to the customer’s browser. The whole point of portal sessions is you generate them on the server, the customer only ever sees the portal URL.
  • If you’re embedding the portal in an iframe, check with the team first — iframe embedding may require additional CORS or CSP configuration.