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

# Organization

> View your organization, manage projects, and manage organization members.

These endpoints back the dashboard's organization settings pages. All require a
**dashboard session token** — an API key is a data-plane credential and gets
`401 session_required` here.

| Method and path | What it does | Role required |
| - | - | - |
| `GET /v1/orgs/me` | Your organization. | Any member |
| `PATCH /v1/orgs/me` | Renames your organization. | Owner or admin |
| `GET /v1/projects` · `POST /v1/projects` | Lists and creates projects. | Any member |
| `GET /v1/members/me` | The currently signed-in member. | Any member |
| `GET /v1/members` | Every member in your organization. | Any member |
| `POST /v1/members/invite` | Invites a new member. | Owner |
| `DELETE /v1/members/{member_id}` | Removes a member. | Owner |

## Get your organization

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

These are control-plane calls, so they authenticate with a **dashboard session**, not an
API key, and neither memory SDK wraps them. `$SESSION` is the session token sign-in
returns.

```bash cURL theme={null}
curl https://api.anonalabs.com/v1/orgs/me \
  -H "Authorization: Bearer $SESSION"
```

```python Python theme={null}
import httpx

data = httpx.get(
    "https://api.anonalabs.com/v1/orgs/me",
    headers={"Authorization": f"Bearer {SESSION}"},
).json()
```

```typescript TypeScript theme={null}
const res = await fetch("https://api.anonalabs.com/v1/orgs/me", {
  headers: { Authorization: `Bearer ${SESSION}` },
});
const data = await res.json();
```

```json theme={null}
{
  "org_id": "org_...",
  "name": "Acme Inc",
  "slug": "acme-inc",
  "created_at": "2026-01-10T09:00:00Z"
}
```

## Rename your organization

```http theme={null}
PATCH /v1/orgs/me
```

Changes the display name only. Your organization's slug never changes: it is the
owner half of a qualified shared-space id (`{owner_slug}:{space_name}`, for example
`acme:demo`), which is an address customers already write down and share, so
changing it would silently break every one of those addresses.

```json Request theme={null}
{ "name": "Acme Robotics" }
```

```json Response theme={null}
{
  "org_id": "org_...",
  "name": "Acme Robotics",
  "slug": "acme-inc",
  "created_at": "2026-01-10T09:00:00Z"
}
```

Restricted to owners and admins.

## Projects

Projects group API keys under an organization. Every organization needs at least one
project before it can create an API key.

```json GET /v1/projects theme={null}
[
  {
    "project_id": "proj_...",
    "org_id": "org_...",
    "name": "default",
    "description": null,
    "created_at": "..."
  }
]
```

```json POST /v1/projects theme={null}
{ "name": "customer-support-bot", "description": "Support agent memories" }
```

`POST` returns the created project in the same shape as the list items above.

## Members

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

```json theme={null}
{
  "member_id": "mem_...",
  "email": "you@acme.com",
  "role": "owner",
  "email_verified": true,
  "created_at": "..."
}
```

`GET /v1/members` returns every member in your organization, as a list of the same
shape.

### Invite a member

`POST /v1/members/invite` is restricted to the owner.

```json Request theme={null}
{ "email": "new-teammate@acme.com", "role": "developer" }
```

```json Response theme={null}
{
  "invitation_id": "inv_...",
  "email": "new-teammate@acme.com",
  "role": "developer",
  "expires_at": "2026-07-22T09:00:00Z"
}
```

`role` must be one of the roles in your organization's role set, excluding `owner`.
Nobody can be invited directly as an owner.

### Remove a member

`DELETE /v1/members/{member_id}` returns `204 No Content`. Owner only.

## Space invitations

