Add Selected Skill
curl --request POST \
--url https://api.example.com/v1/api/selected-skills \
--header 'Content-Type: application/json' \
--header 'x-api-key: <api-key>' \
--data '
{
"user_id": "<string>",
"skill_id": "<string>",
"sub_skill_id": "<string>",
"master_skill_id": "<string>"
}
'import requests
url = "https://api.example.com/v1/api/selected-skills"
payload = {
"user_id": "<string>",
"skill_id": "<string>",
"sub_skill_id": "<string>",
"master_skill_id": "<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({
user_id: '<string>',
skill_id: '<string>',
sub_skill_id: '<string>',
master_skill_id: '<string>'
})
};
fetch('https://api.example.com/v1/api/selected-skills', 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.example.com/v1/api/selected-skills",
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([
'user_id' => '<string>',
'skill_id' => '<string>',
'sub_skill_id' => '<string>',
'master_skill_id' => '<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.example.com/v1/api/selected-skills"
payload := strings.NewReader("{\n \"user_id\": \"<string>\",\n \"skill_id\": \"<string>\",\n \"sub_skill_id\": \"<string>\",\n \"master_skill_id\": \"<string>\"\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.example.com/v1/api/selected-skills")
.header("x-api-key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"user_id\": \"<string>\",\n \"skill_id\": \"<string>\",\n \"sub_skill_id\": \"<string>\",\n \"master_skill_id\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/v1/api/selected-skills")
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 \"user_id\": \"<string>\",\n \"skill_id\": \"<string>\",\n \"sub_skill_id\": \"<string>\",\n \"master_skill_id\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"success": true,
"message": "Skill selected successfully",
"data": {
"selected_skill_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"user_id": "user-123",
"skill_id": "sk-001",
"sub_skill_id": "sub-001",
"master_skill_id": "ms-001",
"createdAt": "2025-01-15T10:30:00.000Z",
"updatedAt": "2025-01-15T10:30:00.000Z"
}
}
{
"message": "\"skill_id\" is required"
}
{
"success": false,
"message": "Skill already selected by this user"
}
Selected Skills
Add Selected Skill
Record that a user has selected a skill.
POST
/
api
/
selected-skills
Add Selected Skill
curl --request POST \
--url https://api.example.com/v1/api/selected-skills \
--header 'Content-Type: application/json' \
--header 'x-api-key: <api-key>' \
--data '
{
"user_id": "<string>",
"skill_id": "<string>",
"sub_skill_id": "<string>",
"master_skill_id": "<string>"
}
'import requests
url = "https://api.example.com/v1/api/selected-skills"
payload = {
"user_id": "<string>",
"skill_id": "<string>",
"sub_skill_id": "<string>",
"master_skill_id": "<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({
user_id: '<string>',
skill_id: '<string>',
sub_skill_id: '<string>',
master_skill_id: '<string>'
})
};
fetch('https://api.example.com/v1/api/selected-skills', 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.example.com/v1/api/selected-skills",
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([
'user_id' => '<string>',
'skill_id' => '<string>',
'sub_skill_id' => '<string>',
'master_skill_id' => '<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.example.com/v1/api/selected-skills"
payload := strings.NewReader("{\n \"user_id\": \"<string>\",\n \"skill_id\": \"<string>\",\n \"sub_skill_id\": \"<string>\",\n \"master_skill_id\": \"<string>\"\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.example.com/v1/api/selected-skills")
.header("x-api-key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"user_id\": \"<string>\",\n \"skill_id\": \"<string>\",\n \"sub_skill_id\": \"<string>\",\n \"master_skill_id\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/v1/api/selected-skills")
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 \"user_id\": \"<string>\",\n \"skill_id\": \"<string>\",\n \"sub_skill_id\": \"<string>\",\n \"master_skill_id\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"success": true,
"message": "Skill selected successfully",
"data": {
"selected_skill_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"user_id": "user-123",
"skill_id": "sk-001",
"sub_skill_id": "sub-001",
"master_skill_id": "ms-001",
"createdAt": "2025-01-15T10:30:00.000Z",
"updatedAt": "2025-01-15T10:30:00.000Z"
}
}
{
"message": "\"skill_id\" is required"
}
{
"success": false,
"message": "Skill already selected by this user"
}
Send a user ID and a skill ID, and this creates a record tying them together. That’s it.
One rule: a user can’t select the same skill twice. Try it and you’ll get a
409. This is enforced at both the application level and in the database with a compound unique index, so even concurrent requests won’t create duplicates.
No authentication needed.
Request Body
string
required
The user who’s selecting the skill.
string
required
The skill being selected.
string
required
The sub-skill category this skill belongs to. You can get this from the search endpoint.
string
required
The master skill category. Also available from search results.
Response
boolean
true when the record is createdstring
A short confirmation message
object
Examples
curl -X POST http://localhost:5000/api/selected-skills \
-H "Content-Type: application/json" \
-d '{
"user_id": "user-123",
"skill_id": "sk-001",
"sub_skill_id": "sub-001",
"master_skill_id": "ms-001"
}'
const res = await fetch("http://localhost:5000/api/selected-skills", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
user_id: "user-123",
skill_id: "sk-001",
sub_skill_id: "sub-001",
master_skill_id: "ms-001"
})
});
const data = await res.json();
import requests
res = requests.post(
"http://localhost:5000/api/selected-skills",
json={
"user_id": "user-123",
"skill_id": "sk-001",
"sub_skill_id": "sub-001",
"master_skill_id": "ms-001"
}
)
print(res.json())
{
"success": true,
"message": "Skill selected successfully",
"data": {
"selected_skill_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"user_id": "user-123",
"skill_id": "sk-001",
"sub_skill_id": "sub-001",
"master_skill_id": "ms-001",
"createdAt": "2025-01-15T10:30:00.000Z",
"updatedAt": "2025-01-15T10:30:00.000Z"
}
}
{
"message": "\"skill_id\" is required"
}
{
"success": false,
"message": "Skill already selected by this user"
}
Why does the 409 check happen twice?The route checks for an existing
{ user_id, skill_id } record before trying to insert. But just in case two requests land at exactly the same time, the database also has a compound unique index on those fields. The app-level check gives you the nicer error message. The DB-level index is the safety net.⌘I

