> ## Documentation Index
> Fetch the complete documentation index at: https://docs.andromeda.ai/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> Cluster API calls are made as a signed-in person with an OIDC bearer token. There are no API keys, and service-account tokens are refused (Business returns 401, Platform returns 403).
> Platform takes the organization as the query parameter businessOrgId on most cluster routes, but as organizationId on /clusters/{clusterId}/ssh-access and /clusters/{clusterId}/kubeconfig.
> The Business API uses snake_case. The Platform API uses camelCase, except /ssh-access and /machines, which use snake_case.
> Business write requests need Idempotency-Key and Audit-Reason headers.
> Storage capacity can grow but cannot shrink, including disk and PVC resizing. Each purchase adds capacity.
> A cluster's storage can be Ceph, WEKA, or both, or NFS on its own. The Ceph quota, the purchased bytes, and Slurm's default 100 GiB shared-volume request are three different quantities.
> Organization permissions cover every cluster the organization owns. A Kubernetes resource grant shares one cluster or namespace, possibly with someone outside the organization, and lets them read that cluster and fetch its kubeconfig. A grant does not give Slurm SSH, Slurm configuration, or organization storage inventory access. Slurm SSH requires organization membership and clusters.ssh.
> The SSH login name is <cluster-id>.<username>. The gateway supports shells, commands, SFTP (including modern scp), and forwarding to loopback ports on the login node. Legacy scp and rsync need their programs on the login node. Remote forwarding and non-loopback destinations are refused.
> Use POST /me/ssh-keys for personal key registration. POST /organizations/{orgID}/ssh-keys is a deprecated alias and requires no membership. Read the preferred shell from GET /me as user.login_shell; update it with PUT /me/login-preferences.
> GET /clusters/{clusterId}/ssh-access returns 200 with ready and reason, even when access is not ready. ready: true does not mean compute nodes or Slurm accounting are ready. To confirm a key or shell change reached a cluster, require observation_current: true and compare ssh_key_set_generation with generation from GET /me/ssh-keys, and shell with user.login_shell from GET /me.
> Adding or removing a login account restarts the cluster's login nodes, Slurm controller, and accounting service, then its compute nodes one at a time; jobs running on a restarting node end. An account is added or removed when a person with an active key gains or loses SSH access, or a person with SSH access registers their first key or revokes their last. Other key changes and shell changes restart no nodes.

# Identity

> Read the signed-in user, their organization memberships, an organization's details, and its members.

