# Update profile

> Replace a profile's name, externalId, and metadata.

Canonical: <https://www.tryadeli.com/docs/api/profiles/update-profile>

`PUT https://app.tryadeli.com/api/v1/profiles/{profileId}`

Authorization: `Bearer <API key>` — see [Authentication](https://www.tryadeli.com/docs/authentication)

Replaces the mutable fields. This is a full replace, not a merge: omitting
`externalId` or `metadata` clears them.

**Path parameters**

| Name        | Type   | Required | Description                                                                      |
| ----------- | ------ | -------- | -------------------------------------------------------------------------------- |
| `profileId` | `uuid` | Yes      | A profile in your organization. Any other value returns 404 profile\_not\_found. |

**Body**

| Name         | Type             | Required | Description                                                                             |
| ------------ | ---------------- | -------- | --------------------------------------------------------------------------------------- |
| `name`       | `string`         | Yes      | 1–200 characters after trimming. Must be unique across your organization's profiles.    |
| `externalId` | `string \| null` |          | Up to 200 characters. Must be unique across your organization's profiles when not null. |
| `metadata`   | `object \| null` |          | Any JSON object, up to 16 KiB encoded as UTF-8. Arrays and scalars are rejected.        |

Both conflict responses carry the colliding profile in `details.existingProfileId`,
as they do on [create](https://www.tryadeli.com/docs/api/profiles/create-profile).

**Errors** — `401 unauthorized`, `400 invalid_request`, `400 invalid_profile`,
`404 profile_not_found`, `409 profile_name_conflict`,
`409 profile_external_id_conflict`, `502 database_error`.

## Request examples

**cURL**

```bash
curl --fail-with-body -X PUT "https://app.tryadeli.com/api/v1/profiles/00000000-0000-4000-8000-000000000002" \
  -H "Authorization: Bearer $ADELI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "Client A",
  "externalId": "customer-123",
  "metadata": {
    "plan": "pro"
  }
}'
```

**JavaScript**

```javascript
const response = await fetch("https://app.tryadeli.com/api/v1/profiles/00000000-0000-4000-8000-000000000002", {
  method: "PUT",
  headers: {
    Authorization: `Bearer ${process.env.ADELI_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    name: "Client A",
    externalId: "customer-123",
    metadata: {
      plan: "pro",
    },
  }),
});
console.log(await response.json());
```

**Python**

```python
import os

import requests

response = requests.put(
    "https://app.tryadeli.com/api/v1/profiles/00000000-0000-4000-8000-000000000002",
    headers={"Authorization": f"Bearer {os.environ['ADELI_API_KEY']}"},
    json={
        "name": "Client A",
        "externalId": "customer-123",
        "metadata": {
            "plan": "pro",
        },
    },
)
print(response.json())
```

## Responses

### 200

```json
{
  "id": "00000000-0000-4000-8000-000000000002",
  "name": "Client A",
  "externalId": "customer-123",
  "metadata": { "plan": "pro" },
  "isDefault": false,
  "createdAt": "2026-09-09T14:30:00.000Z",
  "updatedAt": "2026-10-09T16:00:00.000Z"
}
```

### 409

```json
{
  "error": {
    "code": "profile_external_id_conflict",
    "message": "A profile with this externalId already exists",
    "details": { "existingProfileId": "00000000-0000-4000-8000-000000000009" }
  }
}
```
