# Application API reference

> Your server manages every user of one tenant with a secret credential, a client_credentials access token, which must never reach a browser. For a signed-in user changing their own details, use the User API.

Source: https://docs.authalla.com/docs/api-reference

OpenAPI spec: https://api.authalla.com/api/v1/openapi.json (YAML: https://api.authalla.com/api/v1/openapi.yaml)
Base URL: https://api.authalla.com

## Overview

The Authalla Application API manages the **users of one tenant**.

**Called with:** a **secret credential**, a tenant app's client
credentials access token, got with its client secret. Call it from your
server.

**Reaches:** every user of the tenant, so the token and the client secret
stay on your server and never go in a browser or a mobile app.

**Use another API when:**

- a signed-in user views or changes their own details, sessions or
  connected apps: use the **User API**, called with that user's own
  access token
  ([spec](https://api.authalla.com/me/v1/openapi.json)).
- you configure tenants, apps, domains, sign-in methods or the theme: use
  the **Management API**, also called from your server with a secret
  credential, an account API key
  ([spec](https://api.authalla.com/management/v1/openapi.json)).

Which API, and which credential, for which job:
https://docs.authalla.com/docs/choosing-an-api

### OAuth2 client credentials

All endpoints require an access token from the OAuth2 **client credentials** flow.

#### Getting an Access Token

1. Create a Backend Service app in the Authalla dashboard
2. Call the token endpoint with `grant_type=client_credentials` plus your `client_id` and `client_secret` to obtain an access token
3. Include the access token in the `Authorization` header for all API requests

#### Scopes

Client credentials access tokens are scoped to the data plane. Available scopes:

- `users:read` / `users:write`

Management scopes (`tenants:*`, `apps:*`, `domains:*`, `sender-addresses:*`,
`social-logins:*`, `theme:*`) are not grantable to a tenant client
credentials token; request them on the Management API's account API key
instead.

If no scopes are requested at the token endpoint, the token is granted all scopes allowed for the app.

## Scopes

- `users:read`: Read users
- `users:write`: Create, update, and delete users

Errors use one JSON shape with a stable `error` code; see https://docs.authalla.com/docs/errors.

## Operations

### List users

`GET /api/v1/users` · Required scope: `users:read`

List users in the tenant associated with the access token.

Requires scope: `users:read`.

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `limit` | query | integer | no | Maximum number of users to return |
| `offset` | query | integer | no | Number of users to skip |
| `search` | query | string | no | Search by email or name (case-insensitive substring match) |

Responses:

- `200` List of users (UserListResponse)
- `400` Invalid request parameters (Error)
- `401` Missing or invalid access token (Error)
- `403` Forbidden (insufficient scope or invalid token type) (Error)
- `500` Internal server error (Error)

### Create user

`POST /api/v1/users` · Required scope: `users:write`

Create a new user in the tenant associated with the access token.

Requires scope: `users:write`.

Request body (`application/json`, required): CreateUserRequest

Responses:

- `201` User created successfully (User)
- `400` Invalid request parameters (Error)
- `401` Missing or invalid access token (Error)
- `403` Forbidden (insufficient scope or invalid token type) (Error)
- `409` Conflict (resource already exists) (Error)
- `500` Internal server error (Error)

### Get user

`GET /api/v1/users/{id}` · Required scope: `users:read`

Get a user by public ID in the tenant associated with the access token.

Requires scope: `users:read`.

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | string | yes | User public ID |

Responses:

- `200` User details (User)
- `401` Missing or invalid access token (Error)
- `403` Forbidden (insufficient scope or invalid token type) (Error)
- `404` Resource not found (Error)
- `500` Internal server error (Error)

### Update user

`PUT /api/v1/users/{id}` · Required scope: `users:write`

Update an existing user by public ID in the tenant associated with the access token.

Requires scope: `users:write`.

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | string | yes | User public ID |

Request body (`application/json`, required): UpdateUserRequest

Responses:

- `200` User updated successfully (User)
- `400` Invalid request parameters (Error)
- `401` Missing or invalid access token (Error)
- `403` Forbidden (insufficient scope or invalid token type) (Error)
- `404` Resource not found (Error)
- `500` Internal server error (Error)

### Delete user

`DELETE /api/v1/users/{id}` · Required scope: `users:write`

Delete a user by public ID in the tenant associated with the access token.

Requires scope: `users:write`.

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | string | yes | User public ID |

Responses:

- `204` User deleted successfully
- `401` Missing or invalid access token (Error)
- `403` Forbidden (insufficient scope or invalid token type) (Error)
- `404` Resource not found (Error)
- `500` Internal server error (Error)

### Sign a user out everywhere

`POST /api/v1/users/{id}/sign-out-everywhere` · Required scope: `users:write`

End every browser session of the user and revoke every app connected
to their account: remembered consents are forgotten and all the
user's refresh and access tokens are revoked. Resource servers that
introspect tokens refuse them at once; those that validate them
locally accept them until they expire. With `suspend`, the user is
also suspended so they can't sign in again.

Requires scope: `users:write`.

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | string | yes | User public ID |

Request body (`application/json`): SignOutEverywhereRequest

Responses:

- `204` User signed out everywhere
- `400` Invalid request parameters (Error)
- `401` Missing or invalid access token (Error)
- `403` Forbidden (insufficient scope or invalid token type) (Error)
- `404` Resource not found (Error)
- `500` Internal server error (Error)

## Schemas

### SignOutEverywhereRequest

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `suspend` | boolean | no | Also suspend the user |

### UserStatus

Current status of the user

One of: `active`, `inactive`, `suspended`

### User

A user in a tenant

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | yes | Unique public identifier for the user |
| `email` | string (email) | yes | User email address |
| `name` | string | yes | User display name |
| `email_verified` | boolean | yes | Whether the user's email has been verified |
| `status` | UserStatus | yes |  |
| `last_login` | string (date-time) | no | Timestamp of the user's last login (if any) |
| `scopes` | string[] | no | Custom scopes granted to this user (used to gate non-standard OAuth2 scopes) |
| `created_at` | string (date-time) | yes |  |
| `updated_at` | string (date-time) | yes |  |

### CreateUserRequest

Request body for creating a new user

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `email` | string (email) | yes |  |
| `name` | string | yes |  |
| `scopes` | string[] | no |  |

### UpdateUserRequest

Request body for updating a user

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `email` | string (email) | no |  |
| `name` | string | no |  |
| `status` | UserStatus | no |  |
| `scopes` | string[] | no |  |

### UserListResponse

Response containing a list of users with pagination info

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `users` | User[] | yes |  |
| `total` | integer | yes | Total number of users returned |
| `limit` | integer | yes | Maximum number of results per page |
| `offset` | integer | yes | Number of results skipped |

### Error

Standard error response

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `error` | string (bad_request \\| validation_error \\| unauthorized \\| forbidden \\| not_found \\| conflict \\| internal_error) | yes | Machine-readable error code. See https://docs.authalla.com/docs/errors. |
| `message` | string | yes | Human-readable error message |
| `documentation_url` | string (uri) | yes | Link to this error code on the Errors page. |
