Build

Account & Team

Access account details, team members, and user profile in the Lev API.

Updated June 2026
GET/api/external/v2/account/team

Multi-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-magicians

GET /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-Account header 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-account with { "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's switch_account tool is a wrapper around this endpoint.

Current User

GET/api/external/v2/me

Get 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.

FieldTypeDescription
idintegerAccount identifier
namestringAccount display name
slugstringURL-safe identifier; pass as X-Active-Account
account_typestring|nullAccount classification. One of brokerage, borrower, lender, credit (or lev_internal for Lev-internal accounts, which external callers are unlikely to see).
401unauthorized
Authentication requiredMissing or invalid Authorization header

Available Accounts

GET/api/external/v2/me/accounts

List 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.

401unauthorized
Authentication requiredMissing or invalid Authorization header

Set Active Account

PATCH/api/external/v2/me/active-account

Persist 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.

Request body
slugstringrequired
Account slug returned by GET /me (unscoped) or GET /me/accounts. Must match an account the authenticated user has an active membership on.
curl -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.

400bad_request
slug is requiredRequest body missing the slug field
401unauthorized
Authentication requiredMissing or invalid Authorization header
404not_found
Account not found or user is not a memberslug doesn't match any account the authenticated user belongs to

Account Team

GET/api/external/v2/account/team

List 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:

FieldTypeDescription
idintegerUser identifier
first_namestring|nullFirst name
last_namestring|nullLast name
emailstring|nullEmail address
rolestring|nullAccount role (admin, member, etc.)
titlestring|nullJob title
photo_urlstring|nullProfile photo URL
401unauthorized
Authentication requiredMissing or invalid Authorization header
More in this section