Organizations

Endpoints for creating and managing organizations, their members, avatars, Rancher integration tokens, and organization-scoped access/NATS tokens.

All paths below are relative to the API root /api/v1. For example, GET /orgs/{orgname} is GET https://<akp-host>/api/v1/orgs/{orgname}. In these paths orgname is the organization slug (e.g. appscode).

Unless noted, authenticated endpoints accept a personal access token:

curl -H "Authorization: token $AKP_TOKEN" \
  https://<akp-host>/api/v1/orgs/appscode

Authorization checks (e.g. edit:org, admin:org, view:avatar) are relationship-based (OpenFGA) and evaluated against the caller’s role in the organization.

Organization lifecycle

POST /orgs

Create a new organization owned by the authenticated user.

  • Auth: token. The user must be permitted to create organizations (CanCreateOrganization); otherwise 403 is returned.

Request body (CreateOrgOption):

{
  "username": "acme",
  "full_name": "Acme Inc.",
  "description": "Acme engineering org",
  "website": "https://acme.example.com",
  "location": "Remote",
  "orgType": "public",
  "visibility": "public"
}
FieldTypeRequiredDescription
usernamestringyesSlug/username of the new organization.
full_namestringnoDisplay name.
descriptionstringnoFree-text description.
websitestringnoWebsite URL.
locationstringnoLocation text.
orgTypestringnoOne of public (default), limited, or private.
rancherManagementClusterEndPointstringnoRancher management cluster endpoint (for Rancher-origin orgs).
visibilitystringnoOne of "", public, limited, private.

Response: 201 Created with the created Organization:

{
  "id": 42,
  "username": "acme",
  "full_name": "Acme Inc.",
  "avatar_url": "https://<akp-host>/accounts/avatars?obj=avatars/42-<hash>",
  "description": "Acme engineering org",
  "website": "https://acme.example.com",
  "location": "Remote",
  "rancherManagementClusterEndPoint": "",
  "visibility": "public",
  "orgType": 0
}

PATCH /orgs/claim/{claimID}

Claim a previously created standalone (marketplace) organization and assign ownership to the authenticated user.

  • Auth: token. Only registered on AppsCode-hosted deployments (setting.AppsCodeHosted).

Path parameters:

NameTypeDescription
claimIDstringClaim identifier of the standalone organization.

Response: 200 OK returning the claimed organization as a free-form Kubernetes object (models.User.APIFormat, dynamic payload). 409 Conflict if the organization was already claimed; 404 if the claim ID is unknown.

GET /orgs/claim/

Return the claim ID of the oldest claimable standalone organization, by proxying an eligibility check to the central marketplace server.

  • Auth: token + site admin (reqSiteAdmin). Only registered for marketplace deployments or in dev run mode.

Response: 200 OK (OrgClaimableCheckResp):

{
  "isClaimable": true,
  "claimID": "a1b2c3d4"
}

Verified: not called against the live platform (registered only on marketplace/dev deployments and requires site admin).

GET /orgs/{orgname}

Get an organization’s details (returned if visible to the requesting user).

  • Auth: public (no auth required). A non-public org may return 404 to callers who cannot see it.

Path parameters:

NameTypeDescription
orgnamestringOrganization slug.

Response: 200 OK (Organization):

{
  "id": 3,
  "username": "appscode",
  "full_name": "",
  "avatar_url": "https://<akp-host>/accounts/avatars?obj=avatars/3-<hash>",
  "description": "",
  "website": "",
  "location": "",
  "rancherManagementClusterEndPoint": "",
  "visibility": "public",
  "orgType": 6
}

Verified: GET returned 200 for appscode on 2026-07-14.

PATCH /orgs/{orgname}

Update an organization’s profile fields.

  • Auth: token + authzCheck(edit:org) (Organization_CanEditOrg).

Path parameters:

NameTypeDescription
orgnamestringOrganization slug.

Request body (EditOrgOption):

