curl --request POST \
--url https://app.gc.ai/api/external/v1/vaults/{id}/members \
--header 'Authorization: <api-key>' \
--header 'Content-Type: application/json' \
--data '
{
"user_id": 1,
"email": "dana@example.com",
"role": "editor"
}
'import requests
url = "https://app.gc.ai/api/external/v1/vaults/{id}/members"
payload = {
"user_id": 1,
"email": "dana@example.com",
"role": "editor"
}
headers = {
"Authorization": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({user_id: 1, email: 'dana@example.com', role: 'editor'})
};
fetch('https://app.gc.ai/api/external/v1/vaults/{id}/members', 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://app.gc.ai/api/external/v1/vaults/{id}/members",
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([
'user_id' => 1,
'email' => 'dana@example.com',
'role' => 'editor'
]),
CURLOPT_HTTPHEADER => [
"Authorization: <api-key>",
"Content-Type: application/json"
],
]);
$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://app.gc.ai/api/external/v1/vaults/{id}/members"
payload := strings.NewReader("{\n \"user_id\": 1,\n \"email\": \"dana@example.com\",\n \"role\": \"editor\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "<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://app.gc.ai/api/external/v1/vaults/{id}/members")
.header("Authorization", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"user_id\": 1,\n \"email\": \"dana@example.com\",\n \"role\": \"editor\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.gc.ai/api/external/v1/vaults/{id}/members")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"user_id\": 1,\n \"email\": \"dana@example.com\",\n \"role\": \"editor\"\n}"
response = http.request(request)
puts response.read_body{
"user_id": 123,
"email": "<string>",
"name": "<string>",
"role": "owner",
"added_at": "<string>"
}{
"error": "<string>",
"code": "<string>",
"message": "<string>",
"details": {}
}{
"error": "<string>",
"code": "<string>",
"message": "<string>",
"details": {}
}{
"error": "<string>",
"code": "<string>",
"message": "<string>",
"details": {}
}{
"error": "<string>",
"code": "<string>",
"message": "<string>",
"details": {}
}{
"error": "<string>",
"code": "<string>",
"message": "<string>",
"details": {}
}{
"error": "<string>",
"code": "<string>",
"message": "<string>",
"details": {}
}{
"error": "<string>",
"code": "<string>",
"message": "<string>",
"details": {}
}{
"error": "<string>",
"code": "<string>",
"message": "<string>",
"details": {}
}{
"error": "<string>",
"code": "<string>",
"message": "<string>",
"details": {}
}Add a Member to a Vault
Give someone a role in a vault. Name them by user_id or by email, exactly one of the two.
The person has to be a member of your organization already. An address that belongs to nobody in the organization returns 400 and nothing is sent, so this endpoint can never invite anyone or add a seat.
Adding someone who already holds a role returns their existing row unchanged, current role included. That keeps a repeated call from quietly demoting an owner to editor. To change a role, use PATCH /vaults/{id}/members/{userId}.
Requires the owner role in the vault and the organization-level permission to manage vaults.
Requires a user-scoped API key (u:gcai_...). A vault is shared with named people, so an organization-scoped key has no identity to resolve vault access with.
curl --request POST \
--url https://app.gc.ai/api/external/v1/vaults/{id}/members \
--header 'Authorization: <api-key>' \
--header 'Content-Type: application/json' \
--data '
{
"user_id": 1,
"email": "dana@example.com",
"role": "editor"
}
'import requests
url = "https://app.gc.ai/api/external/v1/vaults/{id}/members"
payload = {
"user_id": 1,
"email": "dana@example.com",
"role": "editor"
}
headers = {
"Authorization": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({user_id: 1, email: 'dana@example.com', role: 'editor'})
};
fetch('https://app.gc.ai/api/external/v1/vaults/{id}/members', 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://app.gc.ai/api/external/v1/vaults/{id}/members",
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([
'user_id' => 1,
'email' => 'dana@example.com',
'role' => 'editor'
]),
CURLOPT_HTTPHEADER => [
"Authorization: <api-key>",
"Content-Type: application/json"
],
]);
$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://app.gc.ai/api/external/v1/vaults/{id}/members"
payload := strings.NewReader("{\n \"user_id\": 1,\n \"email\": \"dana@example.com\",\n \"role\": \"editor\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "<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://app.gc.ai/api/external/v1/vaults/{id}/members")
.header("Authorization", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"user_id\": 1,\n \"email\": \"dana@example.com\",\n \"role\": \"editor\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.gc.ai/api/external/v1/vaults/{id}/members")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"user_id\": 1,\n \"email\": \"dana@example.com\",\n \"role\": \"editor\"\n}"
response = http.request(request)
puts response.read_body{
"user_id": 123,
"email": "<string>",
"name": "<string>",
"role": "owner",
"added_at": "<string>"
}{
"error": "<string>",
"code": "<string>",
"message": "<string>",
"details": {}
}{
"error": "<string>",
"code": "<string>",
"message": "<string>",
"details": {}
}{
"error": "<string>",
"code": "<string>",
"message": "<string>",
"details": {}
}{
"error": "<string>",
"code": "<string>",
"message": "<string>",
"details": {}
}{
"error": "<string>",
"code": "<string>",
"message": "<string>",
"details": {}
}{
"error": "<string>",
"code": "<string>",
"message": "<string>",
"details": {}
}{
"error": "<string>",
"code": "<string>",
"message": "<string>",
"details": {}
}{
"error": "<string>",
"code": "<string>",
"message": "<string>",
"details": {}
}{
"error": "<string>",
"code": "<string>",
"message": "<string>",
"details": {}
}Authorizations
API key for authentication. Format: gcai_xxxxxxxxx
Create API keys in the GC AI app under Settings → API.
Path Parameters
The vault ID
Body
GC AI user ID of the person to add, as user_id from GET /vaults/{id}/members or id from GET /me. Send this or email.
x > 0Email address of the person to add. It has to belong to someone who is already a member of your organization. Send this or user_id.
320"dana@example.com"
Role to grant. Defaults to editor.
owner, editor, viewer Response
The vault member
GC AI user ID of the member. This is the same identifier GET /me reports for the calling user, so a caller can pick their own row out of the list.
Member email address, or null when the account has none on file.
Member display name, preferring the name they chose for themselves. Null when the account has no name on file.
The member's role in this vault: owner (manage members and settings), editor (add documents and edit extracted data), or viewer (read and annotate). Null on the rare stored value GC AI cannot read as a role. Such a grant carries no permissions at all, so remove it and add the person again.
owner, editor, viewer, null ISO 8601 timestamp when the member was added, or null for grants written before GC AI recorded that.
Was this page helpful?