# Organization API

The Organization API lets a script keep EvoHub in step with your directory or HR system: list the people in your organization, create teams and fill them, define custom roles and give them to people or teams, invite new colleagues and read the organization's audit log. Every endpoint, with its parameters, schemas, errors and an example request, is in the [Organization API reference](https://docs-dev.evohub.io/organization.md). This page shows the common tasks and the rules that apply to all of them.

Paths below are relative to `https://evohub.io`. Requests need an API key, sent as described in [API overview](https://docs-dev.evohub.io/api-overview.md#authentication).

## Scopes

Each endpoint needs one scope. Give a key only the ones its job needs.

| To | Scope |
| --- | --- |
| List members and read one | `identity:user:read` |
| Rename members, change their title, remove them from the organization | `identity:user:write` |
| Send, resend, list and cancel invitations | `identity:user:invite` |
| List every team and read any team's members and roles | `identity:team:read` |
| Create, rename and delete teams, add and remove their members | `identity:team:write` |
| List roles, who holds them, and a member's roles | `identity:role:read` |
| Create, change and delete roles, give and take them | `identity:role:write` |
| Rename the organization | `identity:org:write` |
| Read the organization's audit log | `identity:audit:read` |

`GET /api/v1/users/me`, `GET /api/v1/organizations` and `GET /api/v1/permissions` need no scope. A key without the scope gets **403**, never 401. See [Errors](https://docs-dev.evohub.io/errors.md#401-versus-403).

## What a key cannot do

A key is held to its scopes, and it never counts as an owner or administrator, whoever created it. So:

- **It cannot hand out more than it holds.** A role, an invitation or a seat in a team that would give someone a permission the key does not hold is refused with **403** `FORBIDDEN`, and the message names the permission.
- **It cannot do what only administrators do**: give or take the Admin role or standing, edit an owner or administrator, edit the default roles. These return **403** `ADMIN_ONLY`.
- **Some things are for a person in the console**: signing in, everything about a person's own account (profile, password, two-factor authentication, sessions, devices, the list of their organizations, switching or creating organizations, seeing and accepting their invitations), creating and revoking API keys, enrolling agents, the login policy and deleting the organization. A key gets **403** there. See [API keys and scopes](https://docs-dev.evohub.io/api-keys-and-scopes.md#what-a-key-can-never-do).
- **An organization key is not a person.** It cannot send invitations (**403** `NOT_A_PERSON`); use a personal key. `GET /api/v1/users/me` answers it with **403** `NOT_A_PERSON` too, which means the key works but has no profile.

Chat apps (Slack and Microsoft Teams) are connected in On-Call: see the [On-Call API](https://docs-dev.evohub.io/on-call-api.md).

## List members

```bash
curl https://evohub.io/api/v1/users \
  -H "Authorization: Bearer $EVOHUB_API_KEY"
```

Each member has a `role`, their standing in the organization: `owner`, `admin`, `member` or `viewer`. Add `?permission=oncall:alert:respond` to get only the people who hold a permission, for example to know who can be put on a rota.

## Keep a team in step with your directory

```bash
# Create the team once.
curl -X POST https://evohub.io/api/v1/teams \
  -H "Authorization: Bearer $EVOHUB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "Platform", "slug": "platform"}'

# Then add and remove people as your directory changes.
curl -X POST https://evohub.io/api/v1/teams/$TEAM_ID/members \
  -H "Authorization: Bearer $EVOHUB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"user_id": "'"$USER_ID"'", "role": "member"}'

curl -X DELETE https://evohub.io/api/v1/teams/$TEAM_ID/members/$USER_ID \
  -H "Authorization: Bearer $EVOHUB_API_KEY"
```

Adding someone who is already in the team only changes their place in it (`admin`, `member` or `viewer`). The person must already be a member of the organization; invite them first if not.

## Give access through a role

```bash
curl -X POST https://evohub.io/api/v1/roles \
  -H "Authorization: Bearer $EVOHUB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
        "name": "Incident responder",
        "permissions": ["oncall:alert:read", "oncall:alert:respond", "oncall:incident:write"]
      }'
```

Give the role to a team with `POST /api/v1/roles/{id}/teams` and `{"team_id": "…"}`: everyone in the team holds it for as long as they are in it, so access follows your directory. Give it to one person with `POST /api/v1/roles/{id}/users` and `{"user_id": "…"}`. `GET /api/v1/permissions` lists every permission name a role can carry. See [Roles and permissions](https://docs-dev.evohub.io/roles-and-permissions.md).

## Invite someone

```bash
curl -X POST https://evohub.io/api/v1/invitations \
  -H "Authorization: Bearer $EVOHUB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"email": "deniz@acme.example", "role": "member", "team_ids": ["'"$TEAM_ID"'"]}'
```

The invitation is emailed and lasts seven days. `role_ids` and `team_ids` are what the person gets when they accept. An address that already has a pending invitation gets **409** `INVITATION_PENDING`: resend it with `POST /api/v1/invitations/{id}/resend` instead.

## Read the audit log

`GET /api/v1/audit-logs?limit=200` lists who changed what in the organization, newest first, including sign-ins. Page with `offset`, and leave out noisy actions with `exclude=user.login,user.logout`. To read every product's audit trail in one place, use the [EvoTrail API](https://docs-dev.evohub.io/evotrail-api.md).

## Rules that apply everywhere

- **Updates.** `PATCH` on a member, a team or the organization keeps a field you leave out; `""` clears a title or description, and a name (or the organization's slug) cannot be sent empty. A slug another organization uses is **409 `SLUG_TAKEN`**. `PATCH` on a role replaces its name and description, and its permissions when you send them.
- **Personal keys and `me`.** `GET /api/v1/users/me` returns the person a personal key belongs to. Its `permissions` are what the person holds, not the key's scopes.
- **Errors.** This service answers a bad field with `VALIDATION_ERROR` and the field in the message, and an unexpected failure with `INTERNAL_ERROR`. Its error bodies carry `request_id`.

## Related

- [Organization API reference](https://docs-dev.evohub.io/organization.md)
- [API keys and scopes](https://docs-dev.evohub.io/api-keys-and-scopes.md)
- [Roles and permissions](https://docs-dev.evohub.io/roles-and-permissions.md)
- [Organizations and teams](https://docs-dev.evohub.io/organizations-and-teams.md)
- [Errors](https://docs-dev.evohub.io/errors.md)
