---
title: "Create an API key"
description: "Creates an API key for this organization with the chosen permissions, which must be ones the caller holds, and optionally restricted per integration to some of its tools and connections. Answers the key once.\n\n- **Scope:** `account:api-keys:write`\n- **Credentials:** an API key, a client-credentials token or a person's access token\n- **Effect:** writes; not idempotent: check the outcome before you retry\n- **Limits:** request body up to 32 KB, response up to 256 KB\n- **CLI:** `arbol account api-keys create` · **MCP tool:** `account_api_keys_create`"
---

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

Path: Account API › API keys

`POST /v1/account/api-keys`

Creates an API key for this organization with the chosen permissions, which must be ones the caller holds, and optionally restricted per integration to some of its tools and connections. Answers the key once.

- **Scope:** `account:api-keys:write`
- **Credentials:** an API key, a client-credentials token or a person's access token
- **Effect:** writes; not idempotent: check the outcome before you retry
- **Limits:** request body up to 32 KB, response up to 256 KB
- **CLI:** `arbol account api-keys create` · **MCP tool:** `account_api_keys_create`

## Authentication

Requires one of the following:

- `arbolHuman`, oauth2, scopes: `account:api-keys:write`
- `arbolMachine`, oauth2, scopes: `account:api-keys:write`
- `arbolApiKey`, http, header `Authorization`

## Request body

_Required._

- `name` (`account.apiKeys.create.name`; string, required) — What uses it, such as "Billing backend".
  - minLength 1; maxLength 60
- `scopes` (`account.apiKeys.create.scopes`; array<string>, required)
  - minLength 1; maxLength 280; pattern `^[a-z][a-z0-9-]*(?::[a-z][a-z0-9-]*){2,}$`
- `expiresAt` (`account.apiKeys.create.expiresAt`; string, optional) — Exclusive expiration instant, with timezone. Defaults to seven days from creation.
  - format `date-time`
- `restrictions` (`account.apiKeys.create.restrictions`; object, optional) — Per integration (sura, visoft, agenda): what the key may use there. An integration left out is decided by the key's scopes alone.

## Example request

```json
{
  "name": "string",
  "scopes": [
    "string"
  ],
  "expiresAt": "2019-08-24T14:15:22Z",
  "restrictions": {}
}
```

## Code samples

### cURL

```bash
curl https://api.getarbol.com/v1/account/api-keys \
  --request POST \
  --header "Authorization: Bearer $ARBOL_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
  "name": "<name>",
  "scopes": [
    "<scope>"
  ]
}'
```

### TypeScript

```typescript
import { createClient } from "@arbol-ai/sdk";

const arbol = createClient({
  baseUrl: "https://api.getarbol.com",
  token: process.env.ARBOL_API_KEY!,
});

const { data } = await arbol.account.apiKeys.create({
  name: "<name>",
  scopes: ["<scope>"],
});
```

### Rust

```rust
use arbol_sdk::{types, Client, Credential};

let arbol = Client::new(Credential::ApiKey(std::env::var("ARBOL_API_KEY")?))?;

let data = arbol
    .account()
    .api_keys()
    .create(&types::AccountApiKeysCreateInput {
        name: "<name>".into(),
        scopes: vec!["<scope>".into()],
        expires_at: None,
        restrictions: None,
    })
    .await?;
```

### CLI

```bash
arbol account api-keys create --name '<name>' --scopes '<scope>'
```

### MCP

```json
{
  "name": "account_api_keys_create",
  "arguments": {
    "name": "<name>",
    "scopes": [
      "<scope>"
    ]
  }
}
```

## Responses

### 200

Successful operation.

#### Example

```json
{
  "success": true,
  "data": {
    "apiKey": {
      "id": "string",
      "name": "string",
      "scopes": [
        "string"
      ],
      "createdAt": "2019-08-24T14:15:22Z",
      "expiresAt": "2019-08-24T14:15:22Z",
      "createdBy": "string",
      "restrictions": {}
    },
    "key": "string"
  },
  "error": null,
  "metadata": {
    "requestId": "string"
  }
}
```

- `success` (`account.apiKeys.create.response.200.success`; boolean, required)
  - one of `true`
