curl --request POST \
--url https://prod.skillsdbnext.com/api/v1/trainings \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"email": "ada@example.com",
"skillId": "63",
"trainingDate": "2026-02-10T00:00:00.000Z",
"trainer": "J. Instructor",
"evidenceNote": "Completed the practical assessment.",
"delegatedApproverEmail": "dana@example.com",
"preApproved": false,
"notApplicable": false
}
'import requests
url = "https://prod.skillsdbnext.com/api/v1/trainings"
payload = {
"email": "ada@example.com",
"skillId": "63",
"trainingDate": "2026-02-10T00:00:00.000Z",
"trainer": "J. Instructor",
"evidenceNote": "Completed the practical assessment.",
"delegatedApproverEmail": "dana@example.com",
"preApproved": False,
"notApplicable": False
}
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({
email: 'ada@example.com',
skillId: '63',
trainingDate: '2026-02-10T00:00:00.000Z',
trainer: 'J. Instructor',
evidenceNote: 'Completed the practical assessment.',
delegatedApproverEmail: 'dana@example.com',
preApproved: false,
notApplicable: false
})
};
fetch('https://prod.skillsdbnext.com/api/v1/trainings', 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/trainings",
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([
'email' => 'ada@example.com',
'skillId' => '63',
'trainingDate' => '2026-02-10T00:00:00.000Z',
'trainer' => 'J. Instructor',
'evidenceNote' => 'Completed the practical assessment.',
'delegatedApproverEmail' => 'dana@example.com',
'preApproved' => false,
'notApplicable' => false
]),
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/trainings"
payload := strings.NewReader("{\n \"email\": \"ada@example.com\",\n \"skillId\": \"63\",\n \"trainingDate\": \"2026-02-10T00:00:00.000Z\",\n \"trainer\": \"J. Instructor\",\n \"evidenceNote\": \"Completed the practical assessment.\",\n \"delegatedApproverEmail\": \"dana@example.com\",\n \"preApproved\": false,\n \"notApplicable\": false\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/trainings")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"email\": \"ada@example.com\",\n \"skillId\": \"63\",\n \"trainingDate\": \"2026-02-10T00:00:00.000Z\",\n \"trainer\": \"J. Instructor\",\n \"evidenceNote\": \"Completed the practical assessment.\",\n \"delegatedApproverEmail\": \"dana@example.com\",\n \"preApproved\": false,\n \"notApplicable\": false\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://prod.skillsdbnext.com/api/v1/trainings")
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 \"email\": \"ada@example.com\",\n \"skillId\": \"63\",\n \"trainingDate\": \"2026-02-10T00:00:00.000Z\",\n \"trainer\": \"J. Instructor\",\n \"evidenceNote\": \"Completed the practical assessment.\",\n \"delegatedApproverEmail\": \"dana@example.com\",\n \"preApproved\": false,\n \"notApplicable\": false\n}"
response = http.request(request)
puts response.read_body{
"data": {
"id": "5120",
"person": {
"id": "42",
"name": "Welding"
},
"skill": {
"id": "42",
"name": "Welding"
},
"trainingDate": "2026-02-10T00:00:00.000Z",
"trainer": "J. Instructor",
"status": "approved",
"isNotApplicable": false,
"evidenceNote": "Completed the practical assessment.",
"expiresAt": "2027-02-10T00:00:00.000Z",
"isExpired": false,
"skillVersionId": "402",
"requestedById": "91",
"requestedAt": "2026-02-10T09:00:00.000Z",
"delegatedApproverId": "88",
"decision": {
"outcome": "approved",
"decidedById": "88",
"decidedAt": "2026-03-02T14:00:00.000Z",
"reason": null
},
"isSuperseded": false,
"createdAt": "2026-02-10T09:00:00.000Z"
}
}{
"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 training
Records a training against a person’s skill — the skill must already be on the person’s profile. preApproved=true creates the record already approved, bypassing the request step. notApplicable=true records the exclusion without deleting anything. Evidence rules (note, attachments, or both) are configured on the career skill.
Requires scope: training:write.
curl --request POST \
--url https://prod.skillsdbnext.com/api/v1/trainings \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"email": "ada@example.com",
"skillId": "63",
"trainingDate": "2026-02-10T00:00:00.000Z",
"trainer": "J. Instructor",
"evidenceNote": "Completed the practical assessment.",
"delegatedApproverEmail": "dana@example.com",
"preApproved": false,
"notApplicable": false
}
'import requests
url = "https://prod.skillsdbnext.com/api/v1/trainings"
payload = {
"email": "ada@example.com",
"skillId": "63",
"trainingDate": "2026-02-10T00:00:00.000Z",
"trainer": "J. Instructor",
"evidenceNote": "Completed the practical assessment.",
"delegatedApproverEmail": "dana@example.com",
"preApproved": False,
"notApplicable": False
}
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({
email: 'ada@example.com',
skillId: '63',
trainingDate: '2026-02-10T00:00:00.000Z',
trainer: 'J. Instructor',
evidenceNote: 'Completed the practical assessment.',
delegatedApproverEmail: 'dana@example.com',
preApproved: false,
notApplicable: false
})
};
fetch('https://prod.skillsdbnext.com/api/v1/trainings', 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/trainings",
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([
'email' => 'ada@example.com',
'skillId' => '63',
'trainingDate' => '2026-02-10T00:00:00.000Z',
'trainer' => 'J. Instructor',
'evidenceNote' => 'Completed the practical assessment.',
'delegatedApproverEmail' => 'dana@example.com',
'preApproved' => false,
'notApplicable' => false
]),
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/trainings"
payload := strings.NewReader("{\n \"email\": \"ada@example.com\",\n \"skillId\": \"63\",\n \"trainingDate\": \"2026-02-10T00:00:00.000Z\",\n \"trainer\": \"J. Instructor\",\n \"evidenceNote\": \"Completed the practical assessment.\",\n \"delegatedApproverEmail\": \"dana@example.com\",\n \"preApproved\": false,\n \"notApplicable\": false\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/trainings")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"email\": \"ada@example.com\",\n \"skillId\": \"63\",\n \"trainingDate\": \"2026-02-10T00:00:00.000Z\",\n \"trainer\": \"J. Instructor\",\n \"evidenceNote\": \"Completed the practical assessment.\",\n \"delegatedApproverEmail\": \"dana@example.com\",\n \"preApproved\": false,\n \"notApplicable\": false\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://prod.skillsdbnext.com/api/v1/trainings")
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 \"email\": \"ada@example.com\",\n \"skillId\": \"63\",\n \"trainingDate\": \"2026-02-10T00:00:00.000Z\",\n \"trainer\": \"J. Instructor\",\n \"evidenceNote\": \"Completed the practical assessment.\",\n \"delegatedApproverEmail\": \"dana@example.com\",\n \"preApproved\": false,\n \"notApplicable\": false\n}"
response = http.request(request)
puts response.read_body{
"data": {
"id": "5120",
"person": {
"id": "42",
"name": "Welding"
},
"skill": {
"id": "42",
"name": "Welding"
},
"trainingDate": "2026-02-10T00:00:00.000Z",
"trainer": "J. Instructor",
"status": "approved",
"isNotApplicable": false,
"evidenceNote": "Completed the practical assessment.",
"expiresAt": "2027-02-10T00:00:00.000Z",
"isExpired": false,
"skillVersionId": "402",
"requestedById": "91",
"requestedAt": "2026-02-10T09:00:00.000Z",
"delegatedApproverId": "88",
"decision": {
"outcome": "approved",
"decidedById": "88",
"decidedAt": "2026-03-02T14:00:00.000Z",
"reason": null
},
"isSuperseded": false,
"createdAt": "2026-02-10T09:00:00.000Z"
}
}{
"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
Email address of the person the training is recorded for (ENG-4110: people are addressed by email).
"ada@example.com"
"63"
"2026-02-10T00:00:00.000Z"
500"J. Instructor"
"Completed the practical assessment."
Email address of a named person to delegate the approval to.
"dana@example.com"
Create the record already approved, bypassing the request step.
false
Mark the training not applicable for this person.
false
Response
The created resource, enveloped.
Show child attributes
Show child attributes