Moves `mcp_server_configs` from deployment scope to organization scope
so each organization fully controls the MCP servers its members can use
with Coder Agents.
## Summary
- Migration: adds `organization_id` (NOT NULL, FK) and keeps existing
rows as the default organization's originals with credentials intact.
Other organizations start with no MCP servers and configure their own;
nothing is copied across organizations. Chats outside the default
organization keep any now-cross-organization `mcp_server_ids` entries;
the runtime already ignores IDs that do not resolve in the chat's
organization, so no data rewrite is needed. Slug uniqueness becomes
`(organization_id, slug)`.
- RBAC: new org-scoped `ResourceMCPServerConfig` with regosql converter
and `GetAuthorizedMCPServerConfigs`; org admins get in-org CRUD, org
members get read (replaced by ACL evaluation in the follow-up ACL PR in
this stack).
- API: all config routes nest under the organization, matching
templates: `POST|GET
/api/experimental/organizations/{organization}/mcp-servers` and
`GET|PATCH|DELETE .../mcp-servers/{mcpserverconfig}` (plus
`oauth2/connect`), resolved by a read-only param middleware that
conceals read-denied and cross-organization access as 404. Two routes
stay on the frozen `/api/experimental/mcp/servers/{mcpServer}` block:
the OAuth2 callback (the redirect URI baked into existing AS-side client
registrations) and `oauth2/disconnect`, which must remain reachable by
users removed from the organization so they can still revoke their token
grant.
- Chat runtime: selection validation and generation resolve configs
strictly by IDs, enabled state, and the chat's organization in SQL;
requested duplicates are normalized; invalid or cross-org IDs are
rejected with the precise ID list. IDs already persisted on a chat are
exempt from message-time rejection so disabling a selected server never
blocks sends; generation skips servers that are no longer usable.
- Frontend: API layer and admin settings pages target the new endpoints.
The admin page manages the default organization's servers; the org
picker is tracked separately (CODAGT-714).
- Security hardening from review: OAuth user grants are additionally
bound to `oauth2_revocation_url` (changing it invalidates grants, and a
racing OAuth callback gets 409 instead of recreating a grant).
Stack-wide SSRF protection for MCP config-directed traffic was split
into its own PR at the top of this stack (#28242) to keep this diff
reviewable; this PR keeps main's existing discovery IP-range guard.
OAuth2 auto-discovery now completes before the config row is inserted: a
failed discovery persists nothing, and there is no provisional row that
concurrent updates could race against.
Two follow-up PRs in this stack were split out to keep this diff
reviewable: #28064 completes the swagger annotations for the moved
routes (main already ships these experimental MCP handlers unannotated),
and #28065 carries hardening fixes and regression pins on top of the
cutover.
- Force On enforcement (landed on main mid-review) is org-scoped: the
forced set is read per chat organization
(`GetForcedMCPServerConfigsByOrganization`), so another organization's
`force_on` server never attaches to a chat.
## Breaking changes (experimental API)
The MCP server config endpoints move from the deployment-scoped
`/api/experimental/mcp/servers` block to organization-nested paths:
`POST|GET /api/experimental/organizations/{organization}/mcp-servers`
and `GET|PATCH|DELETE
/api/experimental/organizations/{organization}/mcp-servers/{mcpserverconfig}`
(plus `oauth2/connect`). The old paths are removed, so API consumers
must supply an organization. Two routes intentionally stay on the frozen
`/api/experimental/mcp/servers/{mcpServer}` block: the OAuth2 callback
(its redirect URI is baked into existing AS-side client registrations)
and `oauth2/disconnect` (must remain reachable by users removed from the
organization). These endpoints are under `/api/experimental`, so no
deprecation window is provided.
## Rolling upgrades
During a rolling deploy, an old replica creating an MCP config can fail
the new `NOT NULL organization_id` constraint until it is upgraded
(reads are unaffected: old binaries' generated queries select their own
column lists). This matches the repo's existing precedent for additive
NOT NULL migrations (000562) and affects only the admin config-create
path in the upgrade window.
Upgrades are expected to run in scheduled maintenance downtime with the
database locked during migration, so the migration ships no
rolling-upgrade compatibility machinery. The down migration deletes
organization-created configs (their chat references are cleaned by the
000510 delete trigger) and restores deployment-wide slug uniqueness.
Part of the MCP org-separation stack (CODAGT-711 -> CODAGT-717 audit ->
CODAGT-712 ACLs -> CODAGT-806 token RBAC).
Closes https://linear.app/codercom/issue/CODAGT-711
UAT: validated end to end on a two-org dogfood deployment, including a
real pre-migration to post-migration upgrade, cross-org isolation
(404s), same-slug-two-orgs, chat selection gating, and a live MCP tool
call through the org-scoped generation path. The migration was later
revised to keep existing rows in the default organization only (no
per-organization copies); that revision is covered by the migration test
suite.
> Mux (AI agent) authored this PR on Mike's behalf.
<!-- mux-attribution: model=claude-fable-5 thinking=high -->
---------
Co-authored-by: Mathias Fredriksson <mafredri@gmail.com>
67 KiB
Generated
title
| title |
|---|
| Members |
List organization members
Code samples
# Example request using curl
curl -X GET http://coder-server:8080/api/v2/organizations/{organization}/members \
-H 'Accept: application/json' \
-H 'Coder-Session-Token: API_KEY'
GET /api/v2/organizations/{organization}/members
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
organization |
path | string | true | Organization ID |
Example responses
200 Response
[
{
"avatar_url": "string",
"created_at": "2019-08-24T14:15:22Z",
"email": "string",
"global_roles": [
{
"display_name": "string",
"name": "string",
"organization_id": "string"
}
],
"has_ai_seat": true,
"is_service_account": true,
"last_seen_at": "2019-08-24T14:15:22Z",
"login_type": "",
"name": "string",
"organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
"roles": [
{
"display_name": "string",
"name": "string",
"organization_id": "string"
}
],
"status": "active",
"updated_at": "2019-08-24T14:15:22Z",
"user_created_at": "2019-08-24T14:15:22Z",
"user_id": "a169451c-8525-4352-b8ca-070dd449a1a5",
"user_updated_at": "2019-08-24T14:15:22Z",
"username": "string"
}
]
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK | OK | array of codersdk.OrganizationMemberWithUserData |
Response Schema
Status Code 200
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
[array item] |
array | false | ||
» avatar_url |
string | false | ||
» created_at |
string(date-time) | false | ||
» email |
string | false | ||
» global_roles |
array | false | ||
»» display_name |
string | false | ||
»» name |
string | false | ||
»» organization_id |
string | false | ||
» has_ai_seat |
boolean | false | Has ai seat intentionally omits omitempty so the API always includes the field, even when false. | |
» is_service_account |
boolean | false | ||
» last_seen_at |
string(date-time) | false | ||
» login_type |
codersdk.LoginType | false | ||
» name |
string | false | ||
» organization_id |
string(uuid) | false | ||
» roles |
array | false | ||
» status |
codersdk.UserStatus | false | ||
» updated_at |
string(date-time) | false | ||
» user_created_at |
string(date-time) | false | ||
» user_id |
string(uuid) | false | ||
» user_updated_at |
string(date-time) | false | ||
» username |
string | false |
Enumerated Values
| Property | Value(s) |
|---|---|
login_type |
``, github, none, oidc, password, token |
status |
active, suspended |
To perform this operation, you must be authenticated. Learn more.
Get member roles by organization
Code samples
# Example request using curl
curl -X GET http://coder-server:8080/api/v2/organizations/{organization}/members/roles \
-H 'Accept: application/json' \
-H 'Coder-Session-Token: API_KEY'
GET /api/v2/organizations/{organization}/members/roles
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
organization |
path | string(uuid) | true | Organization ID |
Example responses
200 Response
[
{
"assignable": true,
"built_in": true,
"display_name": "string",
"name": "string",
"organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
"organization_member_permissions": [
{
"action": "application_connect",
"negate": true,
"resource_type": "*"
}
],
"organization_permissions": [
{
"action": "application_connect",
"negate": true,
"resource_type": "*"
}
],
"site_permissions": [
{
"action": "application_connect",
"negate": true,
"resource_type": "*"
}
],
"user_permissions": [
{
"action": "application_connect",
"negate": true,
"resource_type": "*"
}
]
}
]
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK | OK | array of codersdk.AssignableRoles |
Response Schema
Status Code 200
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
[array item] |
array | false | ||
» assignable |
boolean | false | ||
» built_in |
boolean | false | Built in roles are immutable | |
» display_name |
string | false | ||
» name |
string | false | ||
» organization_id |
string(uuid) | false | ||
» organization_member_permissions |
array | false | Organization member permissions are specific for the organization in the field 'OrganizationID' above. | |
»» action |
codersdk.RBACAction | false | ||
»» negate |
boolean | false | Negate makes this a negative permission | |
»» resource_type |
codersdk.RBACResource | false | ||
» organization_permissions |
array | false | Organization permissions are specific for the organization in the field 'OrganizationID' above. | |
» site_permissions |
array | false | ||
» user_permissions |
array | false |
Enumerated Values
| Property | Value(s) |
|---|---|
action |
application_connect, assign, create, create_agent, delete, delete_agent, read, read_personal, share, ssh, start, stop, unassign, update, update_agent, update_personal, use, view_insights |
resource_type |
*, ai_gateway_key, ai_model_price, ai_provider, ai_seat, aibridge_interception, api_key, assign_org_role, assign_role, audit_log, boundary_log, boundary_usage, chat, connection_log, crypto_key, debug_info, deployment_config, deployment_stats, file, group, group_member, idpsync_settings, inbox_notification, license, mcp_server_config, notification_message, notification_preference, notification_template, oauth2_app, oauth2_app_code_token, oauth2_app_secret, organization, organization_member, prebuilt_workspace, provisioner_daemon, provisioner_jobs, replicas, system, tailnet_coordinator, task, template, usage_event, user, user_secret, user_skill, webpush_subscription, workspace, workspace_agent_devcontainers, workspace_agent_resource_monitor, workspace_build_orchestration, workspace_dormant, workspace_proxy |
To perform this operation, you must be authenticated. Learn more.
Update a custom organization role
Code samples
# Example request using curl
curl -X PUT http://coder-server:8080/api/v2/organizations/{organization}/members/roles \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'Coder-Session-Token: API_KEY'
PUT /api/v2/organizations/{organization}/members/roles
Body parameter
{
"display_name": "string",
"name": "string",
"organization_member_permissions": [
{
"action": "application_connect",
"negate": true,
"resource_type": "*"
}
],
"organization_permissions": [
{
"action": "application_connect",
"negate": true,
"resource_type": "*"
}
],
"site_permissions": [
{
"action": "application_connect",
"negate": true,
"resource_type": "*"
}
],
"user_permissions": [
{
"action": "application_connect",
"negate": true,
"resource_type": "*"
}
]
}
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
organization |
path | string(uuid) | true | Organization ID |
body |
body | codersdk.CustomRoleRequest | true | Update role request |
Example responses
200 Response
[
{
"display_name": "string",
"name": "string",
"organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
"organization_member_permissions": [
{
"action": "application_connect",
"negate": true,
"resource_type": "*"
}
],
"organization_permissions": [
{
"action": "application_connect",
"negate": true,
"resource_type": "*"
}
],
"site_permissions": [
{
"action": "application_connect",
"negate": true,
"resource_type": "*"
}
],
"user_permissions": [
{
"action": "application_connect",
"negate": true,
"resource_type": "*"
}
]
}
]
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK | OK | array of codersdk.Role |
Response Schema
Status Code 200
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
[array item] |
array | false | ||
» display_name |
string | false | ||
» name |
string | false | ||
» organization_id |
string(uuid) | false | ||
» organization_member_permissions |
array | false | Organization member permissions are specific for the organization in the field 'OrganizationID' above. | |
»» action |
codersdk.RBACAction | false | ||
»» negate |
boolean | false | Negate makes this a negative permission | |
»» resource_type |
codersdk.RBACResource | false | ||
» organization_permissions |
array | false | Organization permissions are specific for the organization in the field 'OrganizationID' above. | |
» site_permissions |
array | false | ||
» user_permissions |
array | false |
Enumerated Values
| Property | Value(s) |
|---|---|
action |
application_connect, assign, create, create_agent, delete, delete_agent, read, read_personal, share, ssh, start, stop, unassign, update, update_agent, update_personal, use, view_insights |
resource_type |
*, ai_gateway_key, ai_model_price, ai_provider, ai_seat, aibridge_interception, api_key, assign_org_role, assign_role, audit_log, boundary_log, boundary_usage, chat, connection_log, crypto_key, debug_info, deployment_config, deployment_stats, file, group, group_member, idpsync_settings, inbox_notification, license, mcp_server_config, notification_message, notification_preference, notification_template, oauth2_app, oauth2_app_code_token, oauth2_app_secret, organization, organization_member, prebuilt_workspace, provisioner_daemon, provisioner_jobs, replicas, system, tailnet_coordinator, task, template, usage_event, user, user_secret, user_skill, webpush_subscription, workspace, workspace_agent_devcontainers, workspace_agent_resource_monitor, workspace_build_orchestration, workspace_dormant, workspace_proxy |
To perform this operation, you must be authenticated. Learn more.
Insert a custom organization role
Code samples
# Example request using curl
curl -X POST http://coder-server:8080/api/v2/organizations/{organization}/members/roles \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'Coder-Session-Token: API_KEY'
POST /api/v2/organizations/{organization}/members/roles
Body parameter
{
"display_name": "string",
"name": "string",
"organization_member_permissions": [
{
"action": "application_connect",
"negate": true,
"resource_type": "*"
}
],
"organization_permissions": [
{
"action": "application_connect",
"negate": true,
"resource_type": "*"
}
],
"site_permissions": [
{
"action": "application_connect",
"negate": true,
"resource_type": "*"
}
],
"user_permissions": [
{
"action": "application_connect",
"negate": true,
"resource_type": "*"
}
]
}
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
organization |
path | string(uuid) | true | Organization ID |
body |
body | codersdk.CustomRoleRequest | true | Insert role request |
Example responses
200 Response
[
{
"display_name": "string",
"name": "string",
"organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
"organization_member_permissions": [
{
"action": "application_connect",
"negate": true,
"resource_type": "*"
}
],
"organization_permissions": [
{
"action": "application_connect",
"negate": true,
"resource_type": "*"
}
],
"site_permissions": [
{
"action": "application_connect",
"negate": true,
"resource_type": "*"
}
],
"user_permissions": [
{
"action": "application_connect",
"negate": true,
"resource_type": "*"
}
]
}
]
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK | OK | array of codersdk.Role |
Response Schema
Status Code 200
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
[array item] |
array | false | ||
» display_name |
string | false | ||
» name |
string | false | ||
» organization_id |
string(uuid) | false | ||
» organization_member_permissions |
array | false | Organization member permissions are specific for the organization in the field 'OrganizationID' above. | |
»» action |
codersdk.RBACAction | false | ||
»» negate |
boolean | false | Negate makes this a negative permission | |
»» resource_type |
codersdk.RBACResource | false | ||
» organization_permissions |
array | false | Organization permissions are specific for the organization in the field 'OrganizationID' above. | |
» site_permissions |
array | false | ||
» user_permissions |
array | false |
Enumerated Values
| Property | Value(s) |
|---|---|
action |
application_connect, assign, create, create_agent, delete, delete_agent, read, read_personal, share, ssh, start, stop, unassign, update, update_agent, update_personal, use, view_insights |
resource_type |
*, ai_gateway_key, ai_model_price, ai_provider, ai_seat, aibridge_interception, api_key, assign_org_role, assign_role, audit_log, boundary_log, boundary_usage, chat, connection_log, crypto_key, debug_info, deployment_config, deployment_stats, file, group, group_member, idpsync_settings, inbox_notification, license, mcp_server_config, notification_message, notification_preference, notification_template, oauth2_app, oauth2_app_code_token, oauth2_app_secret, organization, organization_member, prebuilt_workspace, provisioner_daemon, provisioner_jobs, replicas, system, tailnet_coordinator, task, template, usage_event, user, user_secret, user_skill, webpush_subscription, workspace, workspace_agent_devcontainers, workspace_agent_resource_monitor, workspace_build_orchestration, workspace_dormant, workspace_proxy |
To perform this operation, you must be authenticated. Learn more.
Delete a custom organization role
Code samples
# Example request using curl
curl -X DELETE http://coder-server:8080/api/v2/organizations/{organization}/members/roles/{roleName} \
-H 'Accept: application/json' \
-H 'Coder-Session-Token: API_KEY'
DELETE /api/v2/organizations/{organization}/members/roles/{roleName}
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
organization |
path | string(uuid) | true | Organization ID |
roleName |
path | string | true | Role name |
Example responses
200 Response
[
{
"display_name": "string",
"name": "string",
"organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
"organization_member_permissions": [
{
"action": "application_connect",
"negate": true,
"resource_type": "*"
}
],
"organization_permissions": [
{
"action": "application_connect",
"negate": true,
"resource_type": "*"
}
],
"site_permissions": [
{
"action": "application_connect",
"negate": true,
"resource_type": "*"
}
],
"user_permissions": [
{
"action": "application_connect",
"negate": true,
"resource_type": "*"
}
]
}
]
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK | OK | array of codersdk.Role |
Response Schema
Status Code 200
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
[array item] |
array | false | ||
» display_name |
string | false | ||
» name |
string | false | ||
» organization_id |
string(uuid) | false | ||
» organization_member_permissions |
array | false | Organization member permissions are specific for the organization in the field 'OrganizationID' above. | |
»» action |
codersdk.RBACAction | false | ||
»» negate |
boolean | false | Negate makes this a negative permission | |
»» resource_type |
codersdk.RBACResource | false | ||
» organization_permissions |
array | false | Organization permissions are specific for the organization in the field 'OrganizationID' above. | |
» site_permissions |
array | false | ||
» user_permissions |
array | false |
Enumerated Values
| Property | Value(s) |
|---|---|
action |
application_connect, assign, create, create_agent, delete, delete_agent, read, read_personal, share, ssh, start, stop, unassign, update, update_agent, update_personal, use, view_insights |
resource_type |
*, ai_gateway_key, ai_model_price, ai_provider, ai_seat, aibridge_interception, api_key, assign_org_role, assign_role, audit_log, boundary_log, boundary_usage, chat, connection_log, crypto_key, debug_info, deployment_config, deployment_stats, file, group, group_member, idpsync_settings, inbox_notification, license, mcp_server_config, notification_message, notification_preference, notification_template, oauth2_app, oauth2_app_code_token, oauth2_app_secret, organization, organization_member, prebuilt_workspace, provisioner_daemon, provisioner_jobs, replicas, system, tailnet_coordinator, task, template, usage_event, user, user_secret, user_skill, webpush_subscription, workspace, workspace_agent_devcontainers, workspace_agent_resource_monitor, workspace_build_orchestration, workspace_dormant, workspace_proxy |
To perform this operation, you must be authenticated. Learn more.
Get organization member
Code samples
# Example request using curl
curl -X GET http://coder-server:8080/api/v2/organizations/{organization}/members/{user} \
-H 'Accept: application/json' \
-H 'Coder-Session-Token: API_KEY'
GET /api/v2/organizations/{organization}/members/{user}
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
organization |
path | string | true | Organization ID |
user |
path | string | true | User ID, name, or me |
Example responses
200 Response
{
"avatar_url": "string",
"created_at": "2019-08-24T14:15:22Z",
"email": "string",
"global_roles": [
{
"display_name": "string",
"name": "string",
"organization_id": "string"
}
],
"has_ai_seat": true,
"is_service_account": true,
"last_seen_at": "2019-08-24T14:15:22Z",
"login_type": "",
"name": "string",
"organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
"roles": [
{
"display_name": "string",
"name": "string",
"organization_id": "string"
}
],
"status": "active",
"updated_at": "2019-08-24T14:15:22Z",
"user_created_at": "2019-08-24T14:15:22Z",
"user_id": "a169451c-8525-4352-b8ca-070dd449a1a5",
"user_updated_at": "2019-08-24T14:15:22Z",
"username": "string"
}
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK | OK | codersdk.OrganizationMemberWithUserData |
To perform this operation, you must be authenticated. Learn more.
Add organization member
Code samples
# Example request using curl
curl -X POST http://coder-server:8080/api/v2/organizations/{organization}/members/{user} \
-H 'Accept: application/json' \
-H 'Coder-Session-Token: API_KEY'
POST /api/v2/organizations/{organization}/members/{user}
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
organization |
path | string | true | Organization ID |
user |
path | string | true | User ID, name, or me |
Example responses
200 Response
{
"created_at": "2019-08-24T14:15:22Z",
"organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
"roles": [
{
"display_name": "string",
"name": "string",
"organization_id": "string"
}
],
"updated_at": "2019-08-24T14:15:22Z",
"user_id": "a169451c-8525-4352-b8ca-070dd449a1a5"
}
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK | OK | codersdk.OrganizationMember |
To perform this operation, you must be authenticated. Learn more.
Remove organization member
Code samples
# Example request using curl
curl -X DELETE http://coder-server:8080/api/v2/organizations/{organization}/members/{user} \
-H 'Coder-Session-Token: API_KEY'
DELETE /api/v2/organizations/{organization}/members/{user}
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
organization |
path | string | true | Organization ID |
user |
path | string | true | User ID, name, or me |
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 204 | No Content | No Content |
To perform this operation, you must be authenticated. Learn more.
Assign role to organization member
Code samples
# Example request using curl
curl -X PUT http://coder-server:8080/api/v2/organizations/{organization}/members/{user}/roles \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'Coder-Session-Token: API_KEY'
PUT /api/v2/organizations/{organization}/members/{user}/roles
Body parameter
{
"roles": [
"string"
]
}
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
organization |
path | string | true | Organization ID |
user |
path | string | true | User ID, name, or me |
body |
body | codersdk.UpdateRoles | true | Update roles request |
Example responses
200 Response
{
"created_at": "2019-08-24T14:15:22Z",
"organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
"roles": [
{
"display_name": "string",
"name": "string",
"organization_id": "string"
}
],
"updated_at": "2019-08-24T14:15:22Z",
"user_id": "a169451c-8525-4352-b8ca-070dd449a1a5"
}
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK | OK | codersdk.OrganizationMember |
To perform this operation, you must be authenticated. Learn more.
Paginated organization members
Code samples
# Example request using curl
curl -X GET http://coder-server:8080/api/v2/organizations/{organization}/paginated-members \
-H 'Accept: application/json' \
-H 'Coder-Session-Token: API_KEY'
GET /api/v2/organizations/{organization}/paginated-members
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
organization |
path | string | true | Organization ID |
q |
query | string | false | Member search query |
after_id |
query | string(uuid) | false | After ID |
limit |
query | integer | false | Page limit, if 0 returns all members |
offset |
query | integer | false | Page offset |
Example responses
200 Response
[
{
"count": 0,
"members": [
{
"avatar_url": "string",
"created_at": "2019-08-24T14:15:22Z",
"email": "string",
"global_roles": [
{
"display_name": "string",
"name": "string",
"organization_id": "string"
}
],
"has_ai_seat": true,
"is_service_account": true,
"last_seen_at": "2019-08-24T14:15:22Z",
"login_type": "",
"name": "string",
"organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
"roles": [
{
"display_name": "string",
"name": "string",
"organization_id": "string"
}
],
"status": "active",
"updated_at": "2019-08-24T14:15:22Z",
"user_created_at": "2019-08-24T14:15:22Z",
"user_id": "a169451c-8525-4352-b8ca-070dd449a1a5",
"user_updated_at": "2019-08-24T14:15:22Z",
"username": "string"
}
]
}
]
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK | OK | array of codersdk.PaginatedMembersResponse |
Response Schema
Status Code 200
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
[array item] |
array | false | ||
» count |
integer | false | ||
» members |
array | false | ||
»» avatar_url |
string | false | ||
»» created_at |
string(date-time) | false | ||
»» email |
string | false | ||
»» global_roles |
array | false | ||
»»» display_name |
string | false | ||
»»» name |
string | false | ||
»»» organization_id |
string | false | ||
»» has_ai_seat |
boolean | false | Has ai seat intentionally omits omitempty so the API always includes the field, even when false. | |
»» is_service_account |
boolean | false | ||
»» last_seen_at |
string(date-time) | false | ||
»» login_type |
codersdk.LoginType | false | ||
»» name |
string | false | ||
»» organization_id |
string(uuid) | false | ||
»» roles |
array | false | ||
»» status |
codersdk.UserStatus | false | ||
»» updated_at |
string(date-time) | false | ||
»» user_created_at |
string(date-time) | false | ||
»» user_id |
string(uuid) | false | ||
»» user_updated_at |
string(date-time) | false | ||
»» username |
string | false |
Enumerated Values
| Property | Value(s) |
|---|---|
login_type |
``, github, none, oidc, password, token |
status |
active, suspended |
To perform this operation, you must be authenticated. Learn more.
Get site member roles
Code samples
# Example request using curl
curl -X GET http://coder-server:8080/api/v2/users/roles \
-H 'Accept: application/json' \
-H 'Coder-Session-Token: API_KEY'
GET /api/v2/users/roles
Example responses
200 Response
[
{
"assignable": true,
"built_in": true,
"display_name": "string",
"name": "string",
"organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
"organization_member_permissions": [
{
"action": "application_connect",
"negate": true,
"resource_type": "*"
}
],
"organization_permissions": [
{
"action": "application_connect",
"negate": true,
"resource_type": "*"
}
],
"site_permissions": [
{
"action": "application_connect",
"negate": true,
"resource_type": "*"
}
],
"user_permissions": [
{
"action": "application_connect",
"negate": true,
"resource_type": "*"
}
]
}
]
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK | OK | array of codersdk.AssignableRoles |
Response Schema
Status Code 200
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
[array item] |
array | false | ||
» assignable |
boolean | false | ||
» built_in |
boolean | false | Built in roles are immutable | |
» display_name |
string | false | ||
» name |
string | false | ||
» organization_id |
string(uuid) | false | ||
» organization_member_permissions |
array | false | Organization member permissions are specific for the organization in the field 'OrganizationID' above. | |
»» action |
codersdk.RBACAction | false | ||
»» negate |
boolean | false | Negate makes this a negative permission | |
»» resource_type |
codersdk.RBACResource | false | ||
» organization_permissions |
array | false | Organization permissions are specific for the organization in the field 'OrganizationID' above. | |
» site_permissions |
array | false | ||
» user_permissions |
array | false |
Enumerated Values
| Property | Value(s) |
|---|---|
action |
application_connect, assign, create, create_agent, delete, delete_agent, read, read_personal, share, ssh, start, stop, unassign, update, update_agent, update_personal, use, view_insights |
resource_type |
*, ai_gateway_key, ai_model_price, ai_provider, ai_seat, aibridge_interception, api_key, assign_org_role, assign_role, audit_log, boundary_log, boundary_usage, chat, connection_log, crypto_key, debug_info, deployment_config, deployment_stats, file, group, group_member, idpsync_settings, inbox_notification, license, mcp_server_config, notification_message, notification_preference, notification_template, oauth2_app, oauth2_app_code_token, oauth2_app_secret, organization, organization_member, prebuilt_workspace, provisioner_daemon, provisioner_jobs, replicas, system, tailnet_coordinator, task, template, usage_event, user, user_secret, user_skill, webpush_subscription, workspace, workspace_agent_devcontainers, workspace_agent_resource_monitor, workspace_build_orchestration, workspace_dormant, workspace_proxy |
To perform this operation, you must be authenticated. Learn more.