- `data` (`account.apiKeys.create.response.200.data`; object, required)
  - `apiKey` (`account.apiKeys.create.response.200.data.apiKey`; object, required)
    - `id` (`account.apiKeys.create.response.200.data.apiKey.id`; string, required) — The machine application's client id.
      - minLength 1; maxLength 256
    - `name` (`account.apiKeys.create.response.200.data.apiKey.name`; string, required)
      - maxLength 256
    - `scopes` (`account.apiKeys.create.response.200.data.apiKey.scopes`; array<string>, required)
      - maxLength 280
    - `createdAt` (`account.apiKeys.create.response.200.data.apiKey.createdAt`; string | null, required)
      - format `date-time`
    - `expiresAt` (`account.apiKeys.create.response.200.data.apiKey.expiresAt`; string | null, required) — The UTC instant at which the key stops working. Null for a legacy key without a deadline.
      - format `date-time`
    - `createdBy` (`account.apiKeys.create.response.200.data.apiKey.createdBy`; string | null, required)
      - maxLength 256
    - `restrictions` (`account.apiKeys.create.response.200.data.apiKey.restrictions`; object | null, required) — What the key may use per integration beyond its scopes; null: its scopes alone.
  - `key` (`account.apiKeys.create.response.200.data.key`; string, required) — The API key itself. It is shown only now; store it in a secret manager.
- `error` (`account.apiKeys.create.response.200.error`; unknown, required)
- `metadata` (`account.apiKeys.create.response.200.metadata`; object, required) — What every answer carries besides its data or error.
  - `requestId` (`account.apiKeys.create.response.200.metadata.requestId`; string, required) — Request correlation identifier, also sent as X-Request-Id.

### 400

`INVALID_INPUT`: The request does not match the published schema.

#### Example

```json
{
  "success": false,
  "data": null,
  "error": {
    "code": "INVALID_INPUT",
    "message": "string",
    "retryable": false,
    "data": {
      "issues": [
        {
          "path": "string",
          "message": "string"
        }
      ]
    }
  },
  "metadata": {
    "requestId": "string"
  }
}
```

- `success` (`account.apiKeys.create.response.400.success`; boolean, required)
  - one of `false`
- `data` (`account.apiKeys.create.response.400.data`; unknown, required)
- `error` (`account.apiKeys.create.response.400.error`; object, required) — The request does not match the published schema.
  - `code` (`account.apiKeys.create.response.400.error.code`; string, required) — The failure code, stable across releases.
    - one of `"INVALID_INPUT"`
  - `message` (`account.apiKeys.create.response.400.error.message`; string, required) — What went wrong, for people; it never contains input values.
  - `retryable` (`account.apiKeys.create.response.400.error.retryable`; boolean, required) — Whether repeating the same request may succeed.
    - one of `false`
  - `data` (`account.apiKeys.create.response.400.error.data`; object, required)
    - `issues` (`account.apiKeys.create.response.400.error.data.issues`; array<object>, optional)
      - `path` (`account.apiKeys.create.response.400.error.data.issues.path`; string, required) — RFC 6901 JSON Pointer to the refused field; empty for the whole input.
        - maxLength 256
      - `message` (`account.apiKeys.create.response.400.error.data.issues.message`; string, required)
        - maxLength 256
- `metadata` (`account.apiKeys.create.response.400.metadata`; object, required) — What every answer carries besides its data or error.
  - `requestId` (`account.apiKeys.create.response.400.metadata.requestId`; string, required) — Request correlation identifier, also sent as X-Request-Id.

### 401

`UNAUTHORIZED`: A valid access token is required.

#### Example

```json
{
  "success": false,
  "data": null,
  "error": {
    "code": "UNAUTHORIZED",
    "message": "string",
    "retryable": false,
    "data": {}
  },
  "metadata": {
    "requestId": "string"
  }
}
```

- `success` (`account.apiKeys.create.response.401.success`; boolean, required)
  - one of `false`
- `data` (`account.apiKeys.create.response.401.data`; unknown, required)
- `error` (`account.apiKeys.create.response.401.error`; object, required) — A valid access token is required.
  - `code` (`account.apiKeys.create.response.401.error.code`; string, required) — The failure code, stable across releases.
    - one of `"UNAUTHORIZED"`
  - `message` (`account.apiKeys.create.response.401.error.message`; string, required) — What went wrong, for people; it never contains input values.
  - `retryable` (`account.apiKeys.create.response.401.error.retryable`; boolean, required) — Whether repeating the same request may succeed.
    - one of `false`
  - `data` (`account.apiKeys.create.response.401.error.data`; object, required) — No fields.
