Build
Scope access by customer organization
Give each customer a separate MindBill organization, then select the authorized organization for every server request.
Use one organization per customer
Create a MindBill organization for each customer that needs an isolated billing workspace. Save its organizationId with that customer in your backend. Organizations and their data stay within the sandbox or live environment where they were created.
Create an organization
Use an account-scoped key with orgs:write. Send your stable, non-sensitive customer ID as externalId; the same value lets you safely retry provisioning and recover the existing organization.
curl https://app.mindbill.org/partner/v2/organizations \
--request POST \
--header "Authorization: Bearer $MINDBILL_API_KEY" \
--header "Content-Type: application/json" \
--header "Idempotency-Key: customer-practice-42" \
--data '{
"externalId": "practice_42",
"name": "Example Medical Group"
}'{
"organizationId": "org_01example",
"externalId": "practice_42",
"name": "Example Medical Group",
"status": "configuring",
"accessMode": "managed",
"created": true
}Provisioning is automatic and returns the organization immediately with status: "configuring". A repeated request for the same customer can return 200 with created: false. Keep the returned organizationId; use your own externalId only to reconcile the mapping. Check the organization's status and live readiness before sending live bills.
See the organization provisioning reference for optional practice settings and response fields.
List organizations available to the key
Use GET /organizations with orgs:read to reconcile the organizations linked to the current key in its current environment.
curl https://app.mindbill.org/partner/v2/organizations \
--header "Authorization: Bearer $MINDBILL_API_KEY"The response contains data[] entries with organizationId, externalId, name, and status. An organization-scoped key sees only its fixed organization.
See the list organizations reference.
Select the authorized customer on each request
For an account-scoped key, send the saved MindBill organization ID in X-MindBill-Org-Id on bill, settings, notification, and other organization-specific requests.
curl https://app.mindbill.org/partner/v2/bills \
--header "Authorization: Bearer $MINDBILL_API_KEY" \
--header "X-MindBill-Org-Id: org_01example"MindBill verifies that the organization is linked to the key. A header for an unlinked organization is rejected. Existing single-organization workspaces may retain a default; integrations with more than one possible organization must select the customer explicitly.
Mint a browser session for that organization
For React components, authenticate the user on your server and resolve their customer's saved MindBill organization ID from your own membership data. Pass it to createBrowserSession. The Node SDK sends X-MindBill-Org-Id only when issuing this session. With plain HTTP, send the same header on POST /partner/v2/browser-sessions, outside the JSON body.
// Your authenticated server route; never run this in the browser.
import { MindBillClient } from "@mindbill/node";
const mindbill = new MindBillClient({ apiKey: process.env.MINDBILL_API_KEY! });
export async function POST(request: Request) {
if (!process.env.APP_ORIGIN || request.headers.get("origin") !== process.env.APP_ORIGIN)
return Response.json({ error: "Origin not allowed" }, { status: 403 });
const user = await requireSignedInUser(request);
const customer = await requireCustomerAccess(user); // Server-owned membership lookup.
const organizationId = customer.mindbillOrganizationId; // Saved at provisioning.
const permissions = permissionsForRole(user.role);
const session = await mindbill.createBrowserSession({
organizationId,
subject: user.id,
allowedOrigin: process.env.APP_ORIGIN!,
permissions,
expiresIn: 900,
});
return Response.json({ token: session.token, expiresAt: session.expiresAt },
{ headers: { "Cache-Control": "no-store" } });
}
// In React: <ConnectedBillingWorkspace sessionEndpoint="/api/mindbill/session" />The response's organizationId identifies the organization bound to the short-lived browser token. MindBill rejects a token used with a different organization header. The React component sends the token directly to MindBill; it does not choose an organization or receive the server API key. The host route must recheck customer membership and role each time it issues or refreshes a token. Permissions limit operations; an optional resource can narrow access to a customer or bill within the selected organization.
Restrict a key to one organization
Create an organization-scoped key when a service should access only one customer. That key cannot switch to another organization, even if a different X-MindBill-Org-Id header is sent. Browser sessions are also fixed to the organization chosen by your server when the session is issued.
Continue with authentication and browser-session access, or verify the complete flow in the sandbox checklist.
For a customer-by-customer implementation brief, see the partner integration guide.