cURL
curl --request POST \
--url https://api.nekt.ai/api/v1/invitations/bulk-invite/ \
--header 'Content-Type: application/json' \
--header 'x-api-key: <api-key>' \
--data '
{
"invitations": [
{
"email": "jsmith@example.com",
"first_name": "<string>",
"last_name": "<string>",
"role": "member",
"other_functional_area": "<string>"
}
]
}
'import requests
url = "https://api.nekt.ai/api/v1/invitations/bulk-invite/"
payload = { "invitations": [
{
"email": "jsmith@example.com",
"first_name": "<string>",
"last_name": "<string>",
"role": "member",
"other_functional_area": "<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({
invitations: [
{
email: 'jsmith@example.com',
first_name: '<string>',
last_name: '<string>',
role: 'member',
other_functional_area: '<string>'
}
]
})
};
fetch('https://api.nekt.ai/api/v1/invitations/bulk-invite/', 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/invitations/bulk-invite/",
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([
'invitations' => [
[
'email' => 'jsmith@example.com',
'first_name' => '<string>',
'last_name' => '<string>',
'role' => 'member',
'other_functional_area' => '<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/invitations/bulk-invite/"
payload := strings.NewReader("{\n \"invitations\": [\n {\n \"email\": \"jsmith@example.com\",\n \"first_name\": \"<string>\",\n \"last_name\": \"<string>\",\n \"role\": \"member\",\n \"other_functional_area\": \"<string>\"\n }\n ]\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/invitations/bulk-invite/")
.header("x-api-key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"invitations\": [\n {\n \"email\": \"jsmith@example.com\",\n \"first_name\": \"<string>\",\n \"last_name\": \"<string>\",\n \"role\": \"member\",\n \"other_functional_area\": \"<string>\"\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.nekt.ai/api/v1/invitations/bulk-invite/")
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 \"invitations\": [\n {\n \"email\": \"jsmith@example.com\",\n \"first_name\": \"<string>\",\n \"last_name\": \"<string>\",\n \"role\": \"member\",\n \"other_functional_area\": \"<string>\"\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"message": "<string>",
"invited": [
"jsmith@example.com"
],
"resent": [
"jsmith@example.com"
]
}Invitations
Bulk Invite Users
Invite several people to your organization in one request.
POST
/
api
/
v1
/
invitations
/
bulk-invite
/
cURL
curl --request POST \
--url https://api.nekt.ai/api/v1/invitations/bulk-invite/ \
--header 'Content-Type: application/json' \
--header 'x-api-key: <api-key>' \
--data '
{
"invitations": [
{
"email": "jsmith@example.com",
"first_name": "<string>",
"last_name": "<string>",
"role": "member",
"other_functional_area": "<string>"
}
]
}
'import requests
url = "https://api.nekt.ai/api/v1/invitations/bulk-invite/"
payload = { "invitations": [
{
"email": "jsmith@example.com",
"first_name": "<string>",
"last_name": "<string>",
"role": "member",
"other_functional_area": "<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({
invitations: [
{
email: 'jsmith@example.com',
first_name: '<string>',
last_name: '<string>',
role: 'member',
other_functional_area: '<string>'
}
]
})
};
fetch('https://api.nekt.ai/api/v1/invitations/bulk-invite/', 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/invitations/bulk-invite/",
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([
'invitations' => [
[
'email' => 'jsmith@example.com',
'first_name' => '<string>',
'last_name' => '<string>',
'role' => 'member',
'other_functional_area' => '<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/invitations/bulk-invite/"
payload := strings.NewReader("{\n \"invitations\": [\n {\n \"email\": \"jsmith@example.com\",\n \"first_name\": \"<string>\",\n \"last_name\": \"<string>\",\n \"role\": \"member\",\n \"other_functional_area\": \"<string>\"\n }\n ]\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/invitations/bulk-invite/")
.header("x-api-key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"invitations\": [\n {\n \"email\": \"jsmith@example.com\",\n \"first_name\": \"<string>\",\n \"last_name\": \"<string>\",\n \"role\": \"member\",\n \"other_functional_area\": \"<string>\"\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.nekt.ai/api/v1/invitations/bulk-invite/")
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 \"invitations\": [\n {\n \"email\": \"jsmith@example.com\",\n \"first_name\": \"<string>\",\n \"last_name\": \"<string>\",\n \"role\": \"member\",\n \"other_functional_area\": \"<string>\"\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"message": "<string>",
"invited": [
"jsmith@example.com"
],
"resent": [
"jsmith@example.com"
]
}Invites a list of people in one call. Every entry behaves exactly like a single Invite User request: an address with no outstanding invitation is invited, and one that already has an invitation gets it resent — with a role change if the role differs. This is the common integration case for onboarding a team from a list.
Each entry in
All-or-nothing. One bad entry undoes the whole batch: nothing is written and nobody is emailed. Applying some entries and reporting the rest would make a retry ambiguous, and re-sending the batch would mail everyone who already succeeded a second time.
Request body
| Parameter | Type | Required | Description |
|---|---|---|---|
invitations | array | Yes | The people to invite. Each entry has the same shape as a single invite. |
invitations accepts:
| Field | Type | Required | Description |
|---|---|---|---|
email | string | Yes | The address to invite. Normalized before storing, so casing never creates a duplicate. |
role | string | No | One of owner, admin, or member. Defaults to member. |
first_name | string | No | Shown in the member list before the person accepts. |
last_name | string | No | Shown in the member list before the person accepts. |
functional_area | string | No | The invitee’s functional area. |
other_functional_area | string | No | Free-text functional area, when none of the predefined options fit. |
Each entry behaves exactly like a single Invite User request, so the same fields and validation rules apply.
Response
Returns200 OK with a summary of what the batch did, split by what happened to each address.
{
"message": "Successfully invited 2 user(s).",
"invited": ["analyst@example.com", "lead@example.com"],
"resent": []
}
| Field | Description |
|---|---|
message | Human-readable summary of what the bulk invite did. |
invited | Addresses that had no outstanding invitation and now do. |
resent | Addresses whose outstanding invitation was resent. |
invited and resent together always account for every entry you sent.
Example
curl --request POST \
--url https://api.nekt.ai/api/v1/invitations/bulk-invite/ \
--header "x-api-key: YOUR_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"invitations": [
{"email": "analyst@example.com"},
{"email": "scientist@example.com"},
{"email": "lead@example.com", "role": "admin"}
]
}'
Python example: onboard a team from a list
import os
import requests
BASE_URL = "https://api.nekt.ai"
headers = {
"x-api-key": os.environ["NEKT_API_KEY"],
"Content-Type": "application/json",
}
emails = ["analyst@example.com", "scientist@example.com", "lead@example.com"]
response = requests.post(
f"{BASE_URL}/api/v1/invitations/bulk-invite/",
headers=headers,
# `role` omitted, so everyone comes in as a member.
json={"invitations": [{"email": email} for email in emails]},
)
response.raise_for_status()
body = response.json()
print(f"invited: {body['invited']}")
print(f"resent: {body['resent']}")
Resending
Sending the same batch again is safe and is how you chase people who have not accepted. Nobody is duplicated: addresses that already have an invitation come back underresent with a fresh expiry, and their existing groups and grants are untouched.
{
"message": "Successfully invited 1 user(s) and resent 2 invitation(s).",
"invited": ["newcomer@example.com"],
"resent": ["analyst@example.com", "scientist@example.com"]
}
If an entry names a different role than the outstanding invitation has, the resend moves the person to it — on both the invitation and their pending membership. Moving an existing
admin or owner requires an owner.Authentication
This endpoint requires an API key in thex-api-key header.
Only an owner or an admin can invite, and nobody can invite somebody to a role above their own. For an API key, that ceiling is read from the role of the user who created the key.
Errors
Every one of these rejects the whole batch.| Status | When |
|---|---|
400 | An address already belongs to an active member of the organization. |
400 | The same address appears twice in one payload. |
400 | invitations is empty or missing, or an entry has no email. |
403 | The caller is a member, or an entry names a role above the caller’s own. |
Because one bad entry rejects everything, a long list built from an external source is worth filtering first — drop addresses that are already members, and de-duplicate. A rejected batch tells you what was wrong, but it writes nothing.
Related
- Invite User — invite or resend for a single person.
- Invitation object — the shape of each entry.
Authorizations
API Key authentication. Format: 'x-api-key: api_key'
Body
application/jsonapplication/x-www-form-urlencodedmultipart/form-data
The people to invite.
Show child attributes
Show child attributes
Response
200 - application/json
What a bulk invite did, split by what happened to each address.
Was this page helpful?