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

# Assign Permissions

> Grant, change, and revoke Catalog access for users and groups in a single call.

This endpoint is not a plain create. It is a **declarative bulk upsert**: you describe the access you want, and Nekt works out which grants to create, which to change, and which to remove.

Each entry in `assignments` is a **cross product**. Every recipient in `users` and `groups` is paired with every resource in `layers`, `folders`, `tables`, and `volumes`, and each resulting pair gets `permission_level`. Two users and three tables in one assignment is six grants.

## Request body

| Parameter        | Type             | Required | Description                                       |
| ---------------- | ---------------- | -------- | ------------------------------------------------- |
| `assignments`    | array of objects | Yes      | One or more assignment blocks. Must not be empty. |
| `notify_members` | boolean          | No       | Accepted for compatibility. See the note below.   |
| `message`        | string           | No       | Accepted for compatibility. See the note below.   |

Each object in `assignments`:

| Parameter          | Type                                     | Required | Description                                                             |
| ------------------ | ---------------------------------------- | -------- | ----------------------------------------------------------------------- |
| `permission_level` | `viewer`, `editor`, `manager`, or `null` | Yes      | The level to apply. **`null` revokes** any existing grant for the pair. |
| `users`            | array of UUIDs                           | No       | Recipient users. Must be active members of your workspace.              |
| `groups`           | array of UUIDs                           | No       | Recipient permission groups.                                            |
| `layers`           | array of UUIDs                           | No       | Target layers.                                                          |
| `folders`          | array of UUIDs                           | No       | Target folders.                                                         |
| `tables`           | array of UUIDs                           | No       | Target tables.                                                          |
| `volumes`          | array of UUIDs                           | No       | Target volumes.                                                         |

Recipient ids come from [List Permission Recipients](/platform-api/permissions/catalog/recipients). Resource ids come from [List Layers](/platform-api/catalog/list-layers), the folders, tables, and volumes endpoints.

<Note>
  `notify_members` and `message` are accepted by this endpoint but **do not send email**. They are carried over from an earlier version of the API. Grants take effect regardless; recipients are simply not notified.
</Note>

## Response

```json theme={null}
{
  "created": [ { "id": "…", "permission_level": "viewer", "user": "…", "table": "…" } ],
  "updated": [],
  "revoked": []
}
```

Each list holds full [permission objects](/platform-api/permissions/catalog/permission). A pair that already had the level you asked for appears in none of them — the call is idempotent.

## Grant one level on one table

```bash theme={null}
curl --request POST \
  --url https://api.nekt.ai/api/v1/permissions/ \
  --header "x-api-key: YOUR_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
    "assignments": [
      {
        "permission_level": "viewer",
        "users": ["3f7c1e88-9a41-4b2d-8e5f-6c0a2d4b9e11"],
        "tables": ["a7b4f0d2-5c91-4e34-9c1f-7e3a5f1c9d02"]
      }
    ]
  }'
```

## Onboard a group across a whole layer

Granting on a layer covers the folders, tables, and volumes inside it. You do not need to enumerate them.

```bash theme={null}
curl --request POST \
  --url https://api.nekt.ai/api/v1/permissions/ \
  --header "x-api-key: YOUR_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
    "assignments": [
      {
        "permission_level": "editor",
        "groups": ["b8c5e1e3-6d02-4f45-ad20-8f4b6e2d0e13"],
        "layers": ["e4d5c6b7-a8b9-40c1-d2e3-f4a5b6c7d8e9"]
      }
    ]
  }'
```

## Grant and revoke in one request

Different levels need separate assignment blocks. This is how you move someone up on one resource and off another atomically.

```bash theme={null}
curl --request POST \
  --url https://api.nekt.ai/api/v1/permissions/ \
  --header "x-api-key: YOUR_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
    "assignments": [
      {
        "permission_level": "editor",
        "users": ["3f7c1e88-9a41-4b2d-8e5f-6c0a2d4b9e11"],
        "tables": ["a7b4f0d2-5c91-4e34-9c1f-7e3a5f1c9d02"]
      },
      {
        "permission_level": null,
        "users": ["3f7c1e88-9a41-4b2d-8e5f-6c0a2d4b9e11"],
        "tables": ["f3e4d5c6-b7a8-49e0-1f2a-3b4c5d6e7f80"]
      }
    ]
  }'
```

<Warning>
  Two assignments that target the same recipient and the same resource with **different** levels are rejected with `400` naming the conflicting positions. Repeating the same pair at the same level is fine and simply ignored.
</Warning>

## Python: mirror a group's access onto a new member