{
  "full_name": "Acme Inc.",
  "description": "Updated description",
  "website": "https://acme.example.com",
  "location": "Remote",
  "orgType": "limited",
  "visibility": "limited"
}
FieldTypeRequiredDescription
full_namestringnoDisplay name.
descriptionstringnoFree-text description.
websitestringnoWebsite URL.
locationstringnoLocation text.
orgTypestringnoOne of public, limited, or private.
rancherManagementClusterEndPointstringnoRancher management cluster endpoint.
visibilitystringnoOne of "", public, limited, private.

Response: 200 OK with the updated Organization (same shape as GET /orgs/{orgname}).

DELETE /orgs/{orgname}

Delete an organization.

  • Auth: token + authzCheck(delete:org) (Organization_CanDeleteOrg). The requester must be the last admin (per the orgLastAdmin condition).

Path parameters:

NameTypeDescription
orgnamestringOrganization slug.

Response: 204 No Content on success.

Membership & ownership checks

GET /orgs/{orgname}/user/{username}

Check whether a user exists (in the org context). Looks up a user by username and returns their profile if the user exists and is active.

  • Auth: token (org context).

Path parameters:

NameTypeDescription
orgnamestringOrganization slug.
usernamestringUsername to look up.

Response: 200 OK (Profile):

{
  "name": "someuser",
  "full_name": "Some User",
  "email": "user@example.com",
  "keep_email_private": false,
  "website": "",
  "location": "",
  "language": "en-US",
  "description": ""
}

400 if the user does not exist or is inactive.

Verified: GET returned 200 for appscode/appscode on 2026-07-14.

GET /orgs/{orgname}/is-owner

Return 200 if the authenticated user is an owner of the organization. Ownership is enforced by upstream middleware.

  • Auth: token (org context).

Path parameters:

NameTypeDescription
orgnamestringOrganization slug.

Response: 200 OK (empty body) when the caller is an owner; otherwise 403.

Verified: GET returned 200 for appscode on 2026-07-14.

GET /orgs/{orgname}/members

List an organization’s members. Non-members (and unauthenticated callers) see only public members.

  • Auth: public (no auth required); the response is scoped to what the caller may see.

Path parameters:

NameTypeDescription
orgnamestringOrganization slug.

Response: 200 OK — an array of User:

[
  {
    "id": 2,
    "login": "someuser",
    "username": "someuser",
    "full_name": "Some User",
    "email": "user@example.com",
    "avatar_url": "https://secure.gravatar.com/avatar/<hash>?d=identicon",
    "language": "en-US",
    "is_admin": true,
    "last_login": "2026-07-13T18:23:53Z",
    "created": "2026-07-05T06:46:29Z",
    "type": 0,
    "active": true,
    "prohibit_login": false,
    "location": "",
    "website": "",
    "description": "",
    "orgAdmin": true,
    "clientOrgUser": false
  }
]

username is a backward-compatibility alias of login.

Verified: GET returned 200 for appscode on 2026-07-14.

POST /orgs/{orgname}/members/action/{action}

Perform a membership action for a member identified by the uid query parameter.

  • Auth: token + org membership.

Path parameters:

NameTypeDescription
orgnamestringOrganization slug.
actionstringOne of private, public, remove, leave.

Query parameters:

NameTypeRequiredDescription
uidinteger (int64)yesUser ID of the member the action applies to.

Response: 200 OK when the action is performed. 400 if uid is missing or invalid.

GET /orgs/{orgname}/members/{username}

Check whether a user is a member of an organization.

  • Auth: public (no auth required).

Path parameters:

NameTypeDescription
orgnamestringOrganization slug.
usernamestringUsername to check.

Response: 204 No Content if the user is a member; 404 if not; may redirect (302) to the public-members check for non-members of the org.

Verified: GET returned 204 for member appscode/someuser on 2026-07-14.

DELETE /orgs/{orgname}/members/{username}

Remove a member from the organization.

  • Auth: token + org ownership + authzCheck(admin:org) (Organization_CanRemoveMember, orgLastMember condition). Site admins cannot be removed from the administrative org.

Path parameters:

NameTypeDescription
orgnamestringOrganization slug.
usernamestringUsername of the member to remove.

