cURL
curl --request POST \
--url https://api.nekt.ai/api/v1/permissions/ \
--header 'Content-Type: application/json' \
--header 'x-api-key: <api-key>' \
--data '
{
"assignments": [
{
"users": [],
"groups": [],
"layers": [],
"folders": [],
"tables": [],
"volumes": []
}
],
"notify_members": false,
"message": "<string>"
}
'import requests
url = "https://api.nekt.ai/api/v1/permissions/"
payload = {
"assignments": [
{
"users": [],
"groups": [],
"layers": [],
"folders": [],
"tables": [],
"volumes": []
}
],
"notify_members": False,
"message": "<string>"
}
headers = {
"x-api-key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'x-api-key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
assignments: [{users: [], groups: [], layers: [], folders: [], tables: [], volumes: []}],
notify_members: false,
message: '<string>'
})
};
fetch('https://api.nekt.ai/api/v1/permissions/', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.nekt.ai/api/v1/permissions/",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'assignments' => [
[
'users' => [
],
'groups' => [
],
'layers' => [
],
'folders' => [
],
'tables' => [
],
'volumes' => [
]
]
],
'notify_members' => false,
'message' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"x-api-key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.nekt.ai/api/v1/permissions/"
payload := strings.NewReader("{\n \"assignments\": [\n {\n \"users\": [],\n \"groups\": [],\n \"layers\": [],\n \"folders\": [],\n \"tables\": [],\n \"volumes\": []\n }\n ],\n \"notify_members\": false,\n \"message\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-api-key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.nekt.ai/api/v1/permissions/")
.header("x-api-key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"assignments\": [\n {\n \"users\": [],\n \"groups\": [],\n \"layers\": [],\n \"folders\": [],\n \"tables\": [],\n \"volumes\": []\n }\n ],\n \"notify_members\": false,\n \"message\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.nekt.ai/api/v1/permissions/")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"assignments\": [\n {\n \"users\": [],\n \"groups\": [],\n \"layers\": [],\n \"folders\": [],\n \"tables\": [],\n \"volumes\": []\n }\n ],\n \"notify_members\": false,\n \"message\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"created": [
{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"permission_level": "manager",
"created_at": "2023-11-07T05:31:56Z",
"updated_at": "2023-11-07T05:31:56Z",
"user": "<string>",
"group": "<string>",
"layer": "<string>",
"folder": "<string>",
"table": "<string>",
"volume": "<string>",
"granted_by": "<string>"
}
],
"updated": [
{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"permission_level": "manager",
"created_at": "2023-11-07T05:31:56Z",
"updated_at": "2023-11-07T05:31:56Z",
"user": "<string>",
"group": "<string>",
"layer": "<string>",
"folder": "<string>",
"table": "<string>",
"volume": "<string>",
"granted_by": "<string>"
}
],
"revoked": [
{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"permission_level": "manager",
"created_at": "2023-11-07T05:31:56Z",
"updated_at": "2023-11-07T05:31:56Z",
"user": "<string>",
"group": "<string>",
"layer": "<string>",
"folder": "<string>",
"table": "<string>",
"volume": "<string>",
"granted_by": "<string>"
}
]
}Catalog
Assign Permissions
Grant, change, and revoke Catalog access for users and groups in a single call.
POST
/
api
/
v1
/
permissions
/
cURL
curl --request POST \
--url https://api.nekt.ai/api/v1/permissions/ \
--header 'Content-Type: application/json' \
--header 'x-api-key: <api-key>' \
--data '
{
"assignments": [
{
"users": [],
"groups": [],
"layers": [],
"folders": [],
"tables": [],
"volumes": []
}
],
"notify_members": false,
"message": "<string>"
}
'import requests
url = "https://api.nekt.ai/api/v1/permissions/"
payload = {
"assignments": [
{
"users": [],
"groups": [],
"layers": [],
"folders": [],
"tables": [],
"volumes": []
}
],
"notify_members": False,
"message": "<string>"
}
headers = {
"x-api-key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'x-api-key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
assignments: [{users: [], groups: [], layers: [], folders: [], tables: [], volumes: []}],
notify_members: false,
message: '<string>'
})
};
fetch('https://api.nekt.ai/api/v1/permissions/', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.nekt.ai/api/v1/permissions/",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'assignments' => [
[
'users' => [
],
'groups' => [
],
'layers' => [
],
'folders' => [
],
'tables' => [
],
'volumes' => [
]
]
],
'notify_members' => false,
'message' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"x-api-key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.nekt.ai/api/v1/permissions/"
payload := strings.NewReader("{\n \"assignments\": [\n {\n \"users\": [],\n \"groups\": [],\n \"layers\": [],\n \"folders\": [],\n \"tables\": [],\n \"volumes\": []\n }\n ],\n \"notify_members\": false,\n \"message\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-api-key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.nekt.ai/api/v1/permissions/")
.header("x-api-key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"assignments\": [\n {\n \"users\": [],\n \"groups\": [],\n \"layers\": [],\n \"folders\": [],\n \"tables\": [],\n \"volumes\": []\n }\n ],\n \"notify_members\": false,\n \"message\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.nekt.ai/api/v1/permissions/")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"assignments\": [\n {\n \"users\": [],\n \"groups\": [],\n \"layers\": [],\n \"folders\": [],\n \"tables\": [],\n \"volumes\": []\n }\n ],\n \"notify_members\": false,\n \"message\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"created": [
{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"permission_level": "manager",
"created_at": "2023-11-07T05:31:56Z",
"updated_at": "2023-11-07T05:31:56Z",
"user": "<string>",
"group": "<string>",
"layer": "<string>",
"folder": "<string>",
"table": "<string>",
"volume": "<string>",
"granted_by": "<string>"
}
],
"updated": [
{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"permission_level": "manager",
"created_at": "2023-11-07T05:31:56Z",
"updated_at": "2023-11-07T05:31:56Z",
"user": "<string>",
"group": "<string>",
"layer": "<string>",
"folder": "<string>",
"table": "<string>",
"volume": "<string>",
"granted_by": "<string>"
}
],
"revoked": [
{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"permission_level": "manager",
"created_at": "2023-11-07T05:31:56Z",
"updated_at": "2023-11-07T05:31:56Z",
"user": "<string>",
"group": "<string>",
"layer": "<string>",
"folder": "<string>",
"table": "<string>",
"volume": "<string>",
"granted_by": "<string>"
}
]
}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
Each object in
Recipient ids come from List Permission Recipients. Resource ids come from List Layers, the folders, tables, and volumes endpoints.
Each list holds full permission objects. A pair that already had the level you asked for appears in none of them — the call is idempotent.
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. |
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. |
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.Response
{
"created": [ { "id": "…", "permission_level": "viewer", "user": "…", "table": "…" } ],
"updated": [],
"revoked": []
}
Grant one level on one table
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.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.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"]
}
]
}'
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.Python: mirror a group’s access onto a new member
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. |
Related
- Permissions flow — the end-to-end walkthrough, ceiling rules, and error semantics.
- List Permission Recipients — where recipient ids come from.
- Assign Object Permissions — the same shape for secrets and live connections.
Authorizations
API Key authentication. Format: 'x-api-key: api_key'
Body
application/jsonapplication/x-www-form-urlencodedmultipart/form-data
Was this page helpful?