When someone shares a space with you (from the dashboard's space members page), the
invitation is addressed to your email and waits for you to act on it. These endpoints
back that flow; any signed-in member can call them.

| Method and path | What it does |
| - | - |
| `GET /v1/invitations/pending` | Space invitations waiting on the signed-in person, matched on their email. |
| `POST /v1/invitations/accept` | Accepts one. Body: `{ "token": "..." }`. Returns the granted `space_id`. |
| `POST /v1/invitations/decline` | Declines one. Body: `{ "token": "..." }`. Returns `204 No Content`. |

```json GET /v1/invitations/pending theme={null}
{
  "invitations": [
    {
      "token": "...",
      "org_name": "Acme Inc",
      "space_id": "support-bot",
      "role": "viewer",
      "expires_at": "2026-09-06T09:00:00Z"
    }
  ]
}
```

Accepting grants access to that one space in the inviting organization — you stay in
your own organization. The session's email must match the invited address
(`403 invite_email_mismatch` otherwise, so a forwarded invitation email does not hand
over the seat), and an org-level invitation token is rejected with
`400 not_a_space_invite` — joining an organization goes through the signup flow the
invitation email links to.

## Choosing an organization per request

A person can belong to several organizations: their personal one, plus any shared
organization they have joined. Most requests need no extra input. A request runs in
your **personal organization** unless it names another, and it names another in one of
three ways: the `X-Anona-Org` header (or an `org_id` field on record, batch record,
retrieve and reason), an API key minted in that organization, or a dashboard session
switched into it.

What naming an organization does depends on the credential:

| Credential | Names its own organization | Names a different organization |
| - | - | - |
| API key | Accepted. | `400 org_mismatch`. A key belongs to one organization, so the name is a check, not a switch. |
| Dashboard session token | Accepted. | `400 org_mismatch`. Switch with `POST /auth/switch-org`; a header never switches a session. |
| Temporary profile token | Accepted. | `400 org_mismatch`. |
| MCP OAuth or CLI token | Accepted. | Selects your membership there: `403 not_an_org_member` if you hold none, `403 org_suspended` if it is suspended. |
| Nothing named | Your personal organization (an API key or switched session uses its own). | |

Send `X-Anona-Org` once, as a UUID. A repeated header, or a value that is not a UUID,
is `400 invalid_org_id`, as is an MCP tool call's `org_id` argument that is not a UUID.
A malformed `org_id` in a request body is `422 validation_error`. When both the header
and `org_id` are sent and differ, the request is `400 org_mismatch`.

```bash theme={null}
curl https://api.anonalabs.com/v1/retrieve \
  -H "Authorization: Bearer anona_live_YOUR_KEY" \
  -H "X-Anona-Org: 3f0c9a52-7d1e-4b6a-9c41-2e8d5a7b1f00" \
  -H "Content-Type: application/json" \
  -d '{"space_id": "support", "query": "refund policy"}'
```

Consenting to an MCP client binds it to your **primary** (personal) membership; use
`org_id` or the header to work in a shared organization afterwards.

### Slack and GitHub integrations

| Action | Role required |
| - | - |
| Install or disconnect (including the OAuth callback, which re-checks the role) | Owner |
| Bind, unbind, backfill | Owner or admin |

A non-owner who installs or disconnects gets `403 integration_owner_only`; a member who is neither owner nor admin who binds, unbinds or backfills gets `403 slack_admin_only` or `403 github_admin_only`.

These rules take effect once shared organizations are enabled. Until then, owners and
admins install and disconnect (anyone else gets `403 slack_admin_only` or
`403 github_admin_only`), and any member can bind, unbind and backfill.

Organizations that have never created an API key can still share spaces out and run
connectors. A connector resolves the person who spoke to their membership in the
organization it is installed in, and falls back to the membership their linked account
holds when that one has no grant.

## Error responses

| Status | Code | Cause |
| - | - | - |
| 400 | `invalid_role` | The requested invite role is not valid for this organization. |
| 400 | `no_project` | An API key was created before any project existed. |
| 400 | `cannot_remove_self` | You cannot remove your own membership. |
| 400 | `cannot_remove_owner` | The organization owner cannot be removed. |
| 401 | `session_required` | An API key was sent; these endpoints need a signed-in session. |
| 403 | `insufficient_role` | The caller's role cannot perform this action. |
| 404 | `member_not_found` | The member does not exist, or is not in your organization. |
| 409 | `already_member` | The invited email already has an Anona account. |
| 422 | `invalid_org_name` | The new name is empty or shorter than 2 characters after trimming whitespace. |

See the full [error reference](https://docs.memory.anonalabs.com/api-reference/errors.md).


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