curl --request POST \
--url https://api.reasonmachines.com/v3/organizations/{orgId}/automations \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"name": "Nightly dependency audit",
"instructions": "Audit dependencies for known CVEs and open a PR if any need patching.",
"repo": "acme/widget",
"provider": "github"
}
'import requests
url = "https://api.reasonmachines.com/v3/organizations/{orgId}/automations"
payload = {
"name": "Nightly dependency audit",
"instructions": "Audit dependencies for known CVEs and open a PR if any need patching.",
"repo": "acme/widget",
"provider": "github"
}
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({
name: 'Nightly dependency audit',
instructions: 'Audit dependencies for known CVEs and open a PR if any need patching.',
repo: 'acme/widget',
provider: 'github'
})
};
fetch('https://api.reasonmachines.com/v3/organizations/{orgId}/automations', 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}/automations",
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' => 'Nightly dependency audit',
'instructions' => 'Audit dependencies for known CVEs and open a PR if any need patching.',
'repo' => 'acme/widget',
'provider' => 'github'
]),
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}/automations"
payload := strings.NewReader("{\n \"name\": \"Nightly dependency audit\",\n \"instructions\": \"Audit dependencies for known CVEs and open a PR if any need patching.\",\n \"repo\": \"acme/widget\",\n \"provider\": \"github\"\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://api.reasonmachines.com/v3/organizations/{orgId}/automations")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"Nightly dependency audit\",\n \"instructions\": \"Audit dependencies for known CVEs and open a PR if any need patching.\",\n \"repo\": \"acme/widget\",\n \"provider\": \"github\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.reasonmachines.com/v3/organizations/{orgId}/automations")
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 \"name\": \"Nightly dependency audit\",\n \"instructions\": \"Audit dependencies for known CVEs and open a PR if any need patching.\",\n \"repo\": \"acme/widget\",\n \"provider\": \"github\"\n}"
response = http.request(request)
puts response.read_body{
"id": "automation_example",
"org_id": "org_example",
"name": "Daily repository review",
"instructions": "Review open issues.",
"model": null,
"enabled": true,
"tools": {
"mcp_servers": null,
"app_tools": []
},
"environment": {
"repo": "example/project",
"provider": "github"
},
"triggers": [
{
"id": "trigger_example",
"kind": "schedule",
"enabled": true,
"schedule": {
"kind": "cron",
"expression": "0 9 * * *",
"every_seconds": null,
"next_run_at": "2026-09-24T09:00:00Z"
},
"github": null,
"webhook": null,
"run_kind": null,
"last_fired_at": null,
"created_at": "2026-09-01T00:00:00Z",
"updated_at": "2026-09-01T00:00:00Z"
}
],
"created_at": "2026-09-01T00:00:00Z",
"updated_at": "2026-09-01T00:00:00Z"
}{
"error": "prompt_required"
}{
"error": "missing_bearer",
"message": "Authorization required"
}{
"error": "missing_scope",
"required_scope": "sessions:read"
}{
"error": {
"type": "rate_limited",
"message": "This API key exceeded its request-rate limit"
}
}Create an automation
Send name and direct to atomically configure a tool_call, job, or explicit agent_task with its schedule and bounded limits; direct actions require their execution scopes and create no reasoning Session unless agent_task. Otherwise creates the automation’s configuration (instructions + an optional repository). Add a trigger with POST /automations/{automationId}/triggers to make it fire. A repo, when sent, must already be connected (400 repo_not_connected); without one the automation’s runs start with no repository checked out. It is created enabled unless enabled: false is sent; a paused automation’s triggers do not fire until it is enabled with an update. Name and instructions are trimmed and may not be blank; tools must name MCP servers the workspace has and known app tools (see the field descriptions for each 400 code). A known app tool that is not connected yet is accepted with an app_tool_not_connected entry in warnings.
automations:writecurl --request POST \
--url https://api.reasonmachines.com/v3/organizations/{orgId}/automations \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"name": "Nightly dependency audit",
"instructions": "Audit dependencies for known CVEs and open a PR if any need patching.",
"repo": "acme/widget",
"provider": "github"
}
'import requests
url = "https://api.reasonmachines.com/v3/organizations/{orgId}/automations"
payload = {
"name": "Nightly dependency audit",
"instructions": "Audit dependencies for known CVEs and open a PR if any need patching.",
"repo": "acme/widget",
"provider": "github"
}
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({
name: 'Nightly dependency audit',
instructions: 'Audit dependencies for known CVEs and open a PR if any need patching.',
repo: 'acme/widget',
provider: 'github'
})
};
fetch('https://api.reasonmachines.com/v3/organizations/{orgId}/automations', 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}/automations",
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' => 'Nightly dependency audit',
'instructions' => 'Audit dependencies for known CVEs and open a PR if any need patching.',
'repo' => 'acme/widget',
'provider' => 'github'
]),
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}/automations"
payload := strings.NewReader("{\n \"name\": \"Nightly dependency audit\",\n \"instructions\": \"Audit dependencies for known CVEs and open a PR if any need patching.\",\n \"repo\": \"acme/widget\",\n \"provider\": \"github\"\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://api.reasonmachines.com/v3/organizations/{orgId}/automations")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"Nightly dependency audit\",\n \"instructions\": \"Audit dependencies for known CVEs and open a PR if any need patching.\",\n \"repo\": \"acme/widget\",\n \"provider\": \"github\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.reasonmachines.com/v3/organizations/{orgId}/automations")
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 \"name\": \"Nightly dependency audit\",\n \"instructions\": \"Audit dependencies for known CVEs and open a PR if any need patching.\",\n \"repo\": \"acme/widget\",\n \"provider\": \"github\"\n}"
response = http.request(request)
puts response.read_body{
"id": "automation_example",
"org_id": "org_example",
"name": "Daily repository review",
"instructions": "Review open issues.",
"model": null,
"enabled": true,
"tools": {
"mcp_servers": null,
"app_tools": []
},
"environment": {
"repo": "example/project",
"provider": "github"
},
"triggers": [
{
"id": "trigger_example",
"kind": "schedule",
"enabled": true,
"schedule": {
"kind": "cron",
"expression": "0 9 * * *",
"every_seconds": null,
"next_run_at": "2026-09-24T09:00:00Z"
},
"github": null,
"webhook": null,
"run_kind": null,
"last_fired_at": null,
"created_at": "2026-09-01T00:00:00Z",
"updated_at": "2026-09-01T00:00:00Z"
}
],
"created_at": "2026-09-01T00:00:00Z",
"updated_at": "2026-09-01T00:00:00Z"
}{
"error": "prompt_required"
}{
"error": "missing_bearer",
"message": "Authorization required"
}{
"error": "missing_scope",
"required_scope": "sessions:read"
}{
"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.
Body
- Option 1
- Option 2
Creates the automation's configuration. It has no triggers until you add one via POST /automations/{automationId}/triggers, so it will not fire on its own yet.
The task each run carries out when a trigger fires, written as the prompt the agent receives.
100000Show child attributes
Show child attributes
Label that identifies the automation in lists and audit entries. Omit it to name the automation after the start of instructions.
200Connected GitHub repository, as owner/name, that each run checks out and works in; listRepositories lists the connected ones. Omit it for an automation whose runs start with no repository.
Source-control host of repo, sent only together with it; on its own it returns 400 repo_required. Omit it to look the host up from the connected repositories.
github Model override. null uses the workspace default. New runs accept only the currently available Reason model catalog.
Show child attributes
Show child attributes
Whether the automation starts active. Send false to create it paused: its triggers never fire until an update sets enabled: true.
Response
Created.
An automation: its instructions, tools, environment binding, and triggers.
Automation id; pass it as automationId to read, update, delete or add triggers.
Workspace the automation belongs to.
Label that identifies the automation.
The system instructions the automation runs with.
Model override for its runs; null uses the workspace default.
A paused (false) automation's triggers never fire.
Tools the automation's runs may use.
Show child attributes
Show child attributes
Repository each run starts in; repo is null for an automation without one.
Show child attributes
Show child attributes
Every condition that fires this automation. Empty until you add one.
Show child attributes
Show child attributes
Present only when the request was accepted but something is not as sent or not usable yet. Codes: schedule_interval_raised, app_tool_not_connected.
Show child attributes
Show child attributes
When the automation was created.
When the automation's configuration last changed.

