> For the complete documentation index, see [llms.txt](https://docs.maiagent.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.maiagent.ai/api/en/preparation/conventions.md).

# Common API Conventions

Common rules for calling the MaiAgent platform API, including URLs and version prefixes, API Key authentication, rate limits, error responses and status codes, pagination, field formats, and upload si

This page covers the rules shared by all platform APIs: URLs, authentication, rate limits, error responses, pagination, field formats, and upload limits. See “API Endpoint Documentation” in the left sidebar for each endpoint's fields and examples. These rules apply to all endpoints and are not repeated on individual endpoint pages. Read this page before you start coding.

{% hint style="info" %}

* For UI instructions on creating and managing API Keys, see [API Key Management](https://docs.maiagent.ai/org/developer/api-keys) in the user manual. To view call logs, see [API Call Logs](https://docs.maiagent.ai/org/developer/api-logs).
* For integration steps from scratch, see [Quickstart](https://docs.maiagent.ai/tech/api-integration/quickstart) in the technical manual.
  {% endhint %}

## Base URL and Version Prefix <a href="#base-url" id="base-url"></a>

The SaaS API URL is `https://api.maiagent.ai/api/v1/`. For on-premises and private cloud deployments, replace the domain with your company's platform domain.

* `/api/` and `/api/v1/` expose the same endpoints, with identical paths, fields, and permissions.
* AI Gateway (OpenAI-compatible endpoints) and SCIM are available **only under `/api/v1/`**.
* Always use `/api/v1/` for new integrations.
* Endpoint paths end with `/`. Omitting the trailing `/` returns a `301` redirect to the URL with `/` appended. Some HTTP clients change `POST` to `GET` when following redirects, so call the URL with the trailing `/` directly.

## Authentication <a href="#authentication" id="authentication"></a>

For server-to-server calls, pass an API Key in the `Authorization` header:

```
Authorization: Api-Key <your API Key>
```

A key consists of an alphanumeric prefix and secret, separated by `.`. Include the entire key.

| Rule                                     | Description                                                                                                                                                                                                       |
| ---------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Each key is bound to one member          | Calls use the organization that member belongs to; requests do not need a separate organization ID                                                                                                                |
| Permissions match the member's roles     | There are no endpoint-specific scopes. The key can perform any action the member can. Insufficient permissions return `403`; see [API Key Permissions](/api/en/preparation/authentication.md#api-key-permissions) |
| Disabling the member invalidates the key | The key becomes unusable immediately when the member is disabled or removed from the organization                                                                                                                 |
| Expired, disabled, or revoked keys       | Return `401`, just like a nonexistent key; the response does not disclose the reason                                                                                                                              |
| The full key is shown only once          | Only part of the key is shown after creation. Create a new key if you lose it                                                                                                                                     |

For where to create and manage keys, see [API Authentication](/api/en/preparation/authentication.md).

### Authentication Failure Responses <a href="#auth-errors" id="auth-errors"></a>

A missing key, an incorrectly formatted header, or an invalid key (nonexistent, expired, disabled, revoked, or bound to a member who has been disabled or removed from the organization) all return `401` with the same content:

```json
{"detail": "Authentication credentials were not provided."}
```

* An invalid key also produces the message that no authentication credentials were provided. The platform treats an unrecognized key as missing credentials and does not disclose the specific reason.
* The response includes a `WWW-Authenticate` header. For most endpoints, its value is `Bearer realm="api"` (these endpoints also accept OAuth access tokens). For endpoints that accept only API Keys, such as `api-key-context` below, the value is `Api-Key`. Use the `401` status code to detect authentication failures; do not use this header's value to decide which credentials to send.
* If you put an API Key after `Bearer`, the platform validates it as a login token and returns `401` with different content:

```json
{"detail": "Given token not valid for any token type", "code": "token_not_valid", "messages": [ … ]}
```

If you receive this response, change the header to `Api-Key <key>`.

{% hint style="warning" %}
**Recommended setup for integration keys**: Create a dedicated integration member, assign only the roles it needs, then issue a key for that member and set an expiration date. A key bound to a personal account becomes invalid when the employee leaves and their account is disabled, interrupting the integration. Keep API Keys on the server only: the platform API allows cross-origin (CORS) calls only from approved domains, and keys should never be exposed in the browser.
{% endhint %}

### Identify the Organization Associated with a Key <a href="#api-key-context" id="api-key-context"></a>

To check which organization a key belongs to at your own gateway, call `GET /api/v1/users/api-key-context/`. The response is `{"organizationId": "…"}`. This endpoint accepts only API Keys and does not count toward the key's RPM.

### Other Credentials <a href="#other-credentials" id="other-credentials"></a>

To connect an MCP client as a member, see [MaiAgent as an OAuth Authorization Server](https://docs.maiagent.ai/tech/identity-and-access/maiagent-oauth-server) in the technical manual. For member tokens used to embed MaiGPT in your own system, see [Integrating MaiGPT: Member Identity Embedding](https://docs.maiagent.ai/tech/work/maigpt-system-integration-guide/maigpt-integration#member-embed).

## Rate Limits <a href="#rate-limits" id="rate-limits"></a>

The platform API has **no global default limit**. Only the following limits apply:

| Scope                                                                                         | Limit                                            | Counting Method                             | Who Can Adjust It                                                                                                    |
| --------------------------------------------------------------------------------------------- | ------------------------------------------------ | ------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
| Requests per API Key (RPM)                                                                    | Set by an administrator; unlimited if not set    | Per key, per 60 seconds                     | The organization's <mark style="color:blue;">API Key Management</mark>                                               |
| AI Gateway tokens (TPM)                                                                       | Set by an administrator; unlimited if not set    | Per key, per minute; Gateway inference only | Same as above; see [AI Gateway Limits](https://docs.maiagent.ai/tech/ai-gateway/ai-gateway-openai-compatible#limits) |
| SCIM endpoints                                                                                | 100 requests/minute                              | Per organization                            | Fixed                                                                                                                |
| `web-chats/{id}/setup-contact-credentials/`                                                   | 30 requests/minute                               | Per source IP                               | Fixed                                                                                                                |
| Pricing queries that require no login (`credit/items/`, `credit/pricing-rules/`)              | 60 requests/minute                               | Per source IP                               | Fixed                                                                                                                |
| `auth/login/`                                                                                 | 10 requests/minute by default                    | Per source IP                               | Platform configuration                                                                                               |
| Web Chat requests without credentials (continuing conversations, uploading attachments, etc.) | 10–30 requests/minute, depending on the endpoint | Per source IP                               | Fixed                                                                                                                |

* A key's RPM applies to all platform APIs it can call, not just AI Gateway. If an endpoint also has its own limit, such as a fixed limit in the table, API Key calls are subject to both limits. Each is counted separately; whichever is reached first returns `429`, and `Retry-After` uses the longer required wait. There are two exceptions: the endpoint for [identifying the organization associated with a key](#api-key-context) does not count toward the key's RPM; pricing queries that require no login (`credit/items/`, `credit/pricing-rules/`) do not recognize credentials, so even calls with an API Key are subject only to the per-source-IP limit and do not count toward the key's RPM.
* Requests using OAuth access tokens or back-office login sessions are not subject to key RPM limits.
* Exceeding a limit returns `429` with a `Retry-After` header in seconds. Wait for that duration before retrying; do not resend immediately.

```json
{"detail": "Request was throttled. Expected available in 42 seconds."}
```

## Error Responses <a href="#errors" id="errors"></a>

The platform API has no unified error code table. Handle errors based on the **HTTP status code**, then use `code` for more specific handling when present. **Do not match the text in `detail`**: it is translated according to `Accept-Language`, and its wording may change.

### Response Shapes <a href="#error-shapes" id="error-shapes"></a>

| Shape           | Example                                                            | Common Uses                                                                                                                  |
| --------------- | ------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------- |
| `detail` object | `{"detail": "You do not have permission to perform this action."}` | Authentication, permissions, not found, rate limits, plans, and Credits; a few responses also include `code` or other fields |
| Field object    | `{"name": ["This field is required."]}`                            | Field validation failures; keys are camelCase field names, and errors not tied to a single field appear in `nonFieldErrors`  |
| String array    | `["…"]`                                                            | A few validation errors without an associated field                                                                          |

Exceptions:

* **AI Gateway** OpenAI-compatible endpoints use an OpenAI-format `error` object; see [AI Gateway Error Format](https://docs.maiagent.ai/tech/ai-gateway/ai-gateway-openai-compatible#errors).
* **SCIM** endpoints return request body errors, not-found errors, and conflicts according to the SCIM 2.0 specification (`schemas`, `status`, `detail`).
* **Nonexistent URLs** (incorrect paths or missing resource IDs) return `404` with HTML content, not JSON. `5xx` responses are not guaranteed to be JSON either. Check `Content-Type` before parsing a response.

### Status Codes <a href="#status-codes" id="status-codes"></a>

| Status Code           | Meaning                                                                                                                                                                        | Recommended Handling                                                                                                                                               |
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `200` / `201` / `204` | Success; `204` has no response body and is common for deletions                                                                                                                | —                                                                                                                                                                  |
| `202`                 | Accepted but not yet complete; for example, attachments are still being indexed during a synchronous reply, returning `status: "pending_attachments"`                          | Retry later; see [Cases That Do Not Enter Streaming](https://docs.maiagent.ai/tech/api-integration/dui-hua-yu-xun-xi-hui-fu-chuan-liu-tong-bu#non-streaming-cases) |
| `301`                 | The path is missing a trailing `/`                                                                                                                                             | Use the URL with `/`                                                                                                                                               |
| `400`                 | Field validation failed; most endpoints return `{"detail": "Invalid UUID format."}` when a resource ID is not a valid UUID                                                     | Correct the request; do not retry                                                                                                                                  |
| `401`                 | Credentials are missing or invalid; see [Authentication Failure Responses](#auth-errors)                                                                                       | Check the key and header format; do not retry                                                                                                                      |
| `402`                 | Insufficient plan coverage, Credits, or quota; see [below](#payment-required)                                                                                                  | Notify the organization administrator                                                                                                                              |
| `403`                 | Insufficient role permissions, the feature is not enabled for the organization, the organization is disabled, or usage has reached the limit on a character-based billing plan | Adjust role permissions or contact your representative                                                                                                             |
| `404`                 | The resource does not exist, belongs to a different organization than the key, or the URL is incorrect                                                                         | Check the ID, the key's organization, and the path                                                                                                                 |
| `409`                 | Conflicts with the resource's current state; for example, the same job is already running or a resource to be deleted is still referenced                                      | Retrieve the latest state before deciding what to do; do not resend the same request unchanged                                                                     |
| `429`                 | Rate limit exceeded                                                                                                                                                            | Back off according to `Retry-After`                                                                                                                                |
| `5xx`                 | Platform or upstream service error                                                                                                                                             | Retry with exponential backoff                                                                                                                                     |

A `409` response is a `detail` object. Some endpoints include fields needed to handle the conflict, such as when an FAQ import is already running for a knowledge base:

```json
{"detail": "An FAQ import is already running for this knowledge base.", "jobId": "…"}
```

### 402: Insufficient Plan Coverage, Credits, or Quota <a href="#payment-required" id="payment-required"></a>

| Condition                                                                                 | Response Content                                                                       | Includes `code`?      |
| ----------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- | --------------------- |
| The organization has no active paid plan                                                  | `{"detail": "Your organization has no active paid plan. …", "code": "no_active_plan"}` | Yes, `no_active_plan` |
| The organization has insufficient Credits                                                 | `{"detail": "Insufficient credits …"}`; wording varies by endpoint                     | No                    |
| A member's personal quota is exhausted or unallocated, or their role's quota is exhausted | `{"detail": "Personal credit quota exhausted. …"}`; wording varies by situation        | No                    |

* Only the absence of an active paid plan includes `code`. Responses for insufficient Credits or exhausted quotas contain only `detail`. Currently, the response alone cannot distinguish insufficient organization Credits from an exhausted personal or role quota. Ask the organization administrator to check in the back office.
* Credits and quotas are checked on write requests that incur usage, such as sending messages, uploading and searching knowledge base files, and crawling web pages. Read-only `GET` requests do not return `402` for these reasons.
* AI Gateway OpenAI-compatible endpoints return the OpenAI format: `{"error": {"type": "billing_error", "code": "insufficient_credits", …}}`. The same `code` is used when there is no active plan.
* These `402` responses do not occur when Credits billing is disabled on the platform, as in some on-premises deployments.

## Pagination <a href="#pagination" id="pagination"></a>

Most list endpoints use page-number pagination:

| Parameter                             | Description                                                                                                |
| ------------------------------------- | ---------------------------------------------------------------------------------------------------------- |
| `page`                                | Page number, starting at 1; out-of-range values return `404` with `{"detail": "Invalid page."}`            |
| `page_size` (also accepts `pageSize`) | Items per page; defaults to 20, with a maximum of 100. Values above 100 are capped at 100 without an error |

The response format is `{"count": …, "next": "…", "previous": "…", "results": [ … ]}`. Use the `next` URL directly to retrieve the next page; it is `null` when no next page exists.

Two other cases:

* **Cursor pagination**: The conversation list (`GET /api/v1/conversations/`) and message list (`GET /api/v1/messages/`) use the `cursor` parameter to paginate from newest to oldest. Use `next` to retrieve older data. The message list response includes `count`; the conversation list does not. Within each page of the message list, messages are ordered from oldest to newest.
* **No pagination**: Some lists return an array directly, such as `GET /api/v1/credit/items/`.

Refer to each endpoint's response examples to determine which type it uses.

## Field Formats <a href="#field-format" id="field-format"></a>

* **Naming**: Response keys always use camelCase. Request JSON and query parameters accept both camelCase and snake\_case. Some free-form field contents are preserved without case conversion, such as JSON Schema, custom HTTP headers, and metadata.
* **Time**: Most time fields return Unix timestamps as millisecond strings, such as `"1759536000000"`, with second-level precision (the last three digits are always `000`). A few fields use ISO 8601 strings; refer to the endpoint page.
* **Decimals**: Decimal fields such as amounts and unit prices are returned as strings, such as `"316.8000000000"`. Use a decimal type to avoid floating-point errors.
* **IDs**: Resource IDs are usually UUIDs.
* **Language**: Error messages are translated according to the `Accept-Language` header (for example, `ja`). Messages without a translation remain in English. Do not rely on message text.

## Upload Size Limits <a href="#upload-limits" id="upload-limits"></a>

Upload limits are configured by the platform and may change or differ for on-premises deployments. Use the response from `GET /api/v1/allowed-file-specs/` as the authority. This endpoint requires no authentication and lists allowed file extensions and `maxSize` (in bytes) for each purpose. The production values as of October 2026 are:

| Purpose                                                                           | Limit  |
| --------------------------------------------------------------------------------- | ------ |
| Knowledge base files                                                              | 100 MB |
| Conversation attachments: documents, spreadsheets, presentations, and audio files | 10 MB  |
| Conversation attachments: images                                                  | 5 MB   |
| Meeting recording audio files                                                     | 100 MB |

* For presigned uploads, `POST /api/v1/upload-presigned-url/` checks `fileSize` and the extension when issuing the upload URL. Exceeding the limit or using a disallowed type returns `400`. For the workflow, see [Presigned File Upload Mode](https://docs.maiagent.ai/tech/api-integration/api_knowledge) in the technical manual.
* Excel imports for knowledge base metadata, tags, and FAQs share the knowledge base file limit.

## Frequently Asked Questions <a href="#faq" id="faq"></a>

<details>

<summary>Why do I keep getting 401 even though my key is correct?</summary>

`401` does not disclose the reason. In <mark style="color:blue;">API Key Management</mark>, check that the key is not disabled, expired, or revoked, and that the associated member is still active. The header must use `Api-Key <key>`. Using `Bearer` returns `token_not_valid`; see [Authentication Failure Responses](#auth-errors).

</details>

<details>

<summary>Can I restrict a key to specific APIs?</summary>

No. A key has the role permissions of its associated member. Issue the key for an integration member with only the necessary roles. AI Gateway also lets you restrict which models a key can call; see [AI Gateway: OpenAI-Compatible API Integration](https://docs.maiagent.ai/tech/ai-gateway/ai-gateway-openai-compatible).

</details>

<details>

<summary>Why do examples starting with `/api/` work as well as `/api/v1/`?</summary>

Both prefixes expose the same endpoints. Only AI Gateway and SCIM require `/api/v1/`. Use `/api/v1/` consistently for new integrations.

</details>


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.maiagent.ai/api/en/preparation/conventions.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
