curl --request POST \
--url https://prod.skillsdbnext.com/api/v1/people/{personId}/certifications \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"certificationId": "87",
"issuedAt": "2025-06-01",
"expiresAt": "2027-06-01",
"identifier": "FL-2291-B",
"scoreDescription": "Distinction",
"certified": true,
"issuingAuthority": "National Safety Council",
"files": [
{
"fileName": "certificate.pdf",
"label": "Certificate scan"
}
]
}
'import requests
url = "https://prod.skillsdbnext.com/api/v1/people/{personId}/certifications"
payload = {
"certificationId": "87",
"issuedAt": "2025-06-01",
"expiresAt": "2027-06-01",
"identifier": "FL-2291-B",
"scoreDescription": "Distinction",
"certified": True,
"issuingAuthority": "National Safety Council",
"files": [
{
"fileName": "certificate.pdf",
"label": "Certificate scan"
}
]
}
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({
certificationId: '87',
issuedAt: '2025-06-01',
expiresAt: '2027-06-01',
identifier: 'FL-2291-B',
scoreDescription: 'Distinction',
certified: true,
issuingAuthority: 'National Safety Council',
files: [{fileName: 'certificate.pdf', label: 'Certificate scan'}]
})
};
fetch('https://prod.skillsdbnext.com/api/v1/people/{personId}/certifications', 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/people/{personId}/certifications",
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([
'certificationId' => '87',
'issuedAt' => '2025-06-01',
'expiresAt' => '2027-06-01',
'identifier' => 'FL-2291-B',
'scoreDescription' => 'Distinction',
'certified' => true,
'issuingAuthority' => 'National Safety Council',
'files' => [
[
'fileName' => 'certificate.pdf',
'label' => 'Certificate scan'
]
]
]),
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/people/{personId}/certifications"
payload := strings.NewReader("{\n \"certificationId\": \"87\",\n \"issuedAt\": \"2025-06-01\",\n \"expiresAt\": \"2027-06-01\",\n \"identifier\": \"FL-2291-B\",\n \"scoreDescription\": \"Distinction\",\n \"certified\": true,\n \"issuingAuthority\": \"National Safety Council\",\n \"files\": [\n {\n \"fileName\": \"certificate.pdf\",\n \"label\": \"Certificate scan\"\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/people/{personId}/certifications")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"certificationId\": \"87\",\n \"issuedAt\": \"2025-06-01\",\n \"expiresAt\": \"2027-06-01\",\n \"identifier\": \"FL-2291-B\",\n \"scoreDescription\": \"Distinction\",\n \"certified\": true,\n \"issuingAuthority\": \"National Safety Council\",\n \"files\": [\n {\n \"fileName\": \"certificate.pdf\",\n \"label\": \"Certificate scan\"\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://prod.skillsdbnext.com/api/v1/people/{personId}/certifications")
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 \"certificationId\": \"87\",\n \"issuedAt\": \"2025-06-01\",\n \"expiresAt\": \"2027-06-01\",\n \"identifier\": \"FL-2291-B\",\n \"scoreDescription\": \"Distinction\",\n \"certified\": true,\n \"issuingAuthority\": \"National Safety Council\",\n \"files\": [\n {\n \"fileName\": \"certificate.pdf\",\n \"label\": \"Certificate scan\"\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"data": {
"certification": {
"person": {
"id": "1042",
"name": "Dana Whitfield"
},
"certification": {
"id": "87",
"name": "Forklift Operator Licence",
"type": "Regulatory"
},
"status": "approved",
"certified": true,
"identifier": "FL-2291-B",
"issuedAt": "2025-06-01T00:00:00.000Z",
"expiresAt": "2027-06-01T00:00:00.000Z",
"expiry": {
"state": "expiring",
"daysUntil": 12
},
"scoreDescription": "Distinction",
"issuingAuthority": "National Safety Council",
"heldDirectly": true,
"careers": [
"Warehouse Operator"
],
"attachmentCount": 2,
"labels": [
{
"id": "12",
"name": "Safety"
}
],
"submittedAt": "2026-01-10T10:00:00.000Z",
"approvedAt": "2026-01-12T10:00:00.000Z",
"deniedAt": null,
"attachments": [
{
"id": "5011",
"type": "file",
"label": "Certificate scan",
"url": "https://verify.example.org/abc",
"createdAt": "2026-02-01T09:00:00.000Z"
}
]
},
"uploads": [
{
"attachmentId": "5011",
"fileName": "certificate.pdf",
"label": "Certificate scan",
"uploadUrl": "<string>"
}
]
}
}{
"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"
}Record a certification for a person
Creates the person’s certification in assigned. With only certificationId this is the light assign; add issued/expiry dates, identifier, score, certified flag and evidence to record it in full. Each file returns a pre-signed upload URL. 409 if already held.
Requires scope: certifications:write.
curl --request POST \
--url https://prod.skillsdbnext.com/api/v1/people/{personId}/certifications \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"certificationId": "87",
"issuedAt": "2025-06-01",
"expiresAt": "2027-06-01",
"identifier": "FL-2291-B",
"scoreDescription": "Distinction",
"certified": true,
"issuingAuthority": "National Safety Council",
"files": [
{
"fileName": "certificate.pdf",
"label": "Certificate scan"
}
]
}
'import requests
url = "https://prod.skillsdbnext.com/api/v1/people/{personId}/certifications"
payload = {
"certificationId": "87",
"issuedAt": "2025-06-01",
"expiresAt": "2027-06-01",
"identifier": "FL-2291-B",
"scoreDescription": "Distinction",
"certified": True,
"issuingAuthority": "National Safety Council",
"files": [
{
"fileName": "certificate.pdf",
"label": "Certificate scan"
}
]
}
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({
certificationId: '87',
issuedAt: '2025-06-01',
expiresAt: '2027-06-01',
identifier: 'FL-2291-B',
scoreDescription: 'Distinction',
certified: true,
issuingAuthority: 'National Safety Council',
files: [{fileName: 'certificate.pdf', label: 'Certificate scan'}]
})
};
fetch('https://prod.skillsdbnext.com/api/v1/people/{personId}/certifications', 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/people/{personId}/certifications",
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([
'certificationId' => '87',
'issuedAt' => '2025-06-01',
'expiresAt' => '2027-06-01',
'identifier' => 'FL-2291-B',
'scoreDescription' => 'Distinction',
'certified' => true,
'issuingAuthority' => 'National Safety Council',
'files' => [
[
'fileName' => 'certificate.pdf',
'label' => 'Certificate scan'
]
]
]),
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/people/{personId}/certifications"
payload := strings.NewReader("{\n \"certificationId\": \"87\",\n \"issuedAt\": \"2025-06-01\",\n \"expiresAt\": \"2027-06-01\",\n \"identifier\": \"FL-2291-B\",\n \"scoreDescription\": \"Distinction\",\n \"certified\": true,\n \"issuingAuthority\": \"National Safety Council\",\n \"files\": [\n {\n \"fileName\": \"certificate.pdf\",\n \"label\": \"Certificate scan\"\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/people/{personId}/certifications")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"certificationId\": \"87\",\n \"issuedAt\": \"2025-06-01\",\n \"expiresAt\": \"2027-06-01\",\n \"identifier\": \"FL-2291-B\",\n \"scoreDescription\": \"Distinction\",\n \"certified\": true,\n \"issuingAuthority\": \"National Safety Council\",\n \"files\": [\n {\n \"fileName\": \"certificate.pdf\",\n \"label\": \"Certificate scan\"\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://prod.skillsdbnext.com/api/v1/people/{personId}/certifications")
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 \"certificationId\": \"87\",\n \"issuedAt\": \"2025-06-01\",\n \"expiresAt\": \"2027-06-01\",\n \"identifier\": \"FL-2291-B\",\n \"scoreDescription\": \"Distinction\",\n \"certified\": true,\n \"issuingAuthority\": \"National Safety Council\",\n \"files\": [\n {\n \"fileName\": \"certificate.pdf\",\n \"label\": \"Certificate scan\"\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"data": {
"certification": {
"person": {
"id": "1042",
"name": "Dana Whitfield"
},
"certification": {
"id": "87",
"name": "Forklift Operator Licence",
"type": "Regulatory"
},
"status": "approved",
"certified": true,
"identifier": "FL-2291-B",
"issuedAt": "2025-06-01T00:00:00.000Z",
"expiresAt": "2027-06-01T00:00:00.000Z",
"expiry": {
"state": "expiring",
"daysUntil": 12
},
"scoreDescription": "Distinction",
"issuingAuthority": "National Safety Council",
"heldDirectly": true,
"careers": [
"Warehouse Operator"
],
"attachmentCount": 2,
"labels": [
{
"id": "12",
"name": "Safety"
}
],
"submittedAt": "2026-01-10T10:00:00.000Z",
"approvedAt": "2026-01-12T10:00:00.000Z",
"deniedAt": null,
"attachments": [
{
"id": "5011",
"type": "file",
"label": "Certificate scan",
"url": "https://verify.example.org/abc",
"createdAt": "2026-02-01T09:00:00.000Z"
}
]
},
"uploads": [
{
"attachmentId": "5011",
"fileName": "certificate.pdf",
"label": "Certificate scan",
"uploadUrl": "<string>"
}
]
}
}{
"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.
200Path Parameters
The person's email address — or the opaque person id from any response.
"ada@example.com"
Body
Certification id from GET /certifications.
"87"
Issued date (ISO 8601).
"2025-06-01"
Expiry date (ISO 8601); must not precede issuedAt.
"2027-06-01"
255"FL-2291-B"
255"Distinction"
Pass/fail. The app can only ever record true; the API may record false.
true
255"National Safety Council"
Show child attributes
Show child attributes
Each file returns a pre-signed upload URL.
Show child attributes
Show child attributes
Response
The created resource, enveloped.
Show child attributes
Show child attributes