> ## Documentation Index
> Fetch the complete documentation index at: https://docs.qoder.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Member APIs

> List and manage organization members, stats, quotas, and add-on caps.

## About this document

For **integrations** that manage members and quotas outside the Qoder UI. Complete **[Get API Key](/account/teams/openapi/get-api-key)** first, then read **[Conventions](/account/teams/openapi/conventions)**.

### Requirements

* Valid API key: `Authorization: Bearer <api_key>`.
* Key must belong to the target organization; caller permissions must allow the operation.

## API list

### 1. List members

`GET /v1/organizations/{organization_id}/members`

Paginated retrieval of organization members, with keyword search support.

#### Path parameters

| Parameter         | Type   | Required | Description     |
| ----------------- | ------ | -------- | --------------- |
| `organization_id` | string | Yes      | Organization ID |

#### Query parameters

| Parameter        | Type    | Required | Description                              |
| ---------------- | ------- | -------- | ---------------------------------------- |
| `email`          | string  | No       | Exact email lookup                       |
| `includeDeleted` | string  | No       | Set to `true` to include removed members |
| `maxResults`     | integer | No       | Page size (default 20, max 100)          |
| `nextToken`      | string  | No       | Pagination cursor                        |

#### Success response (200 OK)

**Default query (active members only):**

```json theme={null}
{
  "members": [
    {
      "id": "member_abc123",
      "name": "Alice",
      "email": "alice@example.com",
      "role": "org_admin",
      "status": "ENABLED",
      "joinedAt": "2025-06-01T08:00:00Z"
    },
    {
      "id": "member_ghi789",
      "name": "Charlie",
      "role": "org_member",
      "status": "ENABLED",
      "joinedAt": "2025-07-10T14:30:00Z"
    }
  ],
  "maxResults": 20,
  "nextToken": "eyJwYWdlIjogMn0="
}
```

> Some member records may **not return** the `email` field; treat it as optional during integration.

**Including deleted members (**`**includeDeleted=true**`**):**

```json theme={null}
{
  "members": [
    {
      "id": "member_abc123",
      "name": "Alice",
      "email": "alice@example.com",
      "role": "org_admin",
      "status": "ENABLED",
      "joinedAt": "2025-06-01T08:00:00Z"
    },
    {
      "id": "member_def456",
      "name": "Bob",
      "email": "bob@example.com",
      "role": "org_member",
      "status": "DELETED",
      "joinedAt": "2025-03-15T10:00:00Z",
      "deletedAt": "2026-02-01T12:00:00Z"
    }
  ],
  "maxResults": 20,
  "nextToken": ""
}
```

> `deletedAt` is only returned for deleted members; active members do not include this field. An empty `nextToken` string indicates the last page.

#### Response fields

| Field                 | Type           | Description                                                                                                                                                                                 |
| --------------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `members`             | array          | Member list                                                                                                                                                                                 |
| `members[].id`        | string         | Member ID                                                                                                                                                                                   |
| `members[].name`      | string         | Member name                                                                                                                                                                                 |
| `members[].email`     | string         | Member email (may be empty)                                                                                                                                                                 |
| `members[].role`      | string         | Role name (e.g., `org_admin`, `org_member`)                                                                                                                                                 |
| `members[].status`    | string         | Member status: `ENABLED` (active), `DISABLED` (suspended), `UNACTIVATED` (not activated), `APPROVE_PENDING` (pending approval), `APPROVE_DECLINED` (approval declined), `DELETED` (removed) |
| `members[].joinedAt`  | string         | Join time (ISO 8601)                                                                                                                                                                        |
| `members[].deletedAt` | string or null | Deletion time (ISO 8601); not returned for active members                                                                                                                                   |
| `maxResults`          | int32          | Page size for this request                                                                                                                                                                  |
| `nextToken`           | string         | Next-page cursor; empty means last page                                                                                                                                                     |

***

### 2. Get member details

`GET /v1/organizations/{organization_id}/members/{member_id}`

Retrieve detailed information for a single member.

#### Path parameters

| Parameter         | Type   | Required | Description     |
| ----------------- | ------ | -------- | --------------- |
| `organization_id` | string | Yes      | Organization ID |
| `member_id`       | string | Yes      | Member ID       |

#### Success response (200 OK)

**Active member:**

