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

# Admin API

> API endpoints for managing user onboarding and offboarding

## Admin API

The Admin API provides endpoints for programmatically managing which engineers are onboarded and offboarded in Bilanc. This is useful for automating user lifecycle management — for example, syncing your Active Directory or GitHub organisation membership with Bilanc.

Users can be identified by their **email address** or **GitHub username**.

<Warning>
  These endpoints require an Organisation API Key. To generate one, click your name in the bottom-left corner of the Bilanc app, select **Account Settings**, then navigate to **Organisation API Keys**. If you don't see this page, contact an owner in your organisation.
</Warning>

## Base URL

```
https://api.bilanc.co
```

## Authentication

All Admin API requests require an API key in the `Authorization` header:

```bash theme={null}
Authorization: YOUR_API_KEY
```

***

## List Onboarded Users

Retrieve all currently onboarded users in your organisation, including their name, email, and GitHub username.

```
GET /users/onboarded-users-by-attributes
```

### Parameters

This endpoint does not require any request body or query parameters.

### Example

<CodeGroup>
  ```bash cURL theme={null}
  curl -X GET 'https://api.bilanc.co/users/onboarded-users-by-attributes' \
    -H 'Authorization: YOUR_API_KEY'
  ```

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

  API_KEY = "YOUR_API_KEY"

  response = requests.get(
      "https://api.bilanc.co/users/onboarded-users-by-attributes",
      headers={"Authorization": f"{API_KEY}"},
  )

  data = response.json()
  print(data)
  ```

  ```javascript Node.js theme={null}
  const axios = require('axios');

  const API_KEY = 'YOUR_API_KEY';

  const response = await axios.get(
    'https://api.bilanc.co/users/onboarded-users-by-attributes',
    {
      headers: {
        'Authorization': `${API_KEY}`,
      },
    }
  );

  console.log(response.data);
  ```
</CodeGroup>

### Response

```json theme={null}
{
  "users": [
    {
      "merged_user_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "name": "Jane Smith",
      "email": "jane.smith@company.co.uk",
      "github_username": "janesmith-company"
    },
    {
      "merged_user_id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
      "name": "John Doe",
      "email": "john.doe@company.co.uk",
      "github_username": "johndoe"
    }
  ],
  "total_users_found": 2
}
```

### Response Fields

<ResponseField name="users" type="array">
  List of onboarded users, each containing:

  * `merged_user_id` — Unique identifier for the user in Bilanc
  * `name` — The user's display name
  * `email` — The user's primary email address
  * `github_username` — The user's GitHub login
</ResponseField>

<ResponseField name="total_users_found" type="integer">
  Total number of onboarded users returned.
</ResponseField>

***

## Onboard Users

Onboard one or more users by providing their email addresses and/or GitHub usernames. Bilanc will match these against existing users in your data sources and add them as onboarded engineers.

```
POST /users/onboarded-users-by-attributes
```

### Request Body

<ParamField body="email_addresses" type="string[]">
  List of email addresses to onboard. At least one of `email_addresses` or `github_usernames` must be provided.
</ParamField>

<ParamField body="github_usernames" type="string[]">
  List of GitHub usernames to onboard. At least one of `email_addresses` or `github_usernames` must be provided.
</ParamField>

<Tip>
  You can provide both `email_addresses` and `github_usernames` in the same request. Bilanc will match users against either identifier.
</Tip>

### Example

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST 'https://api.bilanc.co/users/onboarded-users-by-attributes' \
    -H 'Authorization: YOUR_API_KEY' \
    -H 'Content-Type: application/json' \
    -d '{
      "email_addresses": [
        "jane.smith@company.co.uk",
        "john.doe@company.co.uk"
      ],
      "github_usernames": [
        "janesmith-company"
      ]
    }'
  ```

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

  API_KEY = "YOUR_API_KEY"

  response = requests.post(
      "https://api.bilanc.co/users/onboarded-users-by-attributes",
      headers={
          "Authorization": f"{API_KEY}",
          "Content-Type": "application/json",
      },
      json={
          "email_addresses": [
              "jane.smith@company.co.uk",
              "john.doe@company.co.uk",
          ],
          "github_usernames": [
              "janesmith-company",
          ],
      },
  )

  data = response.json()
  print(data)
  ```

  ```javascript Node.js theme={null}
  const axios = require('axios');

  const API_KEY = 'YOUR_API_KEY';

  const response = await axios.post(
    'https://api.bilanc.co/users/onboarded-users-by-attributes',
    {
      email_addresses: [
        'jane.smith@company.co.uk',
        'john.doe@company.co.uk',
      ],
      github_usernames: [
        'janesmith-company',
      ],
    },
    {
      headers: {
        'Authorization': `${API_KEY}`,
        'Content-Type': 'application/json',
      },
    }
  );

  console.log(response.data);
  ```
</CodeGroup>

### Response

```json theme={null}
{
  "message": "Users were successfully onboarded",
  "onboarded_count": 2,
  "onboarded_user_ids": [
    "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "b2c3d4e5-f6a7-8901-bcde-f12345678901"
  ],
  "total_users_found": 2,
  "not_found": {
    "email_addresses": [],
    "github_usernames": []
  },
  "warnings": []
}
```

### Response Fields

<ResponseField name="message" type="string">
  A summary of the result, e.g. `"Users were successfully onboarded"` or `"All users are already onboarded"`.
</ResponseField>

<ResponseField name="onboarded_count" type="integer">
  Number of users that were newly onboarded.
</ResponseField>

<ResponseField name="onboarded_user_ids" type="string[]">
  List of Bilanc user IDs that were onboarded.
</ResponseField>

<ResponseField name="total_users_found" type="integer">
  Total number of users matched from the provided identifiers.
</ResponseField>

<ResponseField name="not_found" type="object">
  Contains any identifiers that could not be matched to existing users:

  * `email_addresses` — Unmatched email addresses
  * `github_usernames` — Unmatched GitHub usernames
</ResponseField>

<ResponseField name="warnings" type="string[]">
  List of warnings, e.g. `["Some users were not found"]` if any identifiers could not be matched.
</ResponseField>

### Partial Matches

If some identifiers are found and others are not, the endpoint will onboard the matched users and return the unmatched identifiers in the `not_found` field. Check `warnings` to see if any identifiers were not found.

***

## Offboard Users

Offboard one or more users by providing their email addresses and/or GitHub usernames. This removes the users from your onboarded engineers list.

```
POST /users/offboarded-users-by-attributes
```

### Request Body

<ParamField body="email_addresses" type="string[]">
  List of email addresses to offboard. At least one of `email_addresses` or `github_usernames` must be provided.
</ParamField>

<ParamField body="github_usernames" type="string[]">
  List of GitHub usernames to offboard. At least one of `email_addresses` or `github_usernames` must be provided.
</ParamField>

### Example

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST 'https://api.bilanc.co/users/offboarded-users-by-attributes' \
    -H 'Authorization: YOUR_API_KEY' \
    -H 'Content-Type: application/json' \
    -d '{
      "email_addresses": [
        "leaver@company.co.uk"
      ],
      "github_usernames": [
        "former-employee"
      ]
    }'
  ```

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

  API_KEY = "YOUR_API_KEY"

  response = requests.post(
      "https://api.bilanc.co/users/offboarded-users-by-attributes",
      headers={
          "Authorization": f"{API_KEY}",
          "Content-Type": "application/json",
      },
      json={
          "email_addresses": [
              "leaver@company.co.uk",
          ],
          "github_usernames": [
              "former-employee",
          ],
      },
  )

  data = response.json()
  print(data)
  ```

  ```javascript Node.js theme={null}
  const axios = require('axios');

  const API_KEY = 'YOUR_API_KEY';

  const response = await axios.post(
    'https://api.bilanc.co/users/offboarded-users-by-attributes',
    {
      email_addresses: [
        'leaver@company.co.uk',
      ],
      github_usernames: [
        'former-employee',
      ],
    },
    {
      headers: {
        'Authorization': `${API_KEY}`,
        'Content-Type': 'application/json',
      },
    }
  );

  console.log(response.data);
  ```
</CodeGroup>

### Response

```json theme={null}
{
  "message": "Users were successfully offboarded",
  "offboarded_count": 2,
  "offboarded_user_ids": [
    "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "b2c3d4e5-f6a7-8901-bcde-f12345678901"
  ],
  "not_found": {
    "email_addresses": [],
    "github_usernames": []
  },
  "warnings": []
}
```

### Response Fields

<ResponseField name="message" type="string">
  A summary of the result, e.g. `"Users were successfully offboarded"`.
</ResponseField>

<ResponseField name="offboarded_count" type="integer">
  Number of users that were offboarded.
</ResponseField>

<ResponseField name="offboarded_user_ids" type="string[]">
  List of Bilanc user IDs that were offboarded.
</ResponseField>

<ResponseField name="not_found" type="object">
  Contains any identifiers that could not be matched to onboarded users:

  * `email_addresses` — Unmatched email addresses
  * `github_usernames` — Unmatched GitHub usernames
</ResponseField>

<ResponseField name="warnings" type="string[]">
  List of warnings if any identifiers could not be matched.
</ResponseField>

***

## Error Responses

All Admin API endpoints return standard HTTP error codes:

| Status Code | Description                                                                            |
| ----------- | -------------------------------------------------------------------------------------- |
| `400`       | Bad request — at least one of `email_addresses` or `github_usernames` must be provided |
| `401`       | Unauthorised — invalid or missing API key                                              |
| `404`       | No users found matching the provided identifiers                                       |
| `500`       | Internal server error                                                                  |

### Example Error Response

```json theme={null}
{
  "detail": "No users found matching the provided attributes (email addresses: unknown@company.co.uk). Please verify the values and try again."
}
```

***

## Common Use Cases

* **Sync with Active Directory**: Automate onboarding and offboarding by comparing your AD/SAML user list with Bilanc's onboarded users
* **New starter automation**: Trigger onboarding via CI/CD or a script when new engineers join your GitHub organisation
* **Leaver removal**: Automatically offboard users when they leave the organisation
* **Slack workflow integration**: Build a Slack workflow that triggers onboarding/offboarding via these endpoints