- `metadata` (`account.apiKeys.create.response.401.metadata`; object, required) — What every answer carries besides its data or error.
  - `requestId` (`account.apiKeys.create.response.401.metadata.requestId`; string, required) — Request correlation identifier, also sent as X-Request-Id.

### 403

- `FORBIDDEN`: The token does not authorize this operation.
- `PERMISSION_NOT_GRANTABLE`: An API key cannot hold a permission you do not hold.

#### Example

```json
{
  "success": false,
  "data": null,
  "error": {
    "code": "FORBIDDEN",
    "message": "string",
    "retryable": false,
    "data": {}
  },
  "metadata": {
    "requestId": "string"
  }
}
```

- `success` (`account.apiKeys.create.response.403.success`; boolean, required)
  - one of `false`
- `data` (`account.apiKeys.create.response.403.data`; unknown, required)
- `error` (`account.apiKeys.create.response.403.error`; one of, required)
  - one of: `ForbiddenFailure`, `AccountPermissionNotGrantableFailure`
  - discriminator: `code`
- `metadata` (`account.apiKeys.create.response.403.metadata`; object, required) — What every answer carries besides its data or error.
  - `requestId` (`account.apiKeys.create.response.403.metadata.requestId`; string, required) — Request correlation identifier, also sent as X-Request-Id.

### 409

`IDENTITY_REJECTED`: The identity service refused the change.

#### Example

```json
{
  "success": false,
  "data": null,
  "error": {
    "code": "IDENTITY_REJECTED",
    "message": "string",
    "retryable": false,
    "data": {}
  },
  "metadata": {
    "requestId": "string"
  }
}
```

- `success` (`account.apiKeys.create.response.409.success`; boolean, required)
  - one of `false`
- `data` (`account.apiKeys.create.response.409.data`; unknown, required)
- `error` (`account.apiKeys.create.response.409.error`; object, required) — The identity service refused the change.
  - `code` (`account.apiKeys.create.response.409.error.code`; string, required) — The failure code, stable across releases.
    - one of `"IDENTITY_REJECTED"`
  - `message` (`account.apiKeys.create.response.409.error.message`; string, required) — What went wrong, for people; it never contains input values.
  - `retryable` (`account.apiKeys.create.response.409.error.retryable`; boolean, required) — Whether repeating the same request may succeed.
    - one of `false`
  - `data` (`account.apiKeys.create.response.409.error.data`; object, required) — No fields.
- `metadata` (`account.apiKeys.create.response.409.metadata`; object, required) — What every answer carries besides its data or error.
  - `requestId` (`account.apiKeys.create.response.409.metadata.requestId`; string, required) — Request correlation identifier, also sent as X-Request-Id.

### 413

`REQUEST_TOO_LARGE`: The request exceeds the allowed size.

#### Example

```json
{
  "success": false,
  "data": null,
  "error": {
    "code": "REQUEST_TOO_LARGE",
    "message": "string",
    "retryable": false,
    "data": {}
  },
  "metadata": {
    "requestId": "string"
  }
}
```

- `success` (`account.apiKeys.create.response.413.success`; boolean, required)
  - one of `false`
- `data` (`account.apiKeys.create.response.413.data`; unknown, required)
- `error` (`account.apiKeys.create.response.413.error`; object, required) — The request exceeds the allowed size.
  - `code` (`account.apiKeys.create.response.413.error.code`; string, required) — The failure code, stable across releases.
    - one of `"REQUEST_TOO_LARGE"`
  - `message` (`account.apiKeys.create.response.413.error.message`; string, required) — What went wrong, for people; it never contains input values.
  - `retryable` (`account.apiKeys.create.response.413.error.retryable`; boolean, required) — Whether repeating the same request may succeed.
    - one of `false`
  - `data` (`account.apiKeys.create.response.413.error.data`; object, required) — No fields.
- `metadata` (`account.apiKeys.create.response.413.metadata`; object, required) — What every answer carries besides its data or error.
  - `requestId` (`account.apiKeys.create.response.413.metadata.requestId`; string, required) — Request correlation identifier, also sent as X-Request-Id.