```json theme={null}
{
  "id": "member_abc123",
  "name": "Alice",
  "email": "alice@example.com",
  "role": "org_admin",
  "status": "ENABLED",
  "joinedAt": "2025-06-01T08:00:00Z"
}
```

**Deleted member (**`**GetMember**` **automatically includes deleted members):**

```json theme={null}
{
  "id": "member_def456",
  "name": "Bob",
  "email": "bob@example.com",
  "role": "org_member",
  "status": "DELETED",
  "joinedAt": "2025-03-15T10:00:00Z",
  "deletedAt": "2026-02-01T12:00:00Z"
}
```

#### Response fields

Same as the `members[]` fields in "List members".

***

### 3. Get member statistics

`GET /v1/organizations/{organization_id}/members/statistics`

Retrieve statistical data about organization members.

#### Path parameters

| Parameter         | Type   | Required | Description     |
| ----------------- | ------ | -------- | --------------- |
| `organization_id` | string | Yes      | Organization ID |

#### Success response (200 OK)

```json theme={null}
{
  "totalMembers": 50,
  "billableMembers": 45,
  "adminMembers": 3,
  "purchasedSeats": 100,
  "remainingSeats": 55
}
```

#### Response fields

| Field             | Type  | Description                |
| ----------------- | ----- | -------------------------- |
| `totalMembers`    | int32 | Total number of members    |
| `billableMembers` | int32 | Number of billable members |
| `adminMembers`    | int32 | Number of admins           |
| `purchasedSeats`  | int32 | Number of purchased seats  |
| `remainingSeats`  | int32 | Number of remaining seats  |

***

### 4. Delete member

`DELETE /v1/organizations/{organization_id}/members/{member_id}`

Remove a member from the organization. Before removal, the system checks whether the member had usage in the current billing cycle.

#### Path parameters

| Parameter         | Type   | Required | Description     |
| ----------------- | ------ | -------- | --------------- |
| `organization_id` | string | Yes      | Organization ID |
| `member_id`       | string | Yes      | Member ID       |

#### Success response (200 OK)

**Member has usage in the current cycle (seat release deferred to end of cycle):**

```json theme={null}
{
  "id": "member_abc123",
  "hasBillingCycleUsage": true
}
```

**Member has no usage in the current cycle (seat can be released immediately):**

```json theme={null}
{
  "id": "member_abc123",
  "hasBillingCycleUsage": false
}
```

#### Response fields

| Field                  | Type   | Description                                                                             |
| ---------------------- | ------ | --------------------------------------------------------------------------------------- |
| `id`                   | string | ID of the deleted member                                                                |
| `hasBillingCycleUsage` | bool   | Whether the member had usage in the current billing cycle (affects seat release timing) |

#### Error responses

**Member not in this team (404)**

```json theme={null}
{
  "requestId": "req_abc123",
  "code": "UserNotTeamMember",
  "message": "User is not a member of this team"
}
```

**Insufficient members (400)**

```json theme={null}
{
  "requestId": "req_abc123",
  "code": "InsufficientMembers",
  "message": "The number of organization members cannot be less than the minimum requirement"
}
```

***

### 5. Get member quota

`GET /v1/organizations/{organization_id}/members/{member_id}/quota`

Query the full usage details for a specified member, including plan quota, resource pack quota, total quota, and organization shared pack quota.

#### Path parameters

| Parameter         | Type   | Required | Description     |
| ----------------- | ------ | -------- | --------------- |
| `organization_id` | string | Yes      | Organization ID |
| `member_id`       | string | Yes      | Member ID       |

#### Success response (200 OK)

**With organization shared pack, status normal:**

```json theme={null}
{
  "userId": "user_abc123",
  "planQuota": {
    "quotaSummary": {
      "usedValue": 350.5,
      "limitValue": 1000.0,
      "unit": "credits"
    }
  },
  "resourcePackageQuota": {
    "quotaSummary": {
      "usedValue": 100.0,
      "limitValue": 500.0,
      "unit": "credits"
    }
  },
  "totalQuota": {
    "quotaSummary": {
      "usedValue": 450.5,
      "limitValue": 1500.0,
      "unit": "credits"
    }
  },
  "sharedQuota": {
    "quotaSummary": {
      "usedValue": 200.0,
      "limitValue": 1000.0,
      "unit": "credits"
    }
  },
  "lastResetAt": "2026-03-01T00:00:00Z",
  "nextResetAt": "2026-04-01T00:00:00Z",
  "status": "active"
}
```

