curl --request POST \
--url https://prod.skillsdbnext.com/api/v1/bulk/people \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"people": [
{
"email": "ada@example.com",
"firstName": "Ada",
"lastName": "Lovelace",
"externalId": "E-10422",
"managerEmail": "manager@example.com",
"isActive": true,
"accessLevel": "basic"
}
]
}
'import requests
url = "https://prod.skillsdbnext.com/api/v1/bulk/people"
payload = { "people": [
{
"email": "ada@example.com",
"firstName": "Ada",
"lastName": "Lovelace",
"externalId": "E-10422",
"managerEmail": "manager@example.com",
"isActive": True,
"accessLevel": "basic"
}
] }
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
people: [
{
email: 'ada@example.com',
firstName: 'Ada',
lastName: 'Lovelace',
externalId: 'E-10422',
managerEmail: 'manager@example.com',
isActive: true,
accessLevel: 'basic'
}
]
})
};
fetch('https://prod.skillsdbnext.com/api/v1/bulk/people', 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://prod.skillsdbnext.com/api/v1/bulk/people",
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([
'people' => [
[
'email' => 'ada@example.com',
'firstName' => 'Ada',
'lastName' => 'Lovelace',
'externalId' => 'E-10422',
'managerEmail' => 'manager@example.com',
'isActive' => true,
'accessLevel' => 'basic'
]
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"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://prod.skillsdbnext.com/api/v1/bulk/people"
payload := strings.NewReader("{\n \"people\": [\n {\n \"email\": \"ada@example.com\",\n \"firstName\": \"Ada\",\n \"lastName\": \"Lovelace\",\n \"externalId\": \"E-10422\",\n \"managerEmail\": \"manager@example.com\",\n \"isActive\": true,\n \"accessLevel\": \"basic\"\n }\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
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://prod.skillsdbnext.com/api/v1/bulk/people")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"people\": [\n {\n \"email\": \"ada@example.com\",\n \"firstName\": \"Ada\",\n \"lastName\": \"Lovelace\",\n \"externalId\": \"E-10422\",\n \"managerEmail\": \"manager@example.com\",\n \"isActive\": true,\n \"accessLevel\": \"basic\"\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://prod.skillsdbnext.com/api/v1/bulk/people")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"people\": [\n {\n \"email\": \"ada@example.com\",\n \"firstName\": \"Ada\",\n \"lastName\": \"Lovelace\",\n \"externalId\": \"E-10422\",\n \"managerEmail\": \"manager@example.com\",\n \"isActive\": true,\n \"accessLevel\": \"basic\"\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"data": {
"results": [
{
"index": 0,
"email": "ada@example.com",
"status": "created",
"id": "4821",
"error": null
}
],
"summary": {
"total": 100,
"created": 12,
"updated": 85,
"deactivated": 2,
"failed": 1
}
}
}{
"type": "https://help.skillsdb.com/api-docs/errors/validation-error",
"title": "Validation failed",
"status": 400,
"detail": "limit must be between 1 and 200",
"instance": "/api/v1/people",
"requestId": "0192c2f1-6f4e-7ab3-b1c4-5f6a7b8c9d0e",
"errors": [
{
"field": "email",
"code": "max_length",
"message": "email must be shorter than or equal to 75 characters"
}
],
"error": "trial_expired",
"upgrade_url": "https://app.skillsdb.com/settings/billing"
}{
"type": "https://help.skillsdb.com/api-docs/errors/validation-error",
"title": "Validation failed",
"status": 400,
"detail": "limit must be between 1 and 200",
"instance": "/api/v1/people",
"requestId": "0192c2f1-6f4e-7ab3-b1c4-5f6a7b8c9d0e",
"errors": [
{
"field": "email",
"code": "max_length",
"message": "email must be shorter than or equal to 75 characters"
}
],
"error": "trial_expired",
"upgrade_url": "https://app.skillsdb.com/settings/billing"
}{
"type": "https://help.skillsdb.com/api-docs/errors/validation-error",
"title": "Validation failed",
"status": 400,
"detail": "limit must be between 1 and 200",
"instance": "/api/v1/people",
"requestId": "0192c2f1-6f4e-7ab3-b1c4-5f6a7b8c9d0e",
"errors": [
{
"field": "email",
"code": "max_length",
"message": "email must be shorter than or equal to 75 characters"
}
],
"error": "trial_expired",
"upgrade_url": "https://app.skillsdb.com/settings/billing"
}{
"type": "https://help.skillsdb.com/api-docs/errors/validation-error",
"title": "Validation failed",
"status": 400,
"detail": "limit must be between 1 and 200",
"instance": "/api/v1/people",
"requestId": "0192c2f1-6f4e-7ab3-b1c4-5f6a7b8c9d0e",
"errors": [
{
"field": "email",
"code": "max_length",
"message": "email must be shorter than or equal to 75 characters"
}
],
"error": "trial_expired",
"upgrade_url": "https://app.skillsdb.com/settings/billing"
}{
"type": "https://help.skillsdb.com/api-docs/errors/validation-error",
"title": "Validation failed",
"status": 400,
"detail": "limit must be between 1 and 200",
"instance": "/api/v1/people",
"requestId": "0192c2f1-6f4e-7ab3-b1c4-5f6a7b8c9d0e",
"errors": [
{
"field": "email",
"code": "max_length",
"message": "email must be shorter than or equal to 75 characters"
}
],
"error": "trial_expired",
"upgrade_url": "https://app.skillsdb.com/settings/billing"
}{
"type": "https://help.skillsdb.com/api-docs/errors/validation-error",
"title": "Validation failed",
"status": 400,
"detail": "limit must be between 1 and 200",
"instance": "/api/v1/people",
"requestId": "0192c2f1-6f4e-7ab3-b1c4-5f6a7b8c9d0e",
"errors": [
{
"field": "email",
"code": "max_length",
"message": "email must be shorter than or equal to 75 characters"
}
],
"error": "trial_expired",
"upgrade_url": "https://app.skillsdb.com/settings/billing"
}{
"type": "https://help.skillsdb.com/api-docs/errors/validation-error",
"title": "Validation failed",
"status": 400,
"detail": "limit must be between 1 and 200",
"instance": "/api/v1/people",
"requestId": "0192c2f1-6f4e-7ab3-b1c4-5f6a7b8c9d0e",
"errors": [
{
"field": "email",
"code": "max_length",
"message": "email must be shorter than or equal to 75 characters"
}
],
"error": "trial_expired",
"upgrade_url": "https://app.skillsdb.com/settings/billing"
}Sync a batch of people
Create-or-update up to 500 people in one call, matched by email within your company. Set isActive: false to deactivate — a soft delete that retains the person and their history. The batch returns 200 whenever it was processed: read each record’s status and the summary, not the HTTP code, to see what happened. One bad record never fails the rest of the batch. Counts against the bulk rate-limit bucket, which is far lower than the read allowance. Send an Idempotency-Key — a retried sync replays the original response instead of double-creating.
Requires scope: people:write.
curl --request POST \
--url https://prod.skillsdbnext.com/api/v1/bulk/people \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"people": [
{
"email": "ada@example.com",
"firstName": "Ada",
"lastName": "Lovelace",
"externalId": "E-10422",
"managerEmail": "manager@example.com",
"isActive": true,
"accessLevel": "basic"
}
]
}
'import requests
url = "https://prod.skillsdbnext.com/api/v1/bulk/people"
payload = { "people": [
{
"email": "ada@example.com",
"firstName": "Ada",
"lastName": "Lovelace",
"externalId": "E-10422",
"managerEmail": "manager@example.com",
"isActive": True,
"accessLevel": "basic"
}
] }
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
people: [
{
email: 'ada@example.com',
firstName: 'Ada',
lastName: 'Lovelace',
externalId: 'E-10422',
managerEmail: 'manager@example.com',
isActive: true,
accessLevel: 'basic'
}
]
})
};
fetch('https://prod.skillsdbnext.com/api/v1/bulk/people', 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://prod.skillsdbnext.com/api/v1/bulk/people",
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([
'people' => [
[
'email' => 'ada@example.com',
'firstName' => 'Ada',
'lastName' => 'Lovelace',
'externalId' => 'E-10422',
'managerEmail' => 'manager@example.com',
'isActive' => true,
'accessLevel' => 'basic'
]
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"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://prod.skillsdbnext.com/api/v1/bulk/people"
payload := strings.NewReader("{\n \"people\": [\n {\n \"email\": \"ada@example.com\",\n \"firstName\": \"Ada\",\n \"lastName\": \"Lovelace\",\n \"externalId\": \"E-10422\",\n \"managerEmail\": \"manager@example.com\",\n \"isActive\": true,\n \"accessLevel\": \"basic\"\n }\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
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://prod.skillsdbnext.com/api/v1/bulk/people")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"people\": [\n {\n \"email\": \"ada@example.com\",\n \"firstName\": \"Ada\",\n \"lastName\": \"Lovelace\",\n \"externalId\": \"E-10422\",\n \"managerEmail\": \"manager@example.com\",\n \"isActive\": true,\n \"accessLevel\": \"basic\"\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://prod.skillsdbnext.com/api/v1/bulk/people")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"people\": [\n {\n \"email\": \"ada@example.com\",\n \"firstName\": \"Ada\",\n \"lastName\": \"Lovelace\",\n \"externalId\": \"E-10422\",\n \"managerEmail\": \"manager@example.com\",\n \"isActive\": true,\n \"accessLevel\": \"basic\"\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"data": {
"results": [
{
"index": 0,
"email": "ada@example.com",
"status": "created",
"id": "4821",
"error": null
}
],
"summary": {
"total": 100,
"created": 12,
"updated": 85,
"deactivated": 2,
"failed": 1
}
}
}{
"type": "https://help.skillsdb.com/api-docs/errors/validation-error",
"title": "Validation failed",
"status": 400,
"detail": "limit must be between 1 and 200",
"instance": "/api/v1/people",
"requestId": "0192c2f1-6f4e-7ab3-b1c4-5f6a7b8c9d0e",
"errors": [
{
"field": "email",
"code": "max_length",
"message": "email must be shorter than or equal to 75 characters"
}
],
"error": "trial_expired",
"upgrade_url": "https://app.skillsdb.com/settings/billing"
}{
"type": "https://help.skillsdb.com/api-docs/errors/validation-error",
"title": "Validation failed",
"status": 400,
"detail": "limit must be between 1 and 200",
"instance": "/api/v1/people",
"requestId": "0192c2f1-6f4e-7ab3-b1c4-5f6a7b8c9d0e",
"errors": [
{
"field": "email",
"code": "max_length",
"message": "email must be shorter than or equal to 75 characters"
}
],
"error": "trial_expired",
"upgrade_url": "https://app.skillsdb.com/settings/billing"
}{
"type": "https://help.skillsdb.com/api-docs/errors/validation-error",
"title": "Validation failed",
"status": 400,
"detail": "limit must be between 1 and 200",
"instance": "/api/v1/people",
"requestId": "0192c2f1-6f4e-7ab3-b1c4-5f6a7b8c9d0e",
"errors": [
{
"field": "email",
"code": "max_length",
"message": "email must be shorter than or equal to 75 characters"
}
],
"error": "trial_expired",
"upgrade_url": "https://app.skillsdb.com/settings/billing"
}{
"type": "https://help.skillsdb.com/api-docs/errors/validation-error",
"title": "Validation failed",
"status": 400,
"detail": "limit must be between 1 and 200",
"instance": "/api/v1/people",
"requestId": "0192c2f1-6f4e-7ab3-b1c4-5f6a7b8c9d0e",
"errors": [
{
"field": "email",
"code": "max_length",
"message": "email must be shorter than or equal to 75 characters"
}
],
"error": "trial_expired",
"upgrade_url": "https://app.skillsdb.com/settings/billing"
}{
"type": "https://help.skillsdb.com/api-docs/errors/validation-error",
"title": "Validation failed",
"status": 400,
"detail": "limit must be between 1 and 200",
"instance": "/api/v1/people",
"requestId": "0192c2f1-6f4e-7ab3-b1c4-5f6a7b8c9d0e",
"errors": [
{
"field": "email",
"code": "max_length",
"message": "email must be shorter than or equal to 75 characters"
}
],
"error": "trial_expired",
"upgrade_url": "https://app.skillsdb.com/settings/billing"
}{
"type": "https://help.skillsdb.com/api-docs/errors/validation-error",
"title": "Validation failed",
"status": 400,
"detail": "limit must be between 1 and 200",
"instance": "/api/v1/people",
"requestId": "0192c2f1-6f4e-7ab3-b1c4-5f6a7b8c9d0e",
"errors": [
{
"field": "email",
"code": "max_length",
"message": "email must be shorter than or equal to 75 characters"
}
],
"error": "trial_expired",
"upgrade_url": "https://app.skillsdb.com/settings/billing"
}{
"type": "https://help.skillsdb.com/api-docs/errors/validation-error",
"title": "Validation failed",
"status": 400,
"detail": "limit must be between 1 and 200",
"instance": "/api/v1/people",
"requestId": "0192c2f1-6f4e-7ab3-b1c4-5f6a7b8c9d0e",
"errors": [
{
"field": "email",
"code": "max_length",
"message": "email must be shorter than or equal to 75 characters"
}
],
"error": "trial_expired",
"upgrade_url": "https://app.skillsdb.com/settings/billing"
}Authorizations
An API key issued by a company administrator — an environment prefix (production: sdb_live_) followed by 32 characters. The prefix identifies the environment and MUST NOT be hard-coded or validated by clients; treat the whole key as opaque. Shown exactly once at creation; only a one-way hash is stored.
Scopes (granted per key on the create screen; :write never implies :read):
skills:readskills:writepeople:readpeople:writecareers:readcareers:writetraining:readtraining:writeflags:readflags:writeorg:readorg:writeassessments:readlearning:readlearning:writecertifications:readcertifications:writeassessments:writeproficiency:readproficiency:writesurveys:readsurveys:writelabels:readlabels:write
Headers
Any unique string (at most 200 characters). Retrying with the same key and identical content replays the stored response for 24h instead of executing twice.
200Body
The batch. At most 500 records — a larger batch is rejected, never truncated.
Show child attributes
Show child attributes
Response
The resource, enveloped.
Show child attributes
Show child attributes