curl --request POST \
--url https://prod.skillsdbnext.com/api/v1/surveys/{id}/people/{personId}/responses \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"questionId": "7001",
"text": "More pairing time with senior riggers.",
"rating": 4,
"optionIds": [
"<string>"
],
"conditionalAnswers": [
{
"optionId": "5003",
"value": "Other: night shift"
}
],
"fileName": "evidence.pdf"
}
'import requests
url = "https://prod.skillsdbnext.com/api/v1/surveys/{id}/people/{personId}/responses"
payload = {
"questionId": "7001",
"text": "More pairing time with senior riggers.",
"rating": 4,
"optionIds": ["<string>"],
"conditionalAnswers": [
{
"optionId": "5003",
"value": "Other: night shift"
}
],
"fileName": "evidence.pdf"
}
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({
questionId: '7001',
text: 'More pairing time with senior riggers.',
rating: 4,
optionIds: ['<string>'],
conditionalAnswers: [{optionId: '5003', value: 'Other: night shift'}],
fileName: 'evidence.pdf'
})
};
fetch('https://prod.skillsdbnext.com/api/v1/surveys/{id}/people/{personId}/responses', 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/surveys/{id}/people/{personId}/responses",
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([
'questionId' => '7001',
'text' => 'More pairing time with senior riggers.',
'rating' => 4,
'optionIds' => [
'<string>'
],
'conditionalAnswers' => [
[
'optionId' => '5003',
'value' => 'Other: night shift'
]
],
'fileName' => 'evidence.pdf'
]),
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/surveys/{id}/people/{personId}/responses"
payload := strings.NewReader("{\n \"questionId\": \"7001\",\n \"text\": \"More pairing time with senior riggers.\",\n \"rating\": 4,\n \"optionIds\": [\n \"<string>\"\n ],\n \"conditionalAnswers\": [\n {\n \"optionId\": \"5003\",\n \"value\": \"Other: night shift\"\n }\n ],\n \"fileName\": \"evidence.pdf\"\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/surveys/{id}/people/{personId}/responses")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"questionId\": \"7001\",\n \"text\": \"More pairing time with senior riggers.\",\n \"rating\": 4,\n \"optionIds\": [\n \"<string>\"\n ],\n \"conditionalAnswers\": [\n {\n \"optionId\": \"5003\",\n \"value\": \"Other: night shift\"\n }\n ],\n \"fileName\": \"evidence.pdf\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://prod.skillsdbnext.com/api/v1/surveys/{id}/people/{personId}/responses")
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 \"questionId\": \"7001\",\n \"text\": \"More pairing time with senior riggers.\",\n \"rating\": 4,\n \"optionIds\": [\n \"<string>\"\n ],\n \"conditionalAnswers\": [\n {\n \"optionId\": \"5003\",\n \"value\": \"Other: night shift\"\n }\n ],\n \"fileName\": \"evidence.pdf\"\n}"
response = http.request(request)
puts response.read_body{
"data": {
"response": {
"id": "9001",
"personId": "1042",
"question": {
"id": "7001",
"questionVersionId": "410",
"name": "Manager support",
"text": "My manager supports my development.",
"version": "1.0",
"type": "multiple_choice",
"position": 1
},
"answer": {
"kind": "text",
"text": "More pairing time with senior riggers.",
"rating": null,
"fileName": null,
"options": [
{
"id": "5001",
"label": "Strongly agree",
"conditionalValue": null
}
],
"certificationCount": 0
},
"createdAt": "2026-07-02T10:00:00.000Z",
"updatedAt": null
},
"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"
}Submit a response
Text, a rating, answer options or a file, depending on the question type. Only the participant may answer — the key must act as that person; anyone else is a 403. For upload questions the result carries a pre-signed upload URL for fileName. A survey that is not launched is a 409.
Requires scope: surveys:write.
curl --request POST \
--url https://prod.skillsdbnext.com/api/v1/surveys/{id}/people/{personId}/responses \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"questionId": "7001",
"text": "More pairing time with senior riggers.",
"rating": 4,
"optionIds": [
"<string>"
],
"conditionalAnswers": [
{
"optionId": "5003",
"value": "Other: night shift"
}
],
"fileName": "evidence.pdf"
}
'import requests
url = "https://prod.skillsdbnext.com/api/v1/surveys/{id}/people/{personId}/responses"
payload = {
"questionId": "7001",
"text": "More pairing time with senior riggers.",
"rating": 4,
"optionIds": ["<string>"],
"conditionalAnswers": [
{
"optionId": "5003",
"value": "Other: night shift"
}
],
"fileName": "evidence.pdf"
}
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({
questionId: '7001',
text: 'More pairing time with senior riggers.',
rating: 4,
optionIds: ['<string>'],
conditionalAnswers: [{optionId: '5003', value: 'Other: night shift'}],
fileName: 'evidence.pdf'
})
};
fetch('https://prod.skillsdbnext.com/api/v1/surveys/{id}/people/{personId}/responses', 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/surveys/{id}/people/{personId}/responses",
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([
'questionId' => '7001',
'text' => 'More pairing time with senior riggers.',
'rating' => 4,
'optionIds' => [
'<string>'
],
'conditionalAnswers' => [
[
'optionId' => '5003',
'value' => 'Other: night shift'
]
],
'fileName' => 'evidence.pdf'
]),
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/surveys/{id}/people/{personId}/responses"
payload := strings.NewReader("{\n \"questionId\": \"7001\",\n \"text\": \"More pairing time with senior riggers.\",\n \"rating\": 4,\n \"optionIds\": [\n \"<string>\"\n ],\n \"conditionalAnswers\": [\n {\n \"optionId\": \"5003\",\n \"value\": \"Other: night shift\"\n }\n ],\n \"fileName\": \"evidence.pdf\"\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/surveys/{id}/people/{personId}/responses")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"questionId\": \"7001\",\n \"text\": \"More pairing time with senior riggers.\",\n \"rating\": 4,\n \"optionIds\": [\n \"<string>\"\n ],\n \"conditionalAnswers\": [\n {\n \"optionId\": \"5003\",\n \"value\": \"Other: night shift\"\n }\n ],\n \"fileName\": \"evidence.pdf\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://prod.skillsdbnext.com/api/v1/surveys/{id}/people/{personId}/responses")
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 \"questionId\": \"7001\",\n \"text\": \"More pairing time with senior riggers.\",\n \"rating\": 4,\n \"optionIds\": [\n \"<string>\"\n ],\n \"conditionalAnswers\": [\n {\n \"optionId\": \"5003\",\n \"value\": \"Other: night shift\"\n }\n ],\n \"fileName\": \"evidence.pdf\"\n}"
response = http.request(request)
puts response.read_body{
"data": {
"response": {
"id": "9001",
"personId": "1042",
"question": {
"id": "7001",
"questionVersionId": "410",
"name": "Manager support",
"text": "My manager supports my development.",
"version": "1.0",
"type": "multiple_choice",
"position": 1
},
"answer": {
"kind": "text",
"text": "More pairing time with senior riggers.",
"rating": null,
"fileName": null,
"options": [
{
"id": "5001",
"label": "Strongly agree",
"conditionalValue": null
}
],
"certificationCount": 0
},
"createdAt": "2026-07-02T10:00:00.000Z",
"updatedAt": null
},
"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
Opaque resource id.
The person's email address — or the opaque person id from any response.
"ada@example.com"
Body
A question id from the survey's question set.
"7001"
8000"More pairing time with senior riggers."
4
Answer option ids for choice questions.
Show child attributes
Show child attributes
For upload questions: the file to PUT to the returned uploadUrl.
255"evidence.pdf"
Response
The created resource, enveloped.
Show child attributes
Show child attributes