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

# Groups

> Organize vaults into groups and scope API key access

## The problem

Every API key with vault access can read and write **all** vaults in your organization. When different teams, clients, or integrations share an account, that's too broad.

## The solution

Vault groups let you:

1. **Organize** — group vaults by client, matter type, or team
2. **Restrict** — scope API keys so they only see vaults in specific groups
3. **Audit** — every group create, update, and delete is logged

***

## Create a group

```bash title="Endpoint" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
POST /vault/groups
```

<CodeGroup>
  ```bash title="cURL" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  curl -X POST https://api.case.dev/vault/groups \
    -H "Authorization: Bearer $CASEDEV_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "Acme Corp",
      "description": "All Acme Corp matters"
    }'
  ```

  ```bash title="CLI" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  casedev vault:groups create --name "Acme Corp"
  ```

  ```typescript title="Typescript" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  const group = await client.vault.groups.create({
    name: 'Acme Corp',
    description: 'All Acme Corp matters'
  });

  console.log(group.id);    // Use this to assign vaults
  console.log(group.slug);  // Auto-generated: "acme-corp"
  ```

  ```python title="Python" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  group = client.vault.groups.create(
      name='Acme Corp',
      description='All Acme Corp matters'
  )

  print(group.id)    # Use this to assign vaults
  print(group.slug)  # Auto-generated: "acme-corp"
  ```

  ```go title="Go" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  group, _ := client.Vault.Groups.New(ctx, casedev.VaultGroupNewParams{
  	Name: casedev.F("Acme Corp"),
  	Description: casedev.F("All Acme Corp matters"),
  })
  fmt.Println(group.ID)
  ```
</CodeGroup>

```json title="Response" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
{
  "id": "grp_abc123",
  "name": "Acme Corp",
  "slug": "acme-corp",
  "description": "All Acme Corp matters",
  "createdAt": "2025-02-17T10:30:00Z",
  "updatedAt": "2025-02-17T10:30:00Z"
}
```

| Field         | Type   | Description                              |
| ------------- | ------ | ---------------------------------------- |
| `name`        | string | **Required.** Display name for the group |
| `description` | string | Optional description                     |

<Info>
  The `slug` is auto-generated from the name and must be unique across your organization—including soft-deleted groups.
</Info>

***

## List groups

```bash title="Endpoint" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
GET /vault/groups
```

<CodeGroup>
  ```bash title="cURL" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  curl https://api.case.dev/vault/groups \
    -H "Authorization: Bearer $CASEDEV_API_KEY"
  ```

  ```bash title="CLI" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  casedev vault:groups list
  ```

  ```typescript title="Typescript" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  const { groups } = await client.vault.groups.list();

  for (const group of groups) {
    console.log(`${group.name} (${group.slug})`);
  }
  ```

  ```python title="Python" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  result = client.vault.groups.list()

  for group in result.groups:
      print(f'{group.name} ({group.slug})')
  ```

  ```go title="Go" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  result, _ := client.Vault.Groups.List(ctx)
  for _, group := range result.Groups {
  	fmt.Printf("%s (%s)\n", group.Name, group.Slug)
  }
  ```
</CodeGroup>

```json title="Response" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
{
  "groups": [
    {
      "id": "grp_abc123",
      "name": "Acme Corp",
      "slug": "acme-corp",
      "description": "All Acme Corp matters",
      "createdAt": "2025-02-17T10:30:00Z",
      "updatedAt": "2025-02-17T10:30:00Z"
    }
  ],
  "total": 1
}
```

<Info>
  If your API key is scoped to specific groups, this endpoint returns only those groups.
</Info>

***

## Update a group

Rename a group or change its description.

```bash title="Endpoint" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
PATCH /vault/groups/:groupId
```

<CodeGroup>
  ```bash title="cURL" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  curl -X PATCH "https://api.case.dev/vault/groups/$GROUP_ID" \
    -H "Authorization: Bearer $CASEDEV_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{"name": "Acme Corporation"}'
  ```

  ```bash title="CLI" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  casedev vault:groups update --group-id $GROUP_ID --name "Acme Corporation"
  ```

  ```typescript title="Typescript" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  const updated = await client.vault.groups.update(groupId, {
    name: 'Acme Corporation',
    description: 'Updated description'
  });
  ```

  ```python title="Python" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  updated = client.vault.groups.update(group_id,
      name='Acme Corporation',
      description='Updated description'
  )
  ```

  ```go title="Go" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  updated, _ := client.Vault.Groups.Update(ctx, groupID, casedev.VaultGroupUpdateParams{
  	Name: casedev.F("Acme Corporation"),
  })
  ```
</CodeGroup>

| Field         | Type           | Description                            |
| ------------- | -------------- | -------------------------------------- |
| `name`        | string         | New display name (slug is regenerated) |
| `description` | string \| null | New description, or `null` to clear    |