**No organization shared pack, usage exceeded:**

```json theme={null}
{
  "userId": "user_def456",
  "planQuota": {
    "quotaSummary": {
      "usedValue": 1000.0,
      "limitValue": 1000.0,
      "unit": "credits"
    }
  },
  "totalQuota": {
    "quotaSummary": {
      "usedValue": 1000.0,
      "limitValue": 1000.0,
      "unit": "credits"
    }
  },
  "lastResetAt": "2026-03-01T00:00:00Z",
  "nextResetAt": "2026-04-01T00:00:00Z",
  "status": "restricted"
}
```

> When the organization has no shared pack, `sharedQuota` is not returned; when the member has no resource pack, `resourcePackageQuota` is not returned. A `status` of `restricted` means the usage limit has been reached.

#### Response fields

| Field                  | Type           | Description                                                                                   |
| ---------------------- | -------------- | --------------------------------------------------------------------------------------------- |
| `userId`               | string         | User ID                                                                                       |
| `planQuota`            | object         | Plan quota information                                                                        |
| `resourcePackageQuota` | object         | Resource pack quota information                                                               |
| `totalQuota`           | object         | Total quota information (plan + resource pack)                                                |
| `sharedQuota`          | object or null | Organization shared pack quota (not returned if the member's organization has no shared pack) |
| `lastResetAt`          | string         | Last reset time (ISO 8601)                                                                    |
| `nextResetAt`          | string         | Next reset time (ISO 8601)                                                                    |
| `status`               | string         | User status: `active` or `restricted`                                                         |

**Quota summary fields**

| Field        | Type    | Description            |
| ------------ | ------- | ---------------------- |
| `usedValue`  | float64 | Amount used            |
| `limitValue` | float64 | Quota limit            |
| `unit`       | string  | Unit (e.g., `credits`) |

***

### 6. Batch get member quotas

`POST /v1/organizations/{organization_id}/members/batchGetQuota`

Query quota usage for multiple members in one request. This endpoint has the same quota scope as [Get member quota](#5-get-member-quota).

#### Path parameters

| Parameter         | Type   | Required | Description     |
| ----------------- | ------ | -------- | --------------- |
| `organization_id` | string | Yes      | Organization ID |

#### Request body (JSON)

| Field       | Type      | Required | Validation                 | Description                                  |
| ----------- | --------- | -------- | -------------------------- | -------------------------------------------- |
| `memberIds` | string\[] | Yes      | 1–100 non-empty member IDs | Members whose quota usage should be returned |

```json theme={null}
{
  "memberIds": ["member_abc123", "member_def456"]
}
```

#### Success response (200 OK)

```json theme={null}
{
  "quotas": [
    {
      "memberId": "member_abc123",
      "userId": "user_abc123",
      "planQuota": {
        "quotaSummary": {
          "usedValue": 350.5,
          "limitValue": 1000.0,
          "unit": "credits"
        }
      },
      "resourcePackageQuota": {
        "quotaSummary": {
          "usedValue": 100.0,
          "limitValue": 500.0,
          "unit": "credits"
        }
      },
      "totalQuota": {
        "quotaSummary": {
          "usedValue": 450.5,
          "limitValue": 1500.0,
          "unit": "credits"
        }
      },
      "sharedQuota": {
        "quotaSummary": {
          "usedValue": 200.0,
          "limitValue": 1000.0,
          "unit": "credits"
        }
      },
      "lastResetAt": "2026-03-01T00:00:00Z",
      "nextResetAt": "2026-04-01T00:00:00Z",
      "status": "active"
    },
    {
      "memberId": "member_def456",
      "userId": "user_def456"
    }
  ]
}
```

The `quotas` array follows the order of `memberIds`, including duplicate IDs. If a member has no quota record, only `memberId` and `userId` are returned for that item. If any member does not exist in the organization, the entire request returns `404 NotFound`; partial success is not returned.

#### Response fields

| Field                           | Type   | Description                                                      |
| ------------------------------- | ------ | ---------------------------------------------------------------- |
| `quotas`                        | array  | Quota usage results                                              |
| `quotas[].memberId`             | string | Member ID                                                        |
| `quotas[].userId`               | string | User ID                                                          |
| `quotas[].planQuota`            | object | Plan quota information; omitted when unavailable                 |
| `quotas[].resourcePackageQuota` | object | Resource pack quota information; omitted when unavailable        |
| `quotas[].totalQuota`           | object | Total quota information; omitted when unavailable                |
| `quotas[].sharedQuota`          | object | Organization shared pack quota; omitted when unavailable         |
| `quotas[].lastResetAt`          | string | Last reset time (ISO 8601); omitted when unavailable             |
| `quotas[].nextResetAt`          | string | Next reset time (ISO 8601); omitted when unavailable             |
| `quotas[].status`               | string | `active` or `restricted`; omitted when quota data is unavailable |

***

### 7. Update member Add-On Cap

`PUT /v1/organizations/{organization_id}/members/{member_id}/addon-cap`

Update a member's Shared Add-On quota cap (based on Big Model Credits quota).

#### Path parameters

| Parameter         | Type   | Required | Description     |
| ----------------- | ------ | -------- | --------------- |
| `organization_id` | string | Yes      | Organization ID |
| `member_id`       | string | Yes      | Member ID       |

#### Request parameters (JSON)

| Field      | Type          | Required | Validation                   | Description                                           |
| ---------- | ------------- | -------- | ---------------------------- | ----------------------------------------------------- |
| `addOnCap` | int64 or null | Yes      | Non-negative integer or null | Quota cap; `null` means unlimited, `0` means disabled |

#### Request examples

**Set a quota cap:**

```json theme={null}
{
  "addOnCap": 1000
}
```

**Set to unlimited:**

```json theme={null}
{
  "addOnCap": null
}
```

#### Success response (200 OK)

```json theme={null}
{
  "memberId": "member_abc123",
  "email": "alice@example.com",
  "addOnCap": 1000
}
```

**When unlimited:**

```json theme={null}
{
  "memberId": "member_abc123",
  "email": "alice@example.com",
  "addOnCap": null
}
```

#### Response fields

| Field      | Type          | Description                               |
| ---------- | ------------- | ----------------------------------------- |
| `memberId` | string        | Member ID                                 |
| `email`    | string        | Member email                              |
| `addOnCap` | int64 or null | Current quota cap; `null` means unlimited |

#### Error responses

**Invalid addOnCap format (400)**

```json theme={null}
{
  "requestId": "req_abc123",
  "code": "InvalidAddOnCapFormat",
  "message": "Invalid addOnCap format"
}
```

**Member not in this team (404)**

```json theme={null}
{
  "requestId": "req_abc123",
  "code": "UserNotTeamMember",
  "message": "User is not a member of this team"
}
```

***

### 8. Batch update member Add-On Cap

`POST /v1/organizations/{organization_id}/batchUpdateAddOnCap`

Batch update the Shared Add-On quota cap for specified members (based on Big Model Credits quota). Up to 100 members per request; all members are set to the same cap.

#### Path parameters

| Parameter         | Type   | Required | Description     |
| ----------------- | ------ | -------- | --------------- |
| `organization_id` | string | Yes      | Organization ID |

#### Request parameters (JSON)

| Field       | Type          | Required | Validation                   | Description                                           |
| ----------- | ------------- | -------- | ---------------------------- | ----------------------------------------------------- |
| `addOnCap`  | int64 or null | Yes      | Non-negative integer or null | Quota cap; `null` means unlimited, `0` means disabled |
| `memberIds` | string\[]     | Yes      | 1–100 non-empty strings      | List of member IDs to update                          |

#### Request examples

**Batch set quota cap:**

```json theme={null}
{
  "addOnCap": 1000,
  "memberIds": ["member_abc123", "member_def456"]
}
```

**Batch set to unlimited:**

```json theme={null}
{
  "addOnCap": null,
  "memberIds": ["member_abc123"]
}
```

#### Success response (200 OK)

```json theme={null}
{
  "members": [
    {
      "memberId": "member_abc123",
      "previousAddOnCap": 500
    },
    {
      "memberId": "member_def456",
      "previousAddOnCap": null
    }
  ]
}
```

> `previousAddOnCap` of `null` means the member previously had no limit (unlimited).

#### Response fields

| Field                        | Type          | Description                                                         |
| ---------------------------- | ------------- | ------------------------------------------------------------------- |
| `members`                    | array         | Update result list, in the same order as `memberIds` in the request |
| `members[].memberId`         | string        | Member ID                                                           |
| `members[].previousAddOnCap` | int64 or null | Previous quota cap; `null` means previously unlimited               |

#### Error responses

**Invalid addOnCap format (400)**

```json theme={null}
{
  "requestId": "req_abc123",
  "code": "InvalidAddOnCapFormat",
  "message": "Invalid addOnCap format"
}
```

**memberIds is empty (400)**

```json theme={null}
{
  "requestId": "req_abc123",
  "code": "BadRequest",
  "message": "memberIds must not be empty"
}
```

**memberIds exceeds 100 (400)**

```json theme={null}
{
  "requestId": "req_abc123",
  "code": "BadRequest",
  "message": "memberIds must not exceed 100"
}
```

***

## Error codes

| Error code                 | HTTP status | Description                                                            |
| -------------------------- | ----------- | ---------------------------------------------------------------------- |
| `BadRequest`               | 400         | Invalid request parameters (e.g., empty member\_id, negative addOnCap) |
| `InvalidBatchQuotaRequest` | 400         | Invalid JSON body for the batch quota request                          |
| `InvalidAddOnCapFormat`    | 400         | Invalid addOnCap format                                                |
| `InsufficientMembers`      | 400         | Organization member count cannot be lower than the minimum requirement |
| `Unauthorized`             | 401         | API key missing or invalid                                             |
| `Forbidden`                | 403         | No permission to access this organization                              |
| `NotFound`                 | 404         | Member not found                                                       |
| `UserNotTeamMember`        | 404         | User is not a member of this team                                      |
| `InternalError`            | 500         | Internal server error                                                  |

Error response shape: see **Error responses** in [Conventions](/account/teams/openapi/conventions).

***

## Usage examples

### List members

```bash theme={null}
curl -X GET "https://api.qoder.com/v1/organizations/org_xxx/members?maxResults=20" \
  -H "Authorization: Bearer <api_key>"
```

### Search member by email

```bash theme={null}
curl -X GET "https://api.qoder.com/v1/organizations/org_xxx/members?email=alice@example.com" \
  -H "Authorization: Bearer <api_key>"
```

### List members (including removed)

```bash theme={null}
curl -X GET "https://api.qoder.com/v1/organizations/org_xxx/members?includeDeleted=true" \
  -H "Authorization: Bearer <api_key>"
```

### Get member details

```bash theme={null}
curl -X GET "https://api.qoder.com/v1/organizations/org_xxx/members/member_abc123" \
  -H "Authorization: Bearer <api_key>"
```

### Get member statistics

```bash theme={null}
curl -X GET "https://api.qoder.com/v1/organizations/org_xxx/members/statistics" \
  -H "Authorization: Bearer <api_key>"
```

### Delete member

```bash theme={null}
curl -X DELETE "https://api.qoder.com/v1/organizations/org_xxx/members/member_abc123" \
  -H "Authorization: Bearer <api_key>"
```

### Update member Add-On Cap

```bash theme={null}
curl -X PUT "https://api.qoder.com/v1/organizations/org_xxx/members/member_abc123/addon-cap" \
  -H "Authorization: Bearer <api_key>" \
  -H "Content-Type: application/json" \
  -d '{
    "addOnCap": 1000
  }'
```

### Get member quota

```bash theme={null}
curl -X GET "https://api.qoder.com/v1/organizations/org_xxx/members/member_abc123/quota" \
  -H "Authorization: Bearer <api_key>"
```

### Batch get member quotas

```bash theme={null}
curl -X POST "https://api.qoder.com/v1/organizations/org_xxx/members/batchGetQuota" \
  -H "Authorization: Bearer <api_key>" \
  -H "Content-Type: application/json" \
  -d '{
    "memberIds": ["member_abc123", "member_def456"]
  }'
```

### Batch update member Add-On Cap

```bash theme={null}
curl -X POST "https://api.qoder.com/v1/organizations/org_xxx/batchUpdateAddOnCap" \
  -H "Authorization: Bearer <api_key>" \
  -H "Content-Type: application/json" \
  -d '{
    "addOnCap": 1000,
    "memberIds": ["member_abc123", "member_def456"]
  }'
```