Response: 204 No Content on success.

GET /orgs/{orgname}/public_members

List an organization’s public members.

  • Auth: public (no auth required).

Path parameters:

NameTypeDescription
orgnamestringOrganization slug.

Response: 200 OK — an array of User (same shape as GET /orgs/{orgname}/members).

Verified: GET returned 200 for appscode on 2026-07-14.

GET /orgs/{orgname}/public_members/{username}

Check whether a user is a public member of an organization.

  • Auth: public (no auth required).

Path parameters:

NameTypeDescription
orgnamestringOrganization slug.
usernamestringUsername to check.

Response: 204 No Content if the user is a public member; 404 if not.

Verified: GET returned 404 for appscode/someuser on 2026-07-14 (member is not public).

PUT /orgs/{orgname}/public_members/{username}

Publicize the caller’s own organization membership.

  • Auth: token + org membership. A user cannot publicize another member (403).

Path parameters:

NameTypeDescription
orgnamestringOrganization slug.
usernamestringThe caller’s own username.

Response: 204 No Content on success.

DELETE /orgs/{orgname}/public_members/{username}

Conceal (make private) the caller’s own organization membership.

  • Auth: token + org membership. A user cannot conceal another member (403).

Path parameters:

NameTypeDescription
orgnamestringOrganization slug.
usernamestringThe caller’s own username.

Response: 204 No Content on success.

Organization avatar

GET /orgs/{orgname}/avatar/

Get the organization’s avatar URL.

  • Auth: token + authzCheck(view:avatar) (Organization_Viewer).

Path parameters:

NameTypeDescription
orgnamestringOrganization slug.

Response: 200 OK — a JSON string containing the avatar URL:

"https://<akp-host>/accounts/avatars?obj=avatars/3-<hash>"

POST /orgs/{orgname}/avatar/

Upload or set the organization avatar.

  • Auth: token + authzCheck(update:avatar) (Organization_Editor).

Path parameters:

NameTypeDescription
orgnamestringOrganization slug.

Request body: multipart/form-data (AvatarParams):

FieldTypeRequiredDescription
avatarbinary (file)noUploaded avatar image file.
sourcestringnoAvatar source selector.
gravatarstringnoGravatar email/URL.
federavatarbooleannoWhether to use a federated avatar.

Response: 200 OK; the exact body depends on the avatar handler (a free-form Kubernetes object).

POST /orgs/{orgname}/avatar/delete

Remove the organization’s avatar.

  • Auth: token + authzCheck(delete:avatar) (Organization_Editor).

Path parameters:

NameTypeDescription
orgnamestringOrganization slug.

Response: 200 OK on success.

Rancher integration tokens

GET /orgs/{orgname}/rancher/sync-token

Get the organization’s Rancher synchronization token.

  • Auth: token + authzCheck(view:sync-token) (Organization_Viewer).

Path parameters:

NameTypeDescription
orgnamestringOrganization slug.

Response: 200 OK (RancherAPIToken):

{
  "userID": 4,
  "orgID": 3,
  "orgName": "appscode",
  "accessKeyID": "<access-key-id>",
  "secretAccessKey": "<secret>"
}

404 when no sync token exists (e.g. the org is not of Rancher origin).

Verified: GET returned 404 for appscode on 2026-07-14 (org is not of Rancher origin — no sync token).

POST /orgs/{orgname}/rancher/sync-token

Create a Rancher organization synchronization token from the provided access key. The organization must be of Rancher origin.

  • Auth: token + authzCheck(create:rancher-org-sync-token) (Organization_Editor).

Path parameters:

NameTypeDescription
orgnamestringOrganization slug.

Request body (AccessToken):

{
  "name": "rancher-sync",
  "sha1": "<rancher-access-key>"
}
FieldTypeRequiredDescription
idinteger (int64)noToken ID.
namestringnoToken name.
sha1stringnoThe plaintext access key.
token_last_eightstringnoLast eight characters of the token.

Response: 200 OK (ApiResponseMessage):

{ "message": "token created" }

400 if the organization’s origin is not Rancher.

