curl --request POST \
--url https://api.checkfu.com/v1/skill-proposals \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'checkfu-version: <checkfu-version>' \
--data '
{
"source_session_ids": [
"<string>"
],
"model_routing_profile_key": "<string>",
"instructions": "<string>",
"skill_name": "<string>"
}
'import requests
url = "https://api.checkfu.com/v1/skill-proposals"
payload = {
"source_session_ids": ["<string>"],
"model_routing_profile_key": "<string>",
"instructions": "<string>",
"skill_name": "<string>"
}
headers = {
"checkfu-version": "<checkfu-version>",
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'checkfu-version': '<checkfu-version>',
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
source_session_ids: ['<string>'],
model_routing_profile_key: '<string>',
instructions: '<string>',
skill_name: '<string>'
})
};
fetch('https://api.checkfu.com/v1/skill-proposals', 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.checkfu.com/v1/skill-proposals",
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([
'source_session_ids' => [
'<string>'
],
'model_routing_profile_key' => '<string>',
'instructions' => '<string>',
'skill_name' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json",
"checkfu-version: <checkfu-version>"
],
]);
$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.checkfu.com/v1/skill-proposals"
payload := strings.NewReader("{\n \"source_session_ids\": [\n \"<string>\"\n ],\n \"model_routing_profile_key\": \"<string>\",\n \"instructions\": \"<string>\",\n \"skill_name\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("checkfu-version", "<checkfu-version>")
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://api.checkfu.com/v1/skill-proposals")
.header("checkfu-version", "<checkfu-version>")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"source_session_ids\": [\n \"<string>\"\n ],\n \"model_routing_profile_key\": \"<string>\",\n \"instructions\": \"<string>\",\n \"skill_name\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.checkfu.com/v1/skill-proposals")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["checkfu-version"] = '<checkfu-version>'
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"source_session_ids\": [\n \"<string>\"\n ],\n \"model_routing_profile_key\": \"<string>\",\n \"instructions\": \"<string>\",\n \"skill_name\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"id": "<string>",
"status": "authoring",
"source_session_ids": [
"<string>"
],
"agent": "<string>",
"model_routing_profile_key": "<string>",
"instructions": "<string>",
"skill": {
"name": "<string>",
"description": "<string>",
"kind": "instructional",
"entry": "<string>",
"content_sha256": "<string>"
},
"verification_material": {
"task": "<string>",
"rubric": "<string>"
},
"verifications": [
{
"session": "<string>",
"started_at": "<string>",
"result": {
"verdict": "satisfied",
"explanation": "<string>",
"cost_tokens": 1,
"completed_at": "<string>"
},
"source_version": 1,
"principal": "<string>",
"launched_at": "<string>"
}
],
"submission": {
"skill_source": "<string>",
"branch": "<string>",
"commit_sha": "<string>",
"submitted_at": "<string>"
},
"adoption": {
"skill_id": "<string>",
"skill_version": 1,
"observed_at": "<string>"
},
"error": "input_session_unavailable",
"usage": {
"input_tokens": 1,
"cached_input_tokens": 1,
"cache_write_input_tokens": 1,
"output_tokens": 1,
"reasoning_output_tokens": 1,
"total_tokens": 1
},
"created_at": "<string>",
"updated_at": "<string>",
"version": 1,
"submission_attempt": {
"source_version": 1,
"skill_source": "<string>",
"acted_as": "<string>",
"branch": "<string>",
"base_commit_sha": "<string>",
"base_content_sha256": "<string>",
"expected_base_digest": "<string>",
"prepared_commit_sha": "<string>",
"started_at": "<string>"
}
}{
"error": {
"type": "validation.malformed",
"message": "<string>",
"more": "https://docs.checkfu.com/reference/errors#validation-malformed"
}
}{
"error": {
"type": "auth.invalid_key",
"message": "<string>",
"more": "https://docs.checkfu.com/reference/errors#auth-invalid-key"
}
}{
"error": {
"type": "auth.disabled_tenancy",
"message": "<string>",
"more": "https://docs.checkfu.com/reference/errors#auth-disabled-tenancy"
}
}{
"error": {
"type": "validation.not_found",
"message": "<string>",
"more": "https://docs.checkfu.com/reference/errors#validation-not-found"
}
}{
"error": {
"type": "validation.idempotency_conflict",
"message": "<string>",
"more": "https://docs.checkfu.com/reference/errors#validation-idempotency-conflict"
}
}{
"error": {
"type": "model.no_eligible_model",
"message": "<string>",
"more": "https://docs.checkfu.com/reference/errors#model-no-eligible-model"
}
}{
"error": {
"type": "budget.exceeded",
"message": "<string>",
"more": "https://docs.checkfu.com/reference/errors#budget-exceeded"
}
}{
"error": {
"type": "runtime.internal",
"message": "<string>",
"more": "https://docs.checkfu.com/reference/errors#runtime-internal"
}
}Author a Skill proposal
Start a model-curated authoring job over source Session logs; its artifact is a complete single-file Agent Skill directory plus the task and rubric that verify it, immutable from the moment it drafts. Requires a model_routing_profile_key logical name — there is no deterministic author — and each source Session may appear at most once. Returns the SkillProposal in authoring; accepts an optional Idempotency-Key.
Checkfu support posture: alpha; hosted. Required evidence journey: skill-delivery. Deployment-specific readiness and the latest proven release are available from GET /v1/support/capabilities.
curl --request POST \
--url https://api.checkfu.com/v1/skill-proposals \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'checkfu-version: <checkfu-version>' \
--data '
{
"source_session_ids": [
"<string>"
],
"model_routing_profile_key": "<string>",
"instructions": "<string>",
"skill_name": "<string>"
}
'import requests
url = "https://api.checkfu.com/v1/skill-proposals"
payload = {
"source_session_ids": ["<string>"],
"model_routing_profile_key": "<string>",
"instructions": "<string>",
"skill_name": "<string>"
}
headers = {
"checkfu-version": "<checkfu-version>",
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'checkfu-version': '<checkfu-version>',
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
source_session_ids: ['<string>'],
model_routing_profile_key: '<string>',
instructions: '<string>',
skill_name: '<string>'
})
};
fetch('https://api.checkfu.com/v1/skill-proposals', 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.checkfu.com/v1/skill-proposals",
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([
'source_session_ids' => [
'<string>'
],
'model_routing_profile_key' => '<string>',
'instructions' => '<string>',
'skill_name' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json",
"checkfu-version: <checkfu-version>"
],
]);
$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.checkfu.com/v1/skill-proposals"
payload := strings.NewReader("{\n \"source_session_ids\": [\n \"<string>\"\n ],\n \"model_routing_profile_key\": \"<string>\",\n \"instructions\": \"<string>\",\n \"skill_name\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("checkfu-version", "<checkfu-version>")
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://api.checkfu.com/v1/skill-proposals")
.header("checkfu-version", "<checkfu-version>")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"source_session_ids\": [\n \"<string>\"\n ],\n \"model_routing_profile_key\": \"<string>\",\n \"instructions\": \"<string>\",\n \"skill_name\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.checkfu.com/v1/skill-proposals")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["checkfu-version"] = '<checkfu-version>'
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"source_session_ids\": [\n \"<string>\"\n ],\n \"model_routing_profile_key\": \"<string>\",\n \"instructions\": \"<string>\",\n \"skill_name\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"id": "<string>",
"status": "authoring",
"source_session_ids": [
"<string>"
],
"agent": "<string>",
"model_routing_profile_key": "<string>",
"instructions": "<string>",
"skill": {
"name": "<string>",
"description": "<string>",
"kind": "instructional",
"entry": "<string>",
"content_sha256": "<string>"
},
"verification_material": {
"task": "<string>",
"rubric": "<string>"
},
"verifications": [
{
"session": "<string>",
"started_at": "<string>",
"result": {
"verdict": "satisfied",
"explanation": "<string>",
"cost_tokens": 1,
"completed_at": "<string>"
},
"source_version": 1,
"principal": "<string>",
"launched_at": "<string>"
}
],
"submission": {
"skill_source": "<string>",
"branch": "<string>",
"commit_sha": "<string>",
"submitted_at": "<string>"
},
"adoption": {
"skill_id": "<string>",
"skill_version": 1,
"observed_at": "<string>"
},
"error": "input_session_unavailable",
"usage": {
"input_tokens": 1,
"cached_input_tokens": 1,
"cache_write_input_tokens": 1,
"output_tokens": 1,
"reasoning_output_tokens": 1,
"total_tokens": 1
},
"created_at": "<string>",
"updated_at": "<string>",
"version": 1,
"submission_attempt": {
"source_version": 1,
"skill_source": "<string>",
"acted_as": "<string>",
"branch": "<string>",
"base_commit_sha": "<string>",
"base_content_sha256": "<string>",
"expected_base_digest": "<string>",
"prepared_commit_sha": "<string>",
"started_at": "<string>"
}
}{
"error": {
"type": "validation.malformed",
"message": "<string>",
"more": "https://docs.checkfu.com/reference/errors#validation-malformed"
}
}{
"error": {
"type": "auth.invalid_key",
"message": "<string>",
"more": "https://docs.checkfu.com/reference/errors#auth-invalid-key"
}
}{
"error": {
"type": "auth.disabled_tenancy",
"message": "<string>",
"more": "https://docs.checkfu.com/reference/errors#auth-disabled-tenancy"
}
}{
"error": {
"type": "validation.not_found",
"message": "<string>",
"more": "https://docs.checkfu.com/reference/errors#validation-not-found"
}
}{
"error": {
"type": "validation.idempotency_conflict",
"message": "<string>",
"more": "https://docs.checkfu.com/reference/errors#validation-idempotency-conflict"
}
}{
"error": {
"type": "model.no_eligible_model",
"message": "<string>",
"more": "https://docs.checkfu.com/reference/errors#model-no-eligible-model"
}
}{
"error": {
"type": "budget.exceeded",
"message": "<string>",
"more": "https://docs.checkfu.com/reference/errors#budget-exceeded"
}
}{
"error": {
"type": "runtime.internal",
"message": "<string>",
"more": "https://docs.checkfu.com/reference/errors#runtime-internal"
}
}Authorizations
Bearer authentication header of the form Bearer <token>, where <token> is your auth token.
Headers
2026-08-27 255Body
Response
an error exactly on authoring failure, an artifact exactly past authoring, a pending submission while submitting and optionally retained after submission for recovery, a completed submission exactly on submitted, adoption only after submission, and verification states only with a recorded attempt
^skp_[0-9a-f]{32}$authoring, drafted, authoring_failed, verifying, verified, verification_failed, submitting, submitted, discarded 1 - 8 elements^sess_[0-9a-f]{32}$^agent_[0-9a-f]{32}$^[a-z0-9](?:[a-z0-9._-]{0,93})$4096Show child attributes
Show child attributes
Show child attributes
Show child attributes
8Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
input_session_unavailable, input_sessions_too_large, authoring_failed, internal Show child attributes
Show child attributes
x > 0Show child attributes
Show child attributes