```python theme={null}
import requests

API_KEY = "YOUR_API_KEY"
BASE_URL = "https://api.nekt.ai"
NEW_USER = "3f7c1e88-9a41-4b2d-8e5f-6c0a2d4b9e11"
REFERENCE_GROUP = "b8c5e1e3-6d02-4f45-ad20-8f4b6e2d0e13"

headers = {"x-api-key": API_KEY, "Content-Type": "application/json"}

grants = requests.get(
    f"{BASE_URL}/api/v1/permissions/",
    headers=headers,
    params={"group": REFERENCE_GROUP},
).json()["results"]

# One assignment block per level, so each block carries a single permission_level.
by_level = {}
for grant in grants:
    block = by_level.setdefault(grant["permission_level"], {"layers": [], "folders": [], "tables": [], "volumes": []})
    for resource in ("layer", "folder", "table", "volume"):
        if grant[resource]:
            block[f"{resource}s"].append(grant[resource])

requests.post(
    f"{BASE_URL}/api/v1/permissions/",
    headers=headers,
    json={
        "assignments": [
            {"permission_level": level, "users": [NEW_USER], **resources}
            for level, resources in by_level.items()
        ],
    },
)
```

## Errors

| Status | When                                                                                                                                                  |
| ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| `400`  | Two assignments conflict on the same recipient and resource, or a referenced id is not visible to your API key.                                       |
| `403`  | Your workspace is not on Growth or Custom, or the key's ceiling does not allow the grant. See [Permissions flow](/platform-api/permissions/overview). |

## Related

* [Permissions flow](/platform-api/permissions/overview) — the end-to-end walkthrough, ceiling rules, and error semantics.
* [List Permission Recipients](/platform-api/permissions/catalog/recipients) — where recipient ids come from.
* [Assign Object Permissions](/platform-api/permissions/objects/assign) — the same shape for secrets and live connections.


## OpenAPI

````yaml POST /api/v1/permissions/
openapi: 3.0.3
info:
  title: Nekt API
  version: v1
  description: Nekt API Documentation
  contact:
    email: support@nekt.ai
servers:
  - url: https://api.nekt.ai
security: []
paths:
  /api/v1/permissions/:
    post:
      tags:
        - v1
      operationId: v1_permissions_create
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AssignLakehousePermission'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/AssignLakehousePermission'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/AssignLakehousePermission'
        required: true
      responses:
        '201':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AssignLakehousePermission'
          description: ''
      security:
        - ApiKeyAuth: []
components:
  schemas:
    AssignLakehousePermission:
      type: object
      properties:
        assignments:
          type: array
          items:
            $ref: '#/components/schemas/PermissionAssignment'
          writeOnly: true
        notify_members:
          type: boolean
          writeOnly: true
          default: false
        message:
          type: string
          writeOnly: true
        created:
          type: array
          items:
            $ref: '#/components/schemas/LakehousePermission'
          readOnly: true
        updated:
          type: array
          items:
            $ref: '#/components/schemas/LakehousePermission'
          readOnly: true
        revoked:
          type: array
          items:
            $ref: '#/components/schemas/LakehousePermission'
          readOnly: true
      required:
        - assignments
        - created
        - revoked
        - updated
    PermissionAssignment:
      type: object
      properties:
        users:
          type: array
          items:
            type: integer
          default: []
        groups:
          type: array
          items:
            type: string
            format: uuid
          default: []
        permission_level:
          nullable: true
          oneOf:
            - $ref: '#/components/schemas/PermissionLevelEnum'
            - $ref: '#/components/schemas/NullEnum'
        layers:
          type: array
          items:
            type: string
            format: uuid
          default: []
        folders:
          type: array
          items:
            type: string
            format: uuid
          default: []
        tables:
          type: array
          items:
            type: string
            format: uuid
          default: []
        volumes:
          type: array
          items:
            type: string
            format: uuid
          default: []
      required:
        - permission_level
    LakehousePermission:
      type: object
      properties:
        id:
          type: string
          format: uuid
          readOnly: true
        permission_level:
          $ref: '#/components/schemas/PermissionLevelEnum'
        created_at:
          type: string
          format: date-time
          readOnly: true
        updated_at:
          type: string
          format: date-time
          readOnly: true
        user:
          type: string
          readOnly: true
          description: User (Expandable)
        group:
          type: string
          readOnly: true
          description: Group (Expandable)
        layer:
          type: string
          readOnly: true
          description: Layer (Expandable)
        folder:
          type: string
          readOnly: true
          description: Folder (Expandable)
        table:
          type: string
          readOnly: true
          description: Table (Expandable)
        volume:
          type: string
          readOnly: true
          description: Volume (Expandable)
        granted_by:
          type: string
          readOnly: true
          description: Granted by (Expandable)
      required:
        - created_at
        - folder
        - granted_by
        - group
        - id
        - layer
        - permission_level
        - table
        - updated_at
        - user
        - volume
    PermissionLevelEnum:
      enum:
        - manager
        - editor
        - viewer
      type: string
      description: |-
        * `manager` - Manager
        * `editor` - Editor
        * `viewer` - Viewer
    NullEnum:
      enum:
        - null
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: x-api-key
      description: 'API Key authentication. Format: ''x-api-key: api_key'''

````