***

## Delete a group

Soft-deletes a group. The group must have no vaults assigned.

```bash title="Endpoint" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
DELETE /vault/groups/:groupId
```

<CodeGroup>
  ```bash title="cURL" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  curl -X DELETE "https://api.case.dev/vault/groups/$GROUP_ID" \
    -H "Authorization: Bearer $CASEDEV_API_KEY"
  ```

  ```bash title="CLI" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  casedev vault:groups delete --group-id $GROUP_ID
  ```

  ```typescript title="Typescript" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  await client.vault.groups.delete(groupId);
  ```

  ```python title="Python" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  client.vault.groups.delete(group_id)
  ```

  ```go title="Go" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  client.Vault.Groups.Delete(ctx, groupID)
  ```
</CodeGroup>

<Warning>
  You must move or delete all vaults in a group before deleting it. Attempting to delete a group with assigned vaults returns `409 Conflict`.
</Warning>

***

## Assign vaults to groups

### When creating a vault

Pass `groupId` to place a new vault into a group:

```bash title="Endpoint" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
POST /vault
```

<CodeGroup>
  ```bash title="cURL" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  curl -X POST https://api.case.dev/vault \
    -H "Authorization: Bearer $CASEDEV_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{"name": "Acme - Contract Review", "groupId": "grp_abc123"}'
  ```

  ```bash title="CLI" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  casedev vault create --name "Acme - Contract Review"
  ```

  ```typescript title="Typescript" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  const vault = await client.vault.create({
    name: 'Acme - Contract Review',
    groupId: 'grp_abc123'
  });
  ```

  ```python title="Python" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  vault = client.vault.create(
      name='Acme - Contract Review',
      group_id='grp_abc123'
  )
  ```

  ```go title="Go" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  vault, _ := client.Vault.New(ctx, casedev.VaultNewParams{
  	Name: casedev.F("Acme - Contract Review"),
  	GroupID: casedev.F("grp_abc123"),
  })
  fmt.Println(vault.ID)
  ```
</CodeGroup>

### Move an existing vault

Use `PATCH /vault/:id` to move a vault into (or between) groups:

<CodeGroup>
  ```bash title="cURL" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  curl -X PATCH "https://api.case.dev/vault/$VAULT_ID" \
    -H "Authorization: Bearer $CASEDEV_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{"groupId": "grp_abc123"}'
  ```

  ```bash title="CLI" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  # Move vault into a group
  casedev vault update --id $VAULT_ID --group-id grp_abc123

  # Remove vault from its group
  casedev vault update --id $VAULT_ID --group-id null
  ```

  ```typescript title="Typescript" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  // Move vault into a group
  await client.vault.update(vaultId, { groupId: 'grp_abc123' });

  // Remove vault from its group (unscoped keys only)
  await client.vault.update(vaultId, { groupId: null });
  ```

  ```python title="Python" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  # Move vault into a group
  client.vault.update(vault_id, group_id='grp_abc123')

  # Remove vault from its group (unscoped keys only)
  client.vault.update(vault_id, group_id=None)
  ```

  ```go title="Go" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  client.Vault.Update(ctx, vaultID, casedev.VaultUpdateParams{
  	GroupID: casedev.F("grp_abc123"),
  })
  ```
</CodeGroup>

***

## Scoped API keys

API keys can be restricted to specific vault groups. A scoped key can only:

* List and access vaults within its allowed groups
* Create new vaults in those groups (must provide `groupId`)
* See only the groups it has access to

Scoped keys **cannot** create, update, or delete groups themselves.

| Operation                            | Scoped key                          | Unscoped key |
| ------------------------------------ | ----------------------------------- | ------------ |
| List groups                          | Only allowed groups                 | All groups   |
| List vaults                          | Only vaults in allowed groups       | All vaults   |
| Get vault by ID                      | Allowed groups only (404 otherwise) | All vaults   |
| Create vault without `groupId`       | Denied (403)                        | Allowed      |
| Create vault in allowed group        | Allowed                             | Allowed      |
| Create vault in other group          | Denied (403)                        | Allowed      |
| Remove vault from group              | Denied (403)                        | Allowed      |
| Manage groups (create/update/delete) | Denied (403)                        | Allowed      |

<Info>
  Create scoped API keys in the [Console](https://console.case.dev) under **API Keys**. Select the Vault service, then check the groups you want the key to access. Leaving all groups unchecked gives full vault access.
</Info>

***

## Audit events

Every group lifecycle action emits an audit event:

| Event                 | When                                 |
| --------------------- | ------------------------------------ |
| `vault.group.created` | Group created                        |
| `vault.group.updated` | Group renamed or description changed |
| `vault.group.deleted` | Group soft-deleted                   |