DELETE /orgs/{orgname}/rancher/sync-token

Delete the organization’s Rancher synchronization token.

  • Auth: token + authzCheck(remove:rancher-sync-token) (Organization_Editor).

Path parameters:

NameTypeDescription
orgnamestringOrganization slug.

Response: 200 OK on success.

GET /orgs/{orgname}/rancher/user-token

Deprecated. Return the caller’s Rancher API token for the organization.

  • Auth: token + org membership + authzCheck(view:sync-token) (Organization_Viewer).

Path parameters:

NameTypeDescription
orgnamestringOrganization slug.

Response: 200 OK (RancherAPIToken, same shape as the sync-token response).

Verified: GET returned 404 for appscode on 2026-07-14 (deprecated; org is not of Rancher origin).

POST /orgs/{orgname}/rancher/user-token

Deprecated. Store a Rancher API token for the caller in the organization.

  • Auth: token + org membership + authzCheck(create:rancher-org-sync-token) (Organization_Editor).

Path parameters:

NameTypeDescription
orgnamestringOrganization slug.

Request body (AccessToken): same as POST /orgs/{orgname}/rancher/sync-token.

Response: 200 OK on success.

DELETE /orgs/{orgname}/rancher/user-token

Deprecated. Delete the caller’s Rancher API token for the organization.

  • Auth: token + org membership + authzCheck(remove:rancher-sync-token) (Organization_Editor).

Path parameters:

NameTypeDescription
orgnamestringOrganization slug.

Response: 200 OK on success.

Organization access & NATS tokens

These endpoints manage tokens belonging to the organization’s system admin.

GET /orgs/{orgname}/tokens/access-tokens/

List the access tokens of the organization’s system admin.

  • Auth: token + org membership + authzCheck(list:access-token) (Organization_Viewer).

Path parameters:

NameTypeDescription
orgnamestringOrganization slug.

Response: 200 OK — an array of AccessTokenInfo:

[
  {
    "id": 12,
    "uid": 4,
    "name": "kube-ui-server 2026-07-05 7:49AM",
    "token": "",
    "tokenLastEight": "3d492e7c",
    "createdAt": 1783237775,
    "updatedAt": 1783785356,
    "hasRecentActivity": true,
    "hasUsed": true,
    "expDate": 2098856975
  }
]

The token value is empty for existing tokens; the full token is only returned at creation time. createdAt, updatedAt, and expDate are Unix timestamps. 400 if the organization system admin does not exist.

Verified: GET returned 200 for appscode on 2026-07-14.

DELETE /orgs/{orgname}/tokens/access-tokens/{id}

Delete an access token of the organization’s system admin.

  • Auth: token + org membership + authzCheck(delete:access-token) (Organization_Editor).

Path parameters:

NameTypeDescription
orgnamestringOrganization slug.
idinteger (int64)ID of the access token.

Response: 200 OK on success. 400 if the organization system admin does not exist.

GET /orgs/{orgname}/tokens/nats-tokens/

List the NATS user-type tokens of the organization’s system admin.

  • Auth: token + org membership + authzCheck(list:nats-token) (Organization_Viewer).

Path parameters:

NameTypeDescription
orgnamestringOrganization slug.

Response: 200 OK — an array of NatsAccount:

[
  {
    "id": 1,
    "uid": 4,
    "accountType": "user",
    "natsPubKey": "<nats-public-key>",
    "clusterID": "<cluster-uid>",
    "productName": "kubedb",
    "revoked": false
  }
]

400 if the organization system admin does not exist.

Verified: GET returned 200 for appscode on 2026-07-14 (empty list []).

POST /orgs/{orgname}/tokens/nats-tokens/{id}/revoke

Revoke a NATS user-type token of the organization’s system admin.

  • Auth: token + org membership + authzCheck(revoke:nats-token) (Organization_Editor).

Path parameters:

NameTypeDescription
orgnamestringOrganization slug.
idinteger (int64)ID of the NATS token.

Response: 200 OK on success. 400 if the organization system admin is missing or the NATS user is not found.