# Update project role assignment

> For AI agents: a documentation index is available at [/docs/llms.txt](/docs/llms.txt). Append `.md` to any page URL for markdown, or send `Accept: text/markdown`.

## Update project role assignment

**PATCH** `/user-management/1/project-role-assignments/{assignmentId}`

Full URL: `https://core.amplitude.com/user-management/1/project-role-assignments/{assignmentId}`

**Servers:**
- US region: `https://core.amplitude.com/user-management/1/project-role-assignments/{assignmentId}`
- EU region: `https://core.eu.amplitude.com/user-management/1/project-role-assignments/{assignmentId}`

Update project role assignment

Updates the role on an existing project role assignment. The principal and project are immutable; only `roleId` can change.

## Authorizations

| Name | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| Authorization | string | Yes | — | **Contact Amplitude Support** to obtain your organization's **org API key** and **org secret key**. Send them as **HTTP Basic** credentials on every request: org API key in the **username** field, org secret key in the **password** field. Also include `orgId` as a query parameter for your organization. **401**: invalid credentials. **403** (`org_not_enrolled`): your organization is not enabled for this API. |

## Path parameters

| Name | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| assignmentId (path) | string | Yes | — | Opaque id of the explicit project role assignment to fetch, update, or delete. |

## Query parameters

| Name | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| orgId (query) | integer | Yes | — | Organization id for the authenticated API caller. Must match the organization tied to the org key pair in the Authorization header. Constraints: min: 1 |

## Body (application/json)

| Name | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| roleId | string | Yes | — | Constraints: format: uuid |

## Response (application/json)

**200** — Project role assignment updated

| Name | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| id | string | Yes | — | Constraints: min length: 1 |
| principalType | string | Yes | user | Whether the assignment targets an individual user (`user`) or a group (`group`) Allowed values: user, group |
| principalId | string | Yes | — | Constraints: min length: 1 |
| projectId | integer | Yes | — | Constraints: min: 0 |
| roleId | string | Yes | — | Constraints: format: uuid |

```json
{
  "id": "q1dGVFo3aM6kXn2pR8vQwZ",
  "principalType": "user",
  "principalId": "alice@company.com",
  "projectId": 187520,
  "roleId": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
}
```

**400** — Invalid request parameters or body

| Name | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| type | string | Yes | — | RFC 7807 problem type URI Constraints: format: uri |
| title | string | Yes | — | — |
| status | integer | Yes | — | — |
| detail | string | No | — | Constraints: nullable |
| instance | string | No | — | Constraints: nullable |
| error_code | string | Yes | — | Allowed values: invalid_request, authentication_required, insufficient_permissions, org_id_mismatch, org_not_enrolled, not_found, conflict, rate_limited, internal_error |
| retryable | boolean | Yes | — | — |
| retry_after_seconds | integer | No | — | Constraints: nullable |

```json
{
  "type": "https://amplitude.com/problems/user-management/invalid-request",
  "title": "Invalid request parameters or body",
  "status": 400,
  "error_code": "invalid_request",
  "detail": "Request body failed validation",
  "instance": null,
  "retryable": false,
  "retry_after_seconds": null
}
```

**401** — Missing or invalid credentials

| Name | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| type | string | Yes | — | RFC 7807 problem type URI Constraints: format: uri |
| title | string | Yes | — | — |
| status | integer | Yes | — | — |
| detail | string | No | — | Constraints: nullable |
| instance | string | No | — | Constraints: nullable |
| error_code | string | Yes | — | Allowed values: invalid_request, authentication_required, insufficient_permissions, org_id_mismatch, org_not_enrolled, not_found, conflict, rate_limited, internal_error |
| retryable | boolean | Yes | — | — |
| retry_after_seconds | integer | No | — | Constraints: nullable |

```json
{
  "type": "https://amplitude.com/problems/user-management/authentication-required",
  "title": "Missing or invalid credentials",
  "status": 401,
  "error_code": "authentication_required",
  "detail": "Missing or invalid org API credentials",
  "instance": null,
  "retryable": false,
  "retry_after_seconds": null
}
```

**403** — Not allowed (org not enrolled, orgId mismatch, or insufficient permissions)

| Name | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| type | string | Yes | — | RFC 7807 problem type URI Constraints: format: uri |
| title | string | Yes | — | — |
| status | integer | Yes | — | — |
| detail | string | No | — | Constraints: nullable |
| instance | string | No | — | Constraints: nullable |
| error_code | string | Yes | — | Allowed values: invalid_request, authentication_required, insufficient_permissions, org_id_mismatch, org_not_enrolled, not_found, conflict, rate_limited, internal_error |
| retryable | boolean | Yes | — | — |
| retry_after_seconds | integer | No | — | Constraints: nullable |

```json
{
  "type": "https://amplitude.com/problems/user-management/org-not-enrolled",
  "title": "Not allowed (org not enrolled, orgId mismatch, or insufficient permissions)",
  "status": 403,
  "error_code": "org_not_enrolled",
  "detail": "This organization is not enrolled in the User Management API",
  "instance": null,
  "retryable": false,
  "retry_after_seconds": null
}
```

**404** — This assignment id does not exist or belongs to another org

