Skills API
Create Skill
Author a new skill (private by default).
POST
/
api
/
v1
/
skills
/
create
Create Skill
curl --request POST \
--url https://api.example.com/api/v1/skills/create \
--header 'Content-Type: application/json' \
--data '
{
"name": "<string>",
"slug": "<string>",
"category": "<string>",
"system_prompt_ext": "<string>",
"description": "<string>",
"tool_definitions": [
{}
],
"is_public": true
}
'import requests
url = "https://api.example.com/api/v1/skills/create"
payload = {
"name": "<string>",
"slug": "<string>",
"category": "<string>",
"system_prompt_ext": "<string>",
"description": "<string>",
"tool_definitions": [{}],
"is_public": True
}
headers = {"Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
name: '<string>',
slug: '<string>',
category: '<string>',
system_prompt_ext: '<string>',
description: '<string>',
tool_definitions: [{}],
is_public: true
})
};
fetch('https://api.example.com/api/v1/skills/create', 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/api/v1/skills/create",
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([
'name' => '<string>',
'slug' => '<string>',
'category' => '<string>',
'system_prompt_ext' => '<string>',
'description' => '<string>',
'tool_definitions' => [
[
]
],
'is_public' => true
]),
CURLOPT_HTTPHEADER => [
"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://api.example.com/api/v1/skills/create"
payload := strings.NewReader("{\n \"name\": \"<string>\",\n \"slug\": \"<string>\",\n \"category\": \"<string>\",\n \"system_prompt_ext\": \"<string>\",\n \"description\": \"<string>\",\n \"tool_definitions\": [\n {}\n ],\n \"is_public\": true\n}")
req, _ := http.NewRequest("POST", url, payload)
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/api/v1/skills/create")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"<string>\",\n \"slug\": \"<string>\",\n \"category\": \"<string>\",\n \"system_prompt_ext\": \"<string>\",\n \"description\": \"<string>\",\n \"tool_definitions\": [\n {}\n ],\n \"is_public\": true\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/api/v1/skills/create")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n \"name\": \"<string>\",\n \"slug\": \"<string>\",\n \"category\": \"<string>\",\n \"system_prompt_ext\": \"<string>\",\n \"description\": \"<string>\",\n \"tool_definitions\": [\n {}\n ],\n \"is_public\": true\n}"
response = http.request(request)
puts response.read_body{
"skill": {}
}Create a new skill. Skills are private by default — use Submit Skill to publish to the marketplace.
Authentication
Requires a Bearer token. See Authentication.Request Body
Human-readable skill name.
Unique identifier. Must be lowercase alphanumeric with hyphens (e.g.,
"inventory-check").Skill category. One of:
productivity, domain, integration, automation, creative.System prompt extension injected into the LLM context when this skill is active.
Short description of what the skill does.
Tool definitions the skill provides.
Whether the skill is publicly listed. Use Submit Skill for marketplace publishing with review.
Request Examples
curl -X POST https://www.hitheo.ai/api/v1/skills/create \
-H "Authorization: Bearer $THEO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Inventory Check",
"slug": "inventory-check",
"category": "automation",
"system_prompt_ext": "You are an inventory specialist. Use check_stock to look up levels.",
"description": "Real-time inventory lookup and reorder alerts",
"tool_definitions": [
{
"name": "check_stock",
"description": "Look up current stock levels for a SKU",
"inputSchema": {
"type": "object",
"properties": { "sku": { "type": "string" } },
"required": ["sku"]
}
}
]
}'
const skill = await theo.createSkill({
name: "Inventory Check",
slug: "inventory-check",
category: "automation",
system_prompt_ext: "You are an inventory specialist. Use check_stock to look up levels.",
description: "Real-time inventory lookup and reorder alerts",
tool_definitions: [
{
name: "check_stock",
description: "Look up current stock levels for a SKU",
inputSchema: {
type: "object",
properties: { sku: { type: "string" } },
required: ["sku"],
},
},
],
});
Response (HTTP 201)
The created skill object with all fields including the generated
id.Errors
| Status | Code | Description |
|---|---|---|
| 400 | validation_error | Missing required fields or invalid slug format |
| 409 | conflict | A skill with this slug already exists |
Was this page helpful?
⌘I
Create Skill
curl --request POST \
--url https://api.example.com/api/v1/skills/create \
--header 'Content-Type: application/json' \
--data '
{
"name": "<string>",
"slug": "<string>",
"category": "<string>",
"system_prompt_ext": "<string>",
"description": "<string>",
"tool_definitions": [
{}
],
"is_public": true
}
'import requests
url = "https://api.example.com/api/v1/skills/create"
payload = {
"name": "<string>",
"slug": "<string>",
"category": "<string>",
"system_prompt_ext": "<string>",
"description": "<string>",
"tool_definitions": [{}],
"is_public": True
}
headers = {"Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
name: '<string>',
slug: '<string>',
category: '<string>',
system_prompt_ext: '<string>',
description: '<string>',
tool_definitions: [{}],
is_public: true
})
};
fetch('https://api.example.com/api/v1/skills/create', 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/api/v1/skills/create",
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([
'name' => '<string>',
'slug' => '<string>',
'category' => '<string>',
'system_prompt_ext' => '<string>',
'description' => '<string>',
'tool_definitions' => [
[
]
],
'is_public' => true
]),
CURLOPT_HTTPHEADER => [
"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://api.example.com/api/v1/skills/create"
payload := strings.NewReader("{\n \"name\": \"<string>\",\n \"slug\": \"<string>\",\n \"category\": \"<string>\",\n \"system_prompt_ext\": \"<string>\",\n \"description\": \"<string>\",\n \"tool_definitions\": [\n {}\n ],\n \"is_public\": true\n}")
req, _ := http.NewRequest("POST", url, payload)
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/api/v1/skills/create")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"<string>\",\n \"slug\": \"<string>\",\n \"category\": \"<string>\",\n \"system_prompt_ext\": \"<string>\",\n \"description\": \"<string>\",\n \"tool_definitions\": [\n {}\n ],\n \"is_public\": true\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/api/v1/skills/create")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n \"name\": \"<string>\",\n \"slug\": \"<string>\",\n \"category\": \"<string>\",\n \"system_prompt_ext\": \"<string>\",\n \"description\": \"<string>\",\n \"tool_definitions\": [\n {}\n ],\n \"is_public\": true\n}"
response = http.request(request)
puts response.read_body{
"skill": {}
}