### 415

`UNSUPPORTED_MEDIA_TYPE`: The request content type is not supported.

#### Example

```json
{
  "success": false,
  "data": null,
  "error": {
    "code": "UNSUPPORTED_MEDIA_TYPE",
    "message": "string",
    "retryable": false,
    "data": {}
  },
  "metadata": {
    "requestId": "string"
  }
}
```

- `success` (`account.apiKeys.create.response.415.success`; boolean, required)
  - one of `false`
- `data` (`account.apiKeys.create.response.415.data`; unknown, required)
- `error` (`account.apiKeys.create.response.415.error`; object, required) — The request content type is not supported.
  - `code` (`account.apiKeys.create.response.415.error.code`; string, required) — The failure code, stable across releases.
    - one of `"UNSUPPORTED_MEDIA_TYPE"`
  - `message` (`account.apiKeys.create.response.415.error.message`; string, required) — What went wrong, for people; it never contains input values.
  - `retryable` (`account.apiKeys.create.response.415.error.retryable`; boolean, required) — Whether repeating the same request may succeed.
    - one of `false`
  - `data` (`account.apiKeys.create.response.415.error.data`; object, required) — No fields.
- `metadata` (`account.apiKeys.create.response.415.metadata`; object, required) — What every answer carries besides its data or error.
  - `requestId` (`account.apiKeys.create.response.415.metadata.requestId`; string, required) — Request correlation identifier, also sent as X-Request-Id.

### 429

`RATE_LIMITED`: The request rate limit was exceeded. Try again later.

#### Example

```json
{
  "success": false,
  "data": null,
  "error": {
    "code": "RATE_LIMITED",
    "message": "string",
    "retryable": true,
    "data": {}
  },
  "metadata": {
    "requestId": "string"
  }
}
```

- `success` (`account.apiKeys.create.response.429.success`; boolean, required)
  - one of `false`
- `data` (`account.apiKeys.create.response.429.data`; unknown, required)
- `error` (`account.apiKeys.create.response.429.error`; object, required) — The request rate limit was exceeded. Try again later.
  - `code` (`account.apiKeys.create.response.429.error.code`; string, required) — The failure code, stable across releases.
    - one of `"RATE_LIMITED"`
  - `message` (`account.apiKeys.create.response.429.error.message`; string, required) — What went wrong, for people; it never contains input values.
  - `retryable` (`account.apiKeys.create.response.429.error.retryable`; boolean, required) — Whether repeating the same request may succeed.
    - one of `true`
  - `data` (`account.apiKeys.create.response.429.error.data`; object, required) — No fields.
- `metadata` (`account.apiKeys.create.response.429.metadata`; object, required) — What every answer carries besides its data or error.
  - `requestId` (`account.apiKeys.create.response.429.metadata.requestId`; string, required) — Request correlation identifier, also sent as X-Request-Id.

### 500

`INTERNAL_ERROR`: The service could not complete the operation.

#### Example

```json
{
  "success": false,
  "data": null,
  "error": {
    "code": "INTERNAL_ERROR",
    "message": "string",
    "retryable": false,
    "data": {}
  },
  "metadata": {
    "requestId": "string"
  }
}
```

- `success` (`account.apiKeys.create.response.500.success`; boolean, required)
  - one of `false`
- `data` (`account.apiKeys.create.response.500.data`; unknown, required)
- `error` (`account.apiKeys.create.response.500.error`; object, required) — The service could not complete the operation.
  - `code` (`account.apiKeys.create.response.500.error.code`; string, required) — The failure code, stable across releases.
    - one of `"INTERNAL_ERROR"`
  - `message` (`account.apiKeys.create.response.500.error.message`; string, required) — What went wrong, for people; it never contains input values.
  - `retryable` (`account.apiKeys.create.response.500.error.retryable`; boolean, required) — Whether repeating the same request may succeed.
    - one of `false`
  - `data` (`account.apiKeys.create.response.500.error.data`; object, required) — No fields.
- `metadata` (`account.apiKeys.create.response.500.metadata`; object, required) — What every answer carries besides its data or error.
  - `requestId` (`account.apiKeys.create.response.500.metadata.requestId`; string, required) — Request correlation identifier, also sent as X-Request-Id.

