curl --request PUT \
--url https://api.reasonmachines.com/v3/organizations/{orgId}/skills/{skillId} \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"name": "<string>",
"description": "<string>",
"instructions": "<string>",
"activation_keywords": [
"<string>"
],
"is_enabled": true
}
'import requests
url = "https://api.reasonmachines.com/v3/organizations/{orgId}/skills/{skillId}"
payload = {
"name": "<string>",
"description": "<string>",
"instructions": "<string>",
"activation_keywords": ["<string>"],
"is_enabled": True
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.put(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PUT',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
name: '<string>',
description: '<string>',
instructions: '<string>',
activation_keywords: ['<string>'],
is_enabled: true
})
};
fetch('https://api.reasonmachines.com/v3/organizations/{orgId}/skills/{skillId}', 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.reasonmachines.com/v3/organizations/{orgId}/skills/{skillId}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PUT",
CURLOPT_POSTFIELDS => json_encode([
'name' => '<string>',
'description' => '<string>',
'instructions' => '<string>',
'activation_keywords' => [
'<string>'
],
'is_enabled' => true
]),
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://api.reasonmachines.com/v3/organizations/{orgId}/skills/{skillId}"
payload := strings.NewReader("{\n \"name\": \"<string>\",\n \"description\": \"<string>\",\n \"instructions\": \"<string>\",\n \"activation_keywords\": [\n \"<string>\"\n ],\n \"is_enabled\": true\n}")
req, _ := http.NewRequest("PUT", 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.put("https://api.reasonmachines.com/v3/organizations/{orgId}/skills/{skillId}")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"<string>\",\n \"description\": \"<string>\",\n \"instructions\": \"<string>\",\n \"activation_keywords\": [\n \"<string>\"\n ],\n \"is_enabled\": true\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.reasonmachines.com/v3/organizations/{orgId}/skills/{skillId}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Put.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"name\": \"<string>\",\n \"description\": \"<string>\",\n \"instructions\": \"<string>\",\n \"activation_keywords\": [\n \"<string>\"\n ],\n \"is_enabled\": true\n}"
response = http.request(request)
puts response.read_body{
"skill_id": "skill_example",
"name": "Release checklist",
"description": "Use when preparing a release.",
"instructions": "Run the repository's release checks before deploying.",
"activation_keywords": [
"release"
],
"is_enabled": true,
"author": "user",
"provenance": "authored",
"created_by": "user_example",
"created_at": "2026-09-01T00:00:00Z",
"updated_at": "2026-09-01T00:00:00Z"
}{
"error": "missing_bearer",
"message": "Authorization required"
}{
"error": "missing_scope",
"required_scope": "sessions:read"
}{
"error": "session_not_found"
}{
"error": {
"type": "rate_limited",
"message": "This API key exceeded its request-rate limit"
}
}Update a skill
Partially updates an authored skill. Installed package and integration skills are read-only. Send only the fields you want to change.
Scope:skills:writecurl --request PUT \
--url https://api.reasonmachines.com/v3/organizations/{orgId}/skills/{skillId} \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"name": "<string>",
"description": "<string>",
"instructions": "<string>",
"activation_keywords": [
"<string>"
],
"is_enabled": true
}
'import requests
url = "https://api.reasonmachines.com/v3/organizations/{orgId}/skills/{skillId}"
payload = {
"name": "<string>",
"description": "<string>",
"instructions": "<string>",
"activation_keywords": ["<string>"],
"is_enabled": True
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.put(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PUT',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
name: '<string>',
description: '<string>',
instructions: '<string>',
activation_keywords: ['<string>'],
is_enabled: true
})
};
fetch('https://api.reasonmachines.com/v3/organizations/{orgId}/skills/{skillId}', 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.reasonmachines.com/v3/organizations/{orgId}/skills/{skillId}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PUT",
CURLOPT_POSTFIELDS => json_encode([
'name' => '<string>',
'description' => '<string>',
'instructions' => '<string>',
'activation_keywords' => [
'<string>'
],
'is_enabled' => true
]),
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://api.reasonmachines.com/v3/organizations/{orgId}/skills/{skillId}"
payload := strings.NewReader("{\n \"name\": \"<string>\",\n \"description\": \"<string>\",\n \"instructions\": \"<string>\",\n \"activation_keywords\": [\n \"<string>\"\n ],\n \"is_enabled\": true\n}")
req, _ := http.NewRequest("PUT", 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.put("https://api.reasonmachines.com/v3/organizations/{orgId}/skills/{skillId}")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"<string>\",\n \"description\": \"<string>\",\n \"instructions\": \"<string>\",\n \"activation_keywords\": [\n \"<string>\"\n ],\n \"is_enabled\": true\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.reasonmachines.com/v3/organizations/{orgId}/skills/{skillId}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Put.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"name\": \"<string>\",\n \"description\": \"<string>\",\n \"instructions\": \"<string>\",\n \"activation_keywords\": [\n \"<string>\"\n ],\n \"is_enabled\": true\n}"
response = http.request(request)
puts response.read_body{
"skill_id": "skill_example",
"name": "Release checklist",
"description": "Use when preparing a release.",
"instructions": "Run the repository's release checks before deploying.",
"activation_keywords": [
"release"
],
"is_enabled": true,
"author": "user",
"provenance": "authored",
"created_by": "user_example",
"created_at": "2026-09-01T00:00:00Z",
"updated_at": "2026-09-01T00:00:00Z"
}{
"error": "missing_bearer",
"message": "Authorization required"
}{
"error": "missing_scope",
"required_scope": "sessions:read"
}{
"error": "session_not_found"
}{
"error": {
"type": "rate_limited",
"message": "This API key exceeded its request-rate limit"
}
}Authorizations
Your Reason API key from Settings › API keys. New keys use reason_; legacy ara_ keys remain accepted. Keys are capability-scoped: run, mcp:read, mcp:write, secrets:read, secrets:write, sessions:read, sessions:debug, knowledge:read, memory:read, memory:write, skills:read, skills:write, repos:read, repos:write, reviews:read, reviews:write, deployment:read, analytics:read, org:read, org:write, attachments:read, attachments:write, guardrails:read, guardrails:write, network:read, network:write, automations:read, automations:write, agent_auth:read. network:read and network:write are opt-in, excluded from default keys. network:read reads the saved workspace network policy; network:write replaces custom allowed hosts and requires a current organization owner/admin. Legacy project PATCH requests containing network_allowed_hosts also require network:write plus their existing run scope and project management permission; saved project hosts do not affect current session egress. Only owners/admins can mint or manage keys with network:write; keys cannot grant themselves more authority. See /docs/network-policies for replacement semantics and runtime applicability. mcp:write manages MCP server configuration only; it does not authorize remote MCP-tool execution. sessions:read reads sessions, including the assistant, reasoning and tool activity in their events. sessions:debug is privileged: only for organization owners/admins, it expands session events to the full diagnostic projection (diagnostic event kinds, status text and raw event metadata).
Path Parameters
Organization id or slug. Resolve it with GET /v3/self.
The skill id, returned as skill_id by listSkills and createSkill.
Body
All fields optional. Only supplied fields are changed.
New display name; a name another skill already uses returns 409. Omit it to keep the current name.
New text saying what the skill does and when an agent should use it; Reason matches it against the task to pick skills. Omit it to keep the current text.
New skill document, replacing the old one whole, that an agent follows once the skill is picked. Omit it to keep the current document.
Replacement list of search aliases, kept for compatibility: they help explicit search but never activate the skill. Omit it to keep the current list.
Send false to stop agents from using the skill, or true to offer it again; omit it to keep the current state.
Response
Updated.
Skill id; pass it as skillId to read, update or delete the skill.
Display name of the skill.
What the skill does and when an agent should use it. Reason uses this description for semantic selection.
The skill document an agent follows when it uses the skill.
Optional search aliases retained for compatibility. They do not activate the skill automatically.
Whether agents may use the skill.
Whether only its creator sees the skill, or the whole workspace.
personal, organization Who wrote the skill: user for one authored in the workspace, otherwise its publisher.
Where the skill came from, which decides what can be edited or deleted.
authored, skills_sh, git, agent_plugin, curated_integration, builtin User id of the member who added it; null when no member added it.
When the skill was added.
When the skill last changed.

