# Create API key

Creates a **community** API key for one community ObjectId.

- Endpoint: `POST https://api.returning.ai/v1/communities/{communityId}/api-keys`
- Section: API keys / Community keys
- Authentication: `Authorization: Bearer <API_KEY>` (Community API key)
- Retries: A timeout can hide a successful create.
- Guide: generated from the published specification
- Last updated: 26 Sep 2026
- Web page: https://docs.returning.ai/api-reference/api-keys-community-api-keys/create-api-key

## Authentication

- Header: `Authorization: Bearer <API_KEY>`

The managing key must belong to that community. Keep it server-side.

## Behaviour

The create body returns the raw `key` once in the same envelope later list/update/delete also return. Treat every management response as secret-bearing.

It does not create user API keys. Those routes are not mounted on this gateway.

**Workflow:** List keys by `name` → `POST` a least-privilege key → store `data.key` in server-side secret storage → prove one allowed call → delete when rotating.

## Request

### Path parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `communityId` | `string` | Yes | The unique identifier of the community (ObjectId) |

### Headers

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `Authorization` | `string` | Yes | API key. (`Bearer <API_KEY>`) |
| `Content-Type` | `string` | Yes | Request body format. (`application/json`) |

### Body

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | `string` | Yes | The name of the API key for identification (Min 1 chars) |
| `permissions` | `string[]` | No | Array of permissions to assign to the API key (Default `[]`) |
| `expirePeriod` | `number` | No | Expiration period in days (0 for no expiration) (Min 0) |
| `expireDate` | `string` | No | Specific expiration date for the API key (Date-time) |

### Watch for

- List/update/delete also return `key`. The OpenAPI text that says list keys are masked is wrong on `https://api.returning.ai`.
- `GET /v1/users/apikeys` and `GET /v1/api-key-info` 404.
- Widget embed keys are a different credential.

### Example request

```bash
curl --request POST \
  --url 'https://api.returning.ai/v1/communities/<communityId>/api-keys' \
  --header 'Authorization: Bearer <API_KEY>' \
  --header 'Content-Type: application/json' \
  --data '{
    "name": "Slack Integration API Key",
    "permissions": [
      "sendMessage",
      "replyMessage",
      "createUser",
      "manageUser",
      "getUserData",
      "getUserStats",
      "bulkUpdateUser",
      "userFields"
    ],
    "expirePeriod": 0
  }'
```

### More examples

**Created (201).** `message` is `Create API key success.` Envelope `{ meta: { status: "success", statusCode: 201 }, message, data }`.

`data` includes `_id`, `name`, `key`, `permissions`, `expirePeriod`, `createdAt`, `updatedAt`.

**Missing name (400).** `Create API key validation error.` `detail.name: API key name is required`.

**Invalid permission (400).** `detail.permissions` lists the allowed enum. Community names include `getUserData`, `sendMessage`, `leaderboard`, `appearance`, `getBulkUpdate`. User-key names such as `sendMessages` are not valid here.

Never paste live `key` values into docs, tickets, or examples.

## Response

HTTP `201`. Store `data.key` immediately. Read back with [list](https://docs.returning.ai/api-reference/api-keys-community-api-keys/read-api-keys.md) and match `_id` or `name`. Update keeps the same `key`. Delete revokes it.

**Secret-bearing create:** If `data.key` is present, redact it in logs. Listing the same key later also returns `key`.

### Response fields

| Field | Type | Presence | Description |
| --- | --- | --- | --- |
| `meta` | `object` | - | - |
| `meta.status` | `string` | - | Response status |
| `meta.statusCode` | `number` | - | HTTP status code |
| `message` | `string` | - | Success message for the operation |
| `data` | `object` | - | - |
| `data._id` | `string` | - | The unique identifier of the API key |
| `data.name` | `string` | - | The name of the API key |
| `data.key` | `string` | - | The generated API key value |
| `data.permissions` | `string[]` | - | Array of permissions assigned to the API key |
| `data.expirePeriod` | `number` | - | Expiration period in days (0 for no expiration) (Nullable) |
| `data.expireDate` | `string` | - | Specific expiration date for the API key (Date-time; nullable) |
| `data.updatedAt` | `string` | - | When the API key was last updated (Date-time) |
| `data.createdAt` | `string` | - | When the API key was created (Date-time) |

### Example response (201)

```json
{
  "meta": {
    "status": "success",
    "statusCode": 201
  },
  "message": "Create API key success.",
  "data": {
    "_id": "675b9876fedc432109876543",
    "name": "Slack Integration API Key",
    "key": "<API_KEY>",
    "permissions": [
      "sendMessage",
      "replyMessage",
      "createUser",
      "manageUser",
      "getUserData",
      "getUserStats",
      "bulkUpdateUser",
      "userFields"
    ],
    "expirePeriod": 0,
    "expireDate": "",
    "updatedAt": "2024-12-15T10:30:45.123Z",
    "createdAt": "2024-12-15T10:30:45.123Z"
  }
}
```

## Errors

### Fix the request

| Status | Code | What to do |
| --- | --- | --- |
| 400 | - | Bad request - Invalid input. |
| 401 | - | Unauthorized - Invalid or missing authentication. |
| 403 | - | Forbidden - Insufficient permissions. |

### Fix the data

| Status | Code | What to do |
| --- | --- | --- |
| 404 | - | Resource not found. |
| 409 | - | The request conflicts with an existing resource or immutable state, such as a duplicate slug/key/name or an already-processed record. |

### Retry with backoff

| Status | Code | What to do |
| --- | --- | --- |
| 500 | - | Internal server error. |

**Retries:** A timeout can hide a successful create. List by `name` before posting the same body again. Duplicate names conflict; a second successful create with a new name is another secret.

## Next step

- [Read community API keys](https://docs.returning.ai/api-reference/api-keys-community-api-keys/read-api-keys.md): `GET /v1/communities/{communityId}/api-keys`. Confirm the new `_id` and permissions. Treat `data[].key` as secret-bearing.
