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

# Tightknit Admin API v1 Introduction

> Authenticate against the Tightknit Admin API v1, page through lists, and handle errors and rate limits.

The Tightknit Admin API v1 lets you read and manage your community's data over REST. Resources live at URLs under `/v1`, and request and response bodies are JSON, except file uploads, which send `multipart/form-data`. Each endpoint page shows whether it reads (`GET`) or writes (`POST`, `PATCH`, `DELETE`).

## Endpoint

Tightknit's v1 REST API endpoint is:

```
https://api.tightknit.ai/v1
```

## Authentication

### API keys

To create and manage API keys, see [API Keys](https://docs.tightknit.ai/integrations/api-keys.md).

Send the key as a bearer token in the `Authorization` header. The `Bearer` prefix is required.

```bash theme={null}
curl https://api.tightknit.ai/v1/feeds \
  --header "Authorization: Bearer <YOUR_API_KEY>"
```

A request without a bearer token returns `401` with the code `unauthorized`. A key that is not valid returns `401` with the code `invalid_token`.

To check which community and permissions a key carries, call `GET /v1/api_key`. It needs no permission.

### Permissions

Each endpoint requires a permission for the family of data it touches. Reading needs the family's read permission (for example `api:admin:feeds:read`). Writing needs the family permission itself (`api:admin:feeds`), which also grants reading.

| Family | Resources |
| - | - |
| `api:admin:awards` | Awards, award assignments |
| `api:admin:calendar-events` | Events, event participants |
| `api:admin:compositions` | Message Blaster drafts (compositions), their deliveries, versions and comments. Sees only drafts shared with all Studio users |
| `api:admin:composition-sends` | Sending, scheduling and canceling the scheduled send of a Message Blaster draft. Also needs `api:admin:compositions`; there is no read-only variant |
| `api:admin:content` | Content collections, content resources |
| `api:admin:feeds` | Feeds, feed members, Slack channels when expanded (for example a milestone's `slack_channel` or an event's `slack_channels`) |
| `api:admin:groups` | Groups, group memberships |
| `api:admin:journeys` | Journeys, journey achievements, milestones, milestone achievements |
| `api:admin:members` | Members, follows, activity logs |
| `api:admin:polls` | Polls, poll responses |
| `api:admin:tags` | Tags, tag groups, tag links when expanded (`tag_links`, `tag_group_links`) |
| `api:admin:files` | Files, uploaded with `POST /v1/files` or expanded (for example a feed's `banner_file`, an event's `cover_image_file` or an award's `badge_image_file`) |
| `api:admin:messages` | Messages, their attachments and versions, pinned messages, search |
| `api:admin:slack-invites` | Slack invitations sent when creating a member (`integrations.slack.invite`) |

Expanding a related object with `expand` also requires the read permission for that object's family. A missing permission returns `403` with the code `insufficient_scope`.

## Responses

Every resource object carries an `object` field naming its type. Most objects also carry an `id` with a short prefix for their type, for example `feed_4h2o89z6qlpw` for a feed or `prof_5Yq7tVz2Hm3n` for a member. Field names are snake\_case, and timestamps are RFC 3339 strings in UTC.

Creating or updating an object returns `200` with the full object, the same shape a `GET` returns. Deleting one returns `200` with the object's type, its `id` and `"deleted": true`.

Send write bodies as JSON with `Content-Type: application/json`, up to 1 MiB.

File uploads are the exception. Send `POST /v1/files` a `multipart/form-data` body instead. The file can be as large as your plan's upload limit, which can exceed 1 MiB.

Every response includes a `Request-Id` header. Include it when you contact support about a request.

## Pagination

Most list endpoints return a list object, paginated with a cursor:

```json theme={null}
{
  "object": "list",
  "data": [
    { "object": "feed", "id": "feed_4h2o89z6qlpw", "...": "..." }
  ],
  "url": "/v1/feeds",
  "next_cursor": "eyJ2YWx1ZSI6IjIwMjYtMDktMjVUMTQ6NTI6MjUuMDQ2WiIs..."
}
```

* Unless an endpoint documents its own ordering, results are ordered newest first, by `created_at`.
* `limit` sets the page size, from 1 to 100. The default is 20.
* To fetch the next page, pass the previous page's `next_cursor` as `starting_after`. When `next_cursor` is absent, you have reached the last page.
* Lists that offer other orders take a `sort` parameter: a field name sorts ascending, and a leading `-` descending (`sort=-start_date`).
* A cursor only works with the filters and sort that produced it. Changing either while reusing a cursor returns `400`.

```bash theme={null}
curl "https://api.tightknit.ai/v1/feeds?limit=50&starting_after=<NEXT_CURSOR>" \
  --header "Authorization: Bearer <YOUR_API_KEY>"
```

A few lists return everything in one response or use their own ordering. Each endpoint's page says when it does.

## Filtering

Most lists accept:

* `id`, repeated to fetch specific objects: `?id=feed_4h2o89z6qlpw&id=feed_9x1k3m7p2q8r` (up to 100 values).
* `created_at[gte]` and `created_at[lte]` to bound the creation time.

Each endpoint documents the filters it supports. Filters that take an operator use the `field[operator]` form.

## Expanding related objects

Objects reference related objects by ID, for example a feed's `created_by_id`. Endpoints that support it accept `expand` to embed the related object in the same response, such as `?expand=created_by`. Repeat the parameter to expand more than one relation. Each endpoint lists the relations it can expand.

## Errors

Errors use the [problem details](https://www.rfc-editor.org/rfc/rfc9457) format with `Content-Type: application/problem+json`:

```json theme={null}
{
  "type": "about:blank",
  "title": "Unauthorized",
  "status": 401,
  "detail": "Provide an API key as a bearer token.",
  "code": "unauthorized",
  "request_id": "req_2ccb940dd8c94b5ca7887c40b5043240"
}
```

Branch on `code`, not on `title` or `detail`. Validation errors return `400` with the code `invalid_request`. When a specific parameter failed, a `param` field names it. An undeclared query parameter or body field is refused rather than ignored, and `param` names it, with its path when it is nested (`integrations.slack.channel_ids`).

| Status | Code | Meaning |
| - | - | - |
| `400` | `invalid_request` | A parameter, body field or cursor is not valid, or the request sends one the endpoint does not accept. |
| `401` | `unauthorized` | No bearer token was sent. |
| `401` | `invalid_token` | The API key is not valid. |
| `403` | `forbidden` | The API key does not resolve to a Tightknit community, for example because a user owns it rather than an organization. |
| `403` | `insufficient_scope` | The key lacks the permission the endpoint requires. |
| `403` | `api_not_enabled` | The Admin API v1 is not enabled for your community. |
| `403` | `account_inactive` | Your Tightknit account is not active. |
| `404` | `not_found` | The object or path does not exist. |
| `413` | `payload_too_large` | The request body exceeds 1 MiB, or an uploaded file exceeds your plan's upload limit. |
| `415` | `unsupported_media_type` | A request body was sent without `Content-Type: application/json`, or a file upload without `Content-Type: multipart/form-data`. |
| `429` | `rate_limited` | You exceeded a rate limit. |
| `500` | `internal_error` | Something went wrong on our side. |
| `503` | `service_unavailable` | A dependency is temporarily unavailable. Retry later. |

## Rate limits

Requests are limited per community, not per API key, so adding keys does not add capacity. Each community gets, per minute:

* **600** reads.
* **300** writes.
* **60** calls to a few costly endpoints, such as search, uploading a file and deleting an event, which count against this budget instead of the read or write one.

Each budget is counted separately in each Cloudflare data center that serves your traffic.

A separate per-IP limit applies before your API key is checked. It sits well above the community limits, so it only matters if you send many communities' traffic from a single outbound IP.

A throttled request returns `429` with these headers:

| Header | Meaning |
| - | - |
| `Retry-After` | Seconds to wait before retrying: the length of the rate limit window, not the time left in it. |
| `RateLimit-Limit` | Requests allowed in the window that refused this request. |
| `RateLimit-Remaining` | Always `0`, since the header only accompanies a refusal. |

Successful responses do not carry rate limit headers. Pace your retries with `Retry-After`.


## Related topics

- [Tightknit Studio](https://docs.tightknit.ai/studio/overview.md)
- [API Keys](https://docs.tightknit.ai/integrations/api-keys.md)
- [Tightknit Enterprise Slack App](https://docs.tightknit.ai/slack/tightknit-enterprise-slack-app.md)
- [Introduction](https://docs.tightknit.ai/introduction.md)
- [Delete a calendar event](https://docs.tightknit.ai/v1/api-reference/events/delete-a-calendar-event.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.