### 502

`OUTCOME_UNKNOWN`: The operation may have been applied; check its result before repeating it.

#### Example

```json
{
  "success": false,
  "data": null,
  "error": {
    "code": "OUTCOME_UNKNOWN",
    "message": "string",
    "retryable": false,
    "data": {}
  },
  "metadata": {
    "requestId": "string"
  }
}
```

- `success` (`account.apiKeys.create.response.502.success`; boolean, required)
  - one of `false`
- `data` (`account.apiKeys.create.response.502.data`; unknown, required)
- `error` (`account.apiKeys.create.response.502.error`; object, required) — The operation may have been applied; check its result before repeating it.
  - `code` (`account.apiKeys.create.response.502.error.code`; string, required) — The failure code, stable across releases.
    - one of `"OUTCOME_UNKNOWN"`
  - `message` (`account.apiKeys.create.response.502.error.message`; string, required) — What went wrong, for people; it never contains input values.
  - `retryable` (`account.apiKeys.create.response.502.error.retryable`; boolean, required) — Whether repeating the same request may succeed.
    - one of `false`
  - `data` (`account.apiKeys.create.response.502.error.data`; object, required) — No fields.
- `metadata` (`account.apiKeys.create.response.502.metadata`; object, required) — What every answer carries besides its data or error.
  - `requestId` (`account.apiKeys.create.response.502.metadata.requestId`; string, required) — Request correlation identifier, also sent as X-Request-Id.

### 503

- `UPSTREAM_UNAVAILABLE`: The upstream service could not complete the request.
- `ACCOUNT_NOT_CONFIGURED`: Account administration is not configured yet.
- `IDENTITY_UNAVAILABLE`: The identity service did not answer.

#### Example

```json
{
  "success": false,
  "data": null,
  "error": {
    "code": "UPSTREAM_UNAVAILABLE",
    "message": "string",
    "retryable": true,
    "data": {}
  },
  "metadata": {
    "requestId": "string"
  }
}
```

- `success` (`account.apiKeys.create.response.503.success`; boolean, required)
  - one of `false`
- `data` (`account.apiKeys.create.response.503.data`; unknown, required)
- `error` (`account.apiKeys.create.response.503.error`; one of, required)
  - one of: `UpstreamUnavailableFailure`, `AccountAccountNotConfiguredFailure`, `AccountIdentityUnavailableFailure`
  - discriminator: `code`
- `metadata` (`account.apiKeys.create.response.503.metadata`; object, required) — What every answer carries besides its data or error.
  - `requestId` (`account.apiKeys.create.response.503.metadata.requestId`; string, required) — Request correlation identifier, also sent as X-Request-Id.

### 504

`UPSTREAM_TIMEOUT`: The upstream service did not respond before its deadline.

#### Example

```json
{
  "success": false,
  "data": null,
  "error": {
    "code": "UPSTREAM_TIMEOUT",
    "message": "string",
    "retryable": true,
    "data": {}
  },
  "metadata": {
    "requestId": "string"
  }
}
```

- `success` (`account.apiKeys.create.response.504.success`; boolean, required)
  - one of `false`
- `data` (`account.apiKeys.create.response.504.data`; unknown, required)
- `error` (`account.apiKeys.create.response.504.error`; object, required) — The upstream service did not respond before its deadline.
  - `code` (`account.apiKeys.create.response.504.error.code`; string, required) — The failure code, stable across releases.
    - one of `"UPSTREAM_TIMEOUT"`
  - `message` (`account.apiKeys.create.response.504.error.message`; string, required) — What went wrong, for people; it never contains input values.
  - `retryable` (`account.apiKeys.create.response.504.error.retryable`; boolean, required) — Whether repeating the same request may succeed.
    - one of `true`
  - `data` (`account.apiKeys.create.response.504.error.data`; object, required) — No fields.
- `metadata` (`account.apiKeys.create.response.504.metadata`; object, required) — What every answer carries besides its data or error.
  - `requestId` (`account.apiKeys.create.response.504.metadata.requestId`; string, required) — Request correlation identifier, also sent as X-Request-Id.


Source: https://docs.getarbol.com/api/account/api-keys/create/index.md