| Name | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| type | string | Yes | — | RFC 7807 problem type URI Constraints: format: uri |
| title | string | Yes | — | — |
| status | integer | Yes | — | — |
| detail | string | No | — | Constraints: nullable |
| instance | string | No | — | Constraints: nullable |
| error_code | string | Yes | — | Allowed values: invalid_request, authentication_required, insufficient_permissions, org_id_mismatch, org_not_enrolled, not_found, conflict, rate_limited, internal_error |
| retryable | boolean | Yes | — | — |
| retry_after_seconds | integer | No | — | Constraints: nullable |

```json
{
  "type": "https://amplitude.com/problems/user-management/not-found",
  "title": "This assignment id does not exist or belongs to another org",
  "status": 404,
  "error_code": "not_found",
  "detail": "The requested resource does not exist or belongs to another org",
  "instance": null,
  "retryable": false,
  "retry_after_seconds": null
}
```

**429** — Rate limit exceeded

| Name | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| type | string | Yes | — | RFC 7807 problem type URI Constraints: format: uri |
| title | string | Yes | — | — |
| status | integer | Yes | — | — |
| detail | string | No | — | Constraints: nullable |
| instance | string | No | — | Constraints: nullable |
| error_code | string | Yes | — | Allowed values: invalid_request, authentication_required, insufficient_permissions, org_id_mismatch, org_not_enrolled, not_found, conflict, rate_limited, internal_error |
| retryable | boolean | Yes | — | — |
| retry_after_seconds | integer | No | — | Constraints: nullable |

```json
{
  "type": "https://amplitude.com/problems/user-management/rate-limited",
  "title": "Rate limit exceeded",
  "status": 429,
  "error_code": "rate_limited",
  "detail": "Rate limit exceeded",
  "instance": null,
  "retryable": true,
  "retry_after_seconds": 60
}
```

**500** — Unexpected server error

| Name | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| type | string | Yes | — | RFC 7807 problem type URI Constraints: format: uri |
| title | string | Yes | — | — |
| status | integer | Yes | — | — |
| detail | string | No | — | Constraints: nullable |
| instance | string | No | — | Constraints: nullable |
| error_code | string | Yes | — | Allowed values: invalid_request, authentication_required, insufficient_permissions, org_id_mismatch, org_not_enrolled, not_found, conflict, rate_limited, internal_error |
| retryable | boolean | Yes | — | — |
| retry_after_seconds | integer | No | — | Constraints: nullable |

```json
{
  "type": "https://amplitude.com/problems/user-management/internal-error",
  "title": "Unexpected server error",
  "status": 500,
  "error_code": "internal_error",
  "detail": "An unexpected error occurred",
  "instance": null,
  "retryable": false,
  "retry_after_seconds": null
}
```

## Code samples

### cURL

```bash
curl -X PATCH "https://core.amplitude.com/user-management/1/project-role-assignments/{assignmentId}" \
  -u "$AMP_API_KEY:$AMP_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
  "roleId": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
}'
```

### Python

```python
import requests

response = requests.patch(
    "https://core.amplitude.com/user-management/1/project-role-assignments/{assignmentId}",
    headers={
        "Content-Type": "application/json"
    },
    auth=("$AMP_API_KEY", "$AMP_SECRET"),
    json={
  "roleId": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
}
)
data = response.json()
```

### JavaScript

```javascript
const response = await fetch("https://core.amplitude.com/user-management/1/project-role-assignments/{assignmentId}", {
  method: "PATCH",
  headers: {
    "Content-Type": "application/json",
    "Authorization": "Basic " + btoa("$AMP_API_KEY:$AMP_SECRET")
  },
  body: JSON.stringify({
  "roleId": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
})
});
const data = await response.json();
```

### PHP

```php
<?php
$ch = curl_init("https://core.amplitude.com/user-management/1/project-role-assignments/{assignmentId}");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PATCH");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Content-Type: application/json"
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_USERPWD, "$AMP_API_KEY:$AMP_SECRET");
$body = json_encode({
  "roleId": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
});
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
$response = curl_exec($ch);
curl_close($ch);
```

### Go

```go
package main

import (
  "bytes"
  "net/http"
)

func main() {
body := []byte("{\"roleId\":\"3fa85f64-5717-4562-b3fc-2c963f66afa6\"}")
req, _ := http.NewRequest("PATCH", "https://core.amplitude.com/user-management/1/project-role-assignments/{assignmentId}", bytes.NewReader(body))
req.Header.Set("Content-Type", "application/json")
req.SetBasicAuth("$AMP_API_KEY", "$AMP_SECRET")
  client := &http.Client{}
  resp, _ := client.Do(req)
  defer resp.Body.Close()
}
```

### Java

```java
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
      .uri(URI.create("https://core.amplitude.com/user-management/1/project-role-assignments/{assignmentId}"))
      .method("PATCH", HttpRequest.BodyPublishers.ofString("{\"roleId\":\"3fa85f64-5717-4562-b3fc-2c963f66afa6\"}"))
.header("Content-Type", "application/json")
      .header("Authorization", "Basic " + Base64.getEncoder().encodeToString("$AMP_API_KEY:$AMP_SECRET".getBytes()))
      .build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
```

### Ruby

```ruby
require "net/http"
require "json"

uri = URI("https://core.amplitude.com/user-management/1/project-role-assignments/{assignmentId}")
request = Net::HTTP::Patch.new(uri)
request["Content-Type"] = "application/json"
request.basic_auth("$AMP_API_KEY", "$AMP_SECRET")
request.body = "{\"roleId\":\"3fa85f64-5717-4562-b3fc-2c963f66afa6\"}"
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == "https") do |http|
  http.request(request)
end
```