* [Read the signed-in user](#read-the-signed-in-user): `GET /me`
* [Read an organization](#read-an-organization): `GET /organizations/{orgID}`
* [List an organization's members](#list-an-organizations-members): `GET /organizations/{orgID}/members`

## Read the signed-in user

```http theme={null}
GET /me
```

**API:** Business. **Permission:** none. Any signed-in person can call it.

Returns your user record and every organization you are an active member of. This is the usual first call: it gives
you the organization IDs every other endpoint needs.

If your sign-in domain is set up to join an organization automatically, the first call creates that membership.

### Response

| Field | Type | Description |
| - | - | - |
| `user.id` | string | Your user ID, `user_` + ULID. |
| `user.primary_email` | string | Your email address, lowercased. |
| `user.display_name` | string | Your display name. |
| `user.preferred_username` | string, optional | The username your identity provider asserted, if any. Not your cluster username. |
| `user.login_shell` | string | Your personal gateway login shell, `/bin/bash` by default. Change it with [`PUT /me/login-preferences`](/api-reference/business/ssh-keys#login-shell). |
| `user.lifecycle_state` | string | Always `active` here. |
| `user.created_at`, `user.updated_at` | timestamp | RFC 3339 timestamps. |
| `memberships` | array | Your active memberships. Empty if you belong to no organization. |
| `memberships[].org_id` | string | The organization ID, `org_` + ULID. |
| `memberships[].role` | string | `owner`, `admin`, or `member`. See [Permissions](/clusters/permissions#roles). |
| `memberships[].organization_username.username` | string | Your login name on this organization's clusters. |
| `memberships[].organization_username.lifecycle_state` | string | `reserved` until first used on a cluster, then `frozen`. |
| `memberships[].user_id`, `.email`, `.lifecycle_state`, `.created_at`, `.updated_at` | | Membership details. `lifecycle_state` is always `active` here. |
| `default_org_id` | string, optional | The organization to use when there is an obvious choice. Absent when you must choose between several. |
| `staff_keys` | array of strings | Andromeda staff permissions. Empty for customers. |

Memberships carry no organization name. Call [`GET /organizations/{orgID}`](#read-an-organization) for that.

### Example

```sh theme={null}
andromeda call business GET /me
```

```json theme={null}
{
  "user": {
    "id": "user_01J8Z3Q4R5S6T7V8W9X0Y1Z2A4",
    "primary_email": "ada@example.com",
    "display_name": "Ada Lovelace",
    "login_shell": "/bin/bash",
    "lifecycle_state": "active",
    "created_at": "2026-09-01T12:00:00Z",
    "updated_at": "2026-09-01T12:00:00Z"
  },
  "memberships": [
    {
      "org_id": "org_01J8Z3Q4R5S6T7V8W9X0Y1Z2A3",
      "user_id": "user_01J8Z3Q4R5S6T7V8W9X0Y1Z2A4",
      "email": "ada@example.com",
      "role": "member",
      "lifecycle_state": "active",
      "organization_username": {
        "id": "org_username_01J8Z3Q4R5S6T7V8W9X0Y1Z2A6",
        "org_id": "org_01J8Z3Q4R5S6T7V8W9X0Y1Z2A3",
        "user_id": "user_01J8Z3Q4R5S6T7V8W9X0Y1Z2A4",
        "username": "ada",
        "source": "local",
        "lifecycle_state": "frozen",
        "created_at": "2026-09-01T12:00:00Z",
        "frozen_at": "2026-09-02T08:15:00Z"
      },
      "created_at": "2026-09-01T12:00:00Z",
      "updated_at": "2026-09-01T12:00:00Z"
    }
  ],
  "default_org_id": "org_01J8Z3Q4R5S6T7V8W9X0Y1Z2A3",
  "staff_keys": []
}
```

### Errors

| Status | Code | When |
| - | - | - |
| 401 | `unauthorized` | No valid token, a service-account token, or no Andromeda account exists for this identity. |
| 503 | `integration_unavailable` | Temporary. Retry. |

## Read an organization

```http theme={null}
GET /organizations/{orgID}
```

**API:** Business. **Permission:** none. You must be an active member.

### Parameters

| Name | In | Type | Required | Description |
| - | - | - | - | - |
| `orgID` | path | string | yes | Organization ID, `org_` + ULID. |

### Response

| Field | Type | Description |
| - | - | - |
| `id` | string | Organization ID. |
| `slug` | string | Stable URL-safe name. |
| `display_name` | string | Human-readable name. |
| `lifecycle_state` | string | Organization state. |
| `created_by_user_id` | string | User who created the organization. |
| `created_at`, `updated_at` | timestamp | RFC 3339 timestamps. |

### Example

```sh theme={null}
andromeda call business GET "/organizations/$ORG_ID"
```

```json theme={null}
{
  "id": "org_01J8Z3Q4R5S6T7V8W9X0Y1Z2A3",
  "slug": "analytical-engines",
  "display_name": "Analytical Engines",
  "lifecycle_state": "active",
  "created_by_user_id": "user_01J8Z3Q4R5S6T7V8W9X0Y1Z2A7",
  "created_at": "2026-08-20T09:00:00Z",
  "updated_at": "2026-08-20T09:00:00Z"
}
```

### Errors

| Status | Code | When |
| - | - | - |
| 404 | `not_found` | The organization does not exist, or you are not a member of it. |

## List an organization's members

```http theme={null}
GET /organizations/{orgID}/members
```

**API:** Business. **Permission:** none. You must be an active member.

Returns every active member, oldest membership first. Use it to find a colleague's user ID from their email address,
for example before [replacing their permissions](/api-reference/business/permissions#replace-a-members-permissions). The list is not
paginated.

### Parameters

| Name | In | Type | Required | Description |
| - | - | - | - | - |
| `orgID` | path | string | yes | Organization ID, `org_` + ULID. |

### Response

| Field | Type | Description |
| - | - | - |
| `members[].user_id` | string | The member's user ID, `user_` + ULID. |
| `members[].email` | string | The member's email address. |
| `members[].role` | string | `owner`, `admin`, or `member`. |
| `members[].organization_username.username` | string | The member's login name on this organization's clusters. |
| `members[].org_id`, `.lifecycle_state`, `.created_at`, `.updated_at` | | Membership details, as in [`GET /me`](#read-the-signed-in-user). |

### Example

```sh theme={null}
andromeda call business GET "/organizations/$ORG_ID/members" | jq -c '.members[] | {user_id, email, role}'
```

```json theme={null}
{"user_id":"user_01J8Z3Q4R5S6T7V8W9X0Y1Z2A7","email":"grace@example.com","role":"owner"}
{"user_id":"user_01J8Z3Q4R5S6T7V8W9X0Y1Z2A4","email":"ada@example.com","role":"member"}
```

### Errors

| Status | Code | When |
| - | - | - |
| 404 | `not_found` | The organization does not exist, or you are not a member of it. |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.