/api/external/v2/account/teamMulti-Account Access
A single Lev user can belong to more than one account — for example, a broker who works across two brokerages, or a user who sits on both a sponsor account and a lender account. Every Lev API response is scoped to a single active account, so callers that need data across accounts must tell Lev which account a given request targets.
How scoping works
Every request on a multi-account user must carry the X-Active-Account header with the target account's slug. The backend resolves the slug against the user's active memberships and returns that account's data. Requests from single-account users, or from API keys (which are bound to a specific account at issuance and don't read this header), may omit it — the account is implied.
X-Active-Account: broker-magiciansGET /me is the one exception. It's the discovery endpoint — calling it without X-Active-Account is how clients bootstrap, and it returns the unscoped response with available_accounts[]. Every other endpoint enforces the rule.
If a multi-account user sends a non-/me request without X-Active-Account (and the caller is not an API key), the backend returns 400 Bad Request:
{
"error": "Active account required. Provide X-Active-Account header or use an API key."
}Discovering available accounts
Call GET /api/external/v2/me without the X-Active-Account header. The unscoped response returns the authenticated user plus an available_accounts array — every account the user has an active membership on — so clients can present a picker or pass a slug programmatically. The Current User section below documents both response branches.
Switching accounts
There are two ways to switch the account a request is scoped to:
- Per-request (JWT users) — change the
X-Active-Accountheader value on the next request. This is the lightweight path for clients that already hold the target slug. - Persisted (MCP, and anyone who wants sticky scoping) — call
PATCH /me/active-accountwith{ "slug": "<target>" }. The backend stores the preference on the user's record and auto-resolves subsequent requests against it until you switch again. The MCP server'sswitch_accounttool is a wrapper around this endpoint.
Current User
/api/external/v2/meGet the authenticated user's profile, account, and platform details
GET /me has two response branches depending on whether the request carries X-Active-Account. Multi-account users should call it unscoped first to discover their memberships, then supply X-Active-Account on every subsequent request.
Scoped response (200) — request carries X-Active-Account: <slug>:
{
"request_id": "...",
"timestamp": "2026-03-20T15:30:45Z",
"data": {
"user": {
"id": 1234,
"uuid": "550e8400-e29b-...",
"email": "jane@example.com",
"first_name": "Jane",
"last_name": "Smith",
"full_name": "Jane Smith",
"role": null,
"photo_url": null,
"last_login_at": "2026-03-20T10:00:00Z"
},
"account": {
"id": 56,
"name": "Acme CRE Advisors",
"account_type": "brokerage",
"org_id": 789
},
"profile": {
"id": 1001,
"title": "Managing Director",
"role": "admin"
},
"subscription": {
"type": "enterprise",
"status": "active",
"billing_cycle": "annual",
"end_date": "2027-01-01T00:00:00Z"
},
"platform": {
"api_tier": "standard",
"granted_scopes": ["deals:read", "deals:write", "contacts:read"],
"rate_limits": {
"requests_per_minute": 100,
"per_tool_per_minute": 20,
"concurrent_requests": 10,
"ai_actions_per_minute": 5,
"daily_read_cap": null,
"daily_write_caps": null
},
"api_keys": {
"current_count": 2,
"max_allowed": 10
}
}
}
}The platform section includes your API tier, granted scopes, current rate limits, and API key usage.
Unscoped response (200) — request omits X-Active-Account:
{
"request_id": "...",
"timestamp": "2026-03-20T15:30:45Z",
"data": {
"user": {
"id": 1234,
"uuid": "550e8400-e29b-...",
"email": "jane@example.com",
"first_name": "Jane",
"last_name": "Smith",
"full_name": "Jane Smith",
"role": null,
"photo_url": null,
"last_login_at": "2026-03-20T10:00:00Z"
},
"account": null,
"available_accounts": [
{
"id": 56,
"name": "Acme CRE Advisors",
"slug": "acme-cre",
"account_type": "brokerage"
},
{
"id": 72,
"name": "Redwood Capital Partners",
"slug": "redwood-capital",
"account_type": "lender"
}
],
"profile": null,
"subscription": null,
"platform": null
}
}account, profile, subscription, and platform are all null until an account is selected. available_accounts lists every account the authenticated user has an active membership on (capped at 50); use any entry's slug as the X-Active-Account value on subsequent requests.
| Field | Type | Description |
|---|---|---|
id | integer | Account identifier |
name | string | Account display name |
slug | string | URL-safe identifier; pass as X-Active-Account |
account_type | string|null | Account classification. One of brokerage, borrower, lender, credit (or lev_internal for Lev-internal accounts, which external callers are unlikely to see). |
unauthorizedAvailable Accounts
/api/external/v2/me/accountsList every account the authenticated user has an active membership on
A dedicated endpoint for fetching just the account list, without the rest of the /me payload. Convenient when the client already knows who the user is and only needs the account picker data.
Rate limits follow the account's tier, as shown by GET /me under platform.rate_limits.
Response (200):
{
"request_id": "...",
"timestamp": "2026-03-20T15:30:45Z",
"data": {
"accounts": [
{
"id": 56,
"name": "Acme CRE Advisors",
"slug": "acme-cre",
"account_type": "brokerage"
},
{
"id": 72,
"name": "Redwood Capital Partners",
"slug": "redwood-capital",
"account_type": "lender"
}
]
}
}Each account object carries the same fields documented under Current User's unscoped response (id, name, slug, account_type). Use any entry's slug as the X-Active-Account header value or pass it to PATCH /me/active-account to persist the selection.
unauthorizedSet Active Account
/api/external/v2/me/active-accountPersist the authenticated user's active-account preference on the server
Use this endpoint when you want account scoping to survive across requests without having to track and re-send X-Active-Account yourself. The backend stores the preference on the user's record and uses it as the default active account on every subsequent request (from any client authenticating with the same credentials). The MCP server's switch_account tool is a thin wrapper around this endpoint.
Rate limits follow the account's tier, as shown by GET /me under platform.rate_limits.
slugstringrequiredcurl -X PATCH "https://api.lev.com/api/external/v2/me/active-account" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "slug": "broker-magicians" }'Response (200):
{
"request_id": "...",
"timestamp": "2026-03-20T15:30:45Z",
"data": {
"active_account": {
"id": 56,
"name": "Broker Magicians",
"slug": "broker-magicians",
"account_type": "brokerage"
}
}
}Once set, GET /me (even unscoped) and every other request automatically scopes to this account. To switch again, call this endpoint with a new slug. To return to the "no preference" state, clients can switch back to the original account or call with another valid slug — there is no separate "clear" action.
bad_requestunauthorizednot_foundAccount Team
/api/external/v2/account/teamList team members in your account
Response (200):
{
"request_id": "...",
"timestamp": "2026-03-20T15:30:45Z",
"data": [
{
"id": 1234,
"first_name": "Jane",
"last_name": "Smith",
"email": "jane@example.com",
"role": "admin",
"title": "Managing Director",
"photo_url": null
}
]
}Each team member object contains:
| Field | Type | Description |
|---|---|---|
id | integer | User identifier |
first_name | string|null | First name |
last_name | string|null | Last name |
email | string|null | Email address |
role | string|null | Account role (admin, member, etc.) |
title | string|null | Job title |
photo_url | string|null | Profile photo URL |
unauthorized