---
canonical_url: "https://docs.composio.dev/reference/api-reference/toolkits/postCustomToolkitsUpsert"
markdown_url: "https://docs.composio.dev/reference/api-reference/toolkits/postCustomToolkitsUpsert.md"
product: "platform"
version: "3.1"
last_updated: null
---

# Upsert a custom toolkit

**Documentation:** /reference/api-reference/toolkits/postCustomToolkitsUpsert

> **API version:** This page documents Composio REST API v3.1, the current version, at `https://backend.composio.dev/api/v3.1`. `https://backend.composio.dev/api/v3` is the previous version and remains supported.

Experimental: custom toolkits are in pilot and this contract may change. Creates a custom toolkit for the project with the provided slug, or updates its display metadata (name, API key field copy) when the project already owns a toolkit with that slug. A toolkit created here is shared with every user in the project; an existing toolkit keeps its access. app_url and auth_schemes cannot be changed on an existing toolkit: re-sending them unchanged is a no-op, changing them returns 409 (delete and re-register the toolkit instead, which revokes its connections).

---

## POST `/api/v3.1/custom/toolkits/upsert`

**Endpoint:** `https://backend.composio.dev/api/v3.1/custom/toolkits/upsert`

**Summary:** Upsert a custom toolkit

Experimental: custom toolkits are in pilot and this contract may change. Creates a custom toolkit for the project with the provided slug, or updates its display metadata (name, API key field copy) when the project already owns a toolkit with that slug. A toolkit created here is shared with every user in the project; an existing toolkit keeps its access. app_url and auth_schemes cannot be changed on an existing toolkit: re-sending them unchanged is a no-op, changing them returns 409 (delete and re-register the toolkit instead, which revokes its connections).

### Authentication

**ApiKeyAuth** - API Key in `header` header `x-api-key` OR **UserApiKeyAuth** - API Key in `header` header `x-user-api-key`

### Request Body

Toolkit creation data

**Schema:**

- `slug` (string) *(required)*: Unique slug identifier for the toolkit. Your slug will be prefixed with CUSTOM_ to avoid collision with composio managed toolkits. Spaces will be converted to underscores.
- `toolkit_config` (object) *(required)*
  - `name` (string) *(required)*: Display name of the toolkit
  - `app_url` (string (uri)) *(required)*: MCP server URL. Must use https.
  - `logo_file` (object): Square PNG or JPEG logo, 256-1024px, max 3MB. Defaults to the Model Context Protocol logo.
    - `content` (string) *(required)*: Base64-encoded image, max 3MB decoded
    - `mime_type` (enum: "image/png" | "image/jpeg") *(required)*: Image MIME type
  - `auth_schemes` (array<any>) *(required)*: How users authenticate to the MCP server

**Example:**

```json
{
  "slug": "string",
  "toolkit_config": {
    "name": "string",
    "app_url": "https://example.com",
    "logo_file": {
      "content": "string",
      "mime_type": "image/png"
    },
    "auth_schemes": [
      null
    ]
  }
}
```

### Responses

#### 200 - Successfully upserted toolkit

**Response Schema:**

- `slug` (string) *(required)*: Slug to be used with composio

**Example Response:**

```json
{
  "slug": "string"
}
```

#### 400 - Bad request - Invalid parameters

**Response Schema:**

- `error` (object) *(required)*
  - `message` (string) *(required)*
  - `code` (number) *(required)*
  - `slug` (string) *(required)*
  - `status` (number) *(required)*
  - `request_id` (string)
  - `suggested_fix` (string)
  - `errors` (array<string>)

#### 401 - Unauthorized - Invalid or missing admin credentials

**Response Schema:**

- `error` (object) *(required)*
  - `message` (string) *(required)*
  - `code` (number) *(required)*
  - `slug` (string) *(required)*
  - `status` (number) *(required)*
  - `request_id` (string)
  - `suggested_fix` (string)
  - `errors` (array<string>)

#### 404 - Not found - Toolkit not found

**Response Schema:**

- `error` (object) *(required)*
  - `message` (string) *(required)*
  - `code` (number) *(required)*
  - `slug` (string) *(required)*
  - `status` (number) *(required)*
  - `request_id` (string)
  - `suggested_fix` (string)
  - `errors` (array<string>)

#### 408 - Request timeout

**Response Schema:**

- `error` (object) *(required)*
  - `message` (string) *(required)*
  - `code` (number) *(required)*
  - `slug` (string) *(required)*
  - `status` (number) *(required)*
  - `request_id` (string)
  - `suggested_fix` (string)
  - `errors` (array<string>)

#### 409 - Conflict - app_url or auth_schemes differ from the registered toolkit; delete and re-register to change them

**Response Schema:**

- `error` (object) *(required)*
  - `message` (string) *(required)*
  - `code` (number) *(required)*
  - `slug` (string) *(required)*
  - `status` (number) *(required)*
  - `request_id` (string)
  - `suggested_fix` (string)
  - `errors` (array<string>)

#### 429 - Too many requests - The upstream service is rate limiting the request; retry after a short backoff

**Response Schema:**

- `error` (object) *(required)*
  - `message` (string) *(required)*
  - `code` (number) *(required)*
  - `slug` (string) *(required)*
  - `status` (number) *(required)*
  - `request_id` (string)
  - `suggested_fix` (string)
  - `errors` (array<string>)

#### 500 - Internal server error - Failed to sync toolkit

**Response Schema:**

- `error` (object) *(required)*
  - `message` (string) *(required)*
  - `code` (number) *(required)*
  - `slug` (string) *(required)*
  - `status` (number) *(required)*
  - `request_id` (string)
  - `suggested_fix` (string)
  - `errors` (array<string>)

### Example cURL Request

```bash
curl -X POST "https://backend.composio.dev/api/v3.1/custom/toolkits/upsert" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "slug": "string",
    "toolkit_config": {
      "name": "string",
      "app_url": "https://example.com",
      "logo_file": {
        "content": "string",
        "mime_type": "image/png"
      },
      "auth_schemes": [
        null
      ]
    }
  }'
```

---

## REST API version

The current REST API version is **v3.1**, served at `https://backend.composio.dev/api/v3.1`. Prefer it for new code and new examples.

`https://backend.composio.dev/api/v3` is the previous version. It is frozen with pinned tool-version defaults and remains supported — existing v3 integrations keep working and do not need to migrate.