curl --request PATCH \
--url https://api.reasonmachines.com/v3/organizations/{orgId}/reasons/{reasonId}/loops/{loopId} \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"prompt": "<string>",
"name": "<string>",
"enabled": true,
"schedule": "<string>",
"webhook": {
"signing_secret_name": "<string>",
"condition": "<string>"
},
"wake_on": [
{
"schedule": "0 9 * * 1-5"
},
{
"webhook": {}
}
],
"until": "2023-11-07T05:31:56Z",
"max_runs": 50000,
"session_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"device_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"timezone": "<string>",
"model": "<string>"
}
'import requests
url = "https://api.reasonmachines.com/v3/organizations/{orgId}/reasons/{reasonId}/loops/{loopId}"
payload = {
"prompt": "<string>",
"name": "<string>",
"enabled": True,
"schedule": "<string>",
"webhook": {
"signing_secret_name": "<string>",
"condition": "<string>"
},
"wake_on": [{ "schedule": "0 9 * * 1-5" }, { "webhook": {} }],
"until": "2023-11-07T05:31:56Z",
"max_runs": 50000,
"session_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"device_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"timezone": "<string>",
"model": "<string>"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.patch(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PATCH',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
prompt: '<string>',
name: '<string>',
enabled: true,
schedule: '<string>',
webhook: {signing_secret_name: '<string>', condition: '<string>'},
wake_on: [{schedule: '0 9 * * 1-5'}, {webhook: {}}],
until: '2023-11-07T05:31:56Z',
max_runs: 50000,
session_id: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
device_id: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
timezone: '<string>',
model: '<string>'
})
};
fetch('https://api.reasonmachines.com/v3/organizations/{orgId}/reasons/{reasonId}/loops/{loopId}', 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}/reasons/{reasonId}/loops/{loopId}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PATCH",
CURLOPT_POSTFIELDS => json_encode([
'prompt' => '<string>',
'name' => '<string>',
'enabled' => true,
'schedule' => '<string>',
'webhook' => [
'signing_secret_name' => '<string>',
'condition' => '<string>'
],
'wake_on' => [
[
'schedule' => '0 9 * * 1-5'
],
[
'webhook' => [
]
]
],
'until' => '2023-11-07T05:31:56Z',
'max_runs' => 50000,
'session_id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'device_id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'timezone' => '<string>',
'model' => '<string>'
]),
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}/reasons/{reasonId}/loops/{loopId}"
payload := strings.NewReader("{\n \"prompt\": \"<string>\",\n \"name\": \"<string>\",\n \"enabled\": true,\n \"schedule\": \"<string>\",\n \"webhook\": {\n \"signing_secret_name\": \"<string>\",\n \"condition\": \"<string>\"\n },\n \"wake_on\": [\n {\n \"schedule\": \"0 9 * * 1-5\"\n },\n {\n \"webhook\": {}\n }\n ],\n \"until\": \"2023-11-07T05:31:56Z\",\n \"max_runs\": 50000,\n \"session_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"device_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"timezone\": \"<string>\",\n \"model\": \"<string>\"\n}")
req, _ := http.NewRequest("PATCH", 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.patch("https://api.reasonmachines.com/v3/organizations/{orgId}/reasons/{reasonId}/loops/{loopId}")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"prompt\": \"<string>\",\n \"name\": \"<string>\",\n \"enabled\": true,\n \"schedule\": \"<string>\",\n \"webhook\": {\n \"signing_secret_name\": \"<string>\",\n \"condition\": \"<string>\"\n },\n \"wake_on\": [\n {\n \"schedule\": \"0 9 * * 1-5\"\n },\n {\n \"webhook\": {}\n }\n ],\n \"until\": \"2023-11-07T05:31:56Z\",\n \"max_runs\": 50000,\n \"session_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"device_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"timezone\": \"<string>\",\n \"model\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.reasonmachines.com/v3/organizations/{orgId}/reasons/{reasonId}/loops/{loopId}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Patch.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"prompt\": \"<string>\",\n \"name\": \"<string>\",\n \"enabled\": true,\n \"schedule\": \"<string>\",\n \"webhook\": {\n \"signing_secret_name\": \"<string>\",\n \"condition\": \"<string>\"\n },\n \"wake_on\": [\n {\n \"schedule\": \"0 9 * * 1-5\"\n },\n {\n \"webhook\": {}\n }\n ],\n \"until\": \"2023-11-07T05:31:56Z\",\n \"max_runs\": 50000,\n \"session_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"device_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"timezone\": \"<string>\",\n \"model\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"loop": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"reason_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"name": "<string>",
"prompt": "<string>",
"enabled": true,
"status": "active",
"paused_reason": "<string>",
"schedule": {
"kind": "every",
"expression": "<string>",
"every_seconds": 123,
"timezone": "<string>",
"next_run_at": "2023-11-07T05:31:56Z"
},
"slack": {},
"execution_mode": "session",
"session_id": "<string>",
"latest_session_id": "<string>",
"device_id": "<string>",
"repository": "<string>",
"model": "<string>",
"notification_policy": "important_updates",
"until": "2023-11-07T05:31:56Z",
"max_runs": 123,
"run_count": 123,
"last_run": {
"status": "<string>",
"at": "<string>",
"session_id": "<string>"
},
"created_by_user_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"trigger_description": "<string>",
"wakes_on": [
{
"kind": "schedule",
"description": "<string>"
}
],
"event_trigger": {
"kind": "webhook",
"url": "<string>"
},
"viewer_access": {
"edit": true,
"stop": true
}
},
"webhook": {
"url": "<string>",
"key": "<string>"
}
}{
"error": "prompt_required"
}{
"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 Loop
Partial update. A paused Loop resumes from its next slot. wake_on replaces everything that wakes the Loop (send it alone, or with name, prompt, notification_policy, until, max_runs and model; a single entry of the kind already waking it changes that in place); a webhook it adds returns its URL and key once, as on create. Switching the Loop on, or onto another Session or model, checks the workspace can fund it (402 loop_model_not_fundable). Who sees and changes a Loop follows its Reason: the people who can use the Reason see and change its Loops, except that a teammate’s Loop on a team Reason stays that teammate’s (the Reason’s owner may see and stop it). Workspace owners and admins may pause and delete any Loop.What a Loop runs in (its Session or computer), its Slack channels and what wakes it stay with its creator, since each is checked against their access (403 loop_creator_only_change).
automations:writecurl --request PATCH \
--url https://api.reasonmachines.com/v3/organizations/{orgId}/reasons/{reasonId}/loops/{loopId} \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"prompt": "<string>",
"name": "<string>",
"enabled": true,
"schedule": "<string>",
"webhook": {
"signing_secret_name": "<string>",
"condition": "<string>"
},
"wake_on": [
{
"schedule": "0 9 * * 1-5"
},
{
"webhook": {}
}
],
"until": "2023-11-07T05:31:56Z",
"max_runs": 50000,
"session_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"device_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"timezone": "<string>",
"model": "<string>"
}
'import requests
url = "https://api.reasonmachines.com/v3/organizations/{orgId}/reasons/{reasonId}/loops/{loopId}"
payload = {
"prompt": "<string>",
"name": "<string>",
"enabled": True,
"schedule": "<string>",
"webhook": {
"signing_secret_name": "<string>",
"condition": "<string>"
},
"wake_on": [{ "schedule": "0 9 * * 1-5" }, { "webhook": {} }],
"until": "2023-11-07T05:31:56Z",
"max_runs": 50000,
"session_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"device_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"timezone": "<string>",
"model": "<string>"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.patch(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PATCH',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
prompt: '<string>',
name: '<string>',
enabled: true,
schedule: '<string>',
webhook: {signing_secret_name: '<string>', condition: '<string>'},
wake_on: [{schedule: '0 9 * * 1-5'}, {webhook: {}}],
until: '2023-11-07T05:31:56Z',
max_runs: 50000,
session_id: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
device_id: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
timezone: '<string>',
model: '<string>'
})
};
fetch('https://api.reasonmachines.com/v3/organizations/{orgId}/reasons/{reasonId}/loops/{loopId}', 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}/reasons/{reasonId}/loops/{loopId}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PATCH",
CURLOPT_POSTFIELDS => json_encode([
'prompt' => '<string>',
'name' => '<string>',
'enabled' => true,
'schedule' => '<string>',
'webhook' => [
'signing_secret_name' => '<string>',
'condition' => '<string>'
],
'wake_on' => [
[
'schedule' => '0 9 * * 1-5'
],
[
'webhook' => [
]
]
],
'until' => '2023-11-07T05:31:56Z',
'max_runs' => 50000,
'session_id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'device_id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'timezone' => '<string>',
'model' => '<string>'
]),
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}/reasons/{reasonId}/loops/{loopId}"
payload := strings.NewReader("{\n \"prompt\": \"<string>\",\n \"name\": \"<string>\",\n \"enabled\": true,\n \"schedule\": \"<string>\",\n \"webhook\": {\n \"signing_secret_name\": \"<string>\",\n \"condition\": \"<string>\"\n },\n \"wake_on\": [\n {\n \"schedule\": \"0 9 * * 1-5\"\n },\n {\n \"webhook\": {}\n }\n ],\n \"until\": \"2023-11-07T05:31:56Z\",\n \"max_runs\": 50000,\n \"session_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"device_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"timezone\": \"<string>\",\n \"model\": \"<string>\"\n}")
req, _ := http.NewRequest("PATCH", 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.patch("https://api.reasonmachines.com/v3/organizations/{orgId}/reasons/{reasonId}/loops/{loopId}")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"prompt\": \"<string>\",\n \"name\": \"<string>\",\n \"enabled\": true,\n \"schedule\": \"<string>\",\n \"webhook\": {\n \"signing_secret_name\": \"<string>\",\n \"condition\": \"<string>\"\n },\n \"wake_on\": [\n {\n \"schedule\": \"0 9 * * 1-5\"\n },\n {\n \"webhook\": {}\n }\n ],\n \"until\": \"2023-11-07T05:31:56Z\",\n \"max_runs\": 50000,\n \"session_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"device_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"timezone\": \"<string>\",\n \"model\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.reasonmachines.com/v3/organizations/{orgId}/reasons/{reasonId}/loops/{loopId}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Patch.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"prompt\": \"<string>\",\n \"name\": \"<string>\",\n \"enabled\": true,\n \"schedule\": \"<string>\",\n \"webhook\": {\n \"signing_secret_name\": \"<string>\",\n \"condition\": \"<string>\"\n },\n \"wake_on\": [\n {\n \"schedule\": \"0 9 * * 1-5\"\n },\n {\n \"webhook\": {}\n }\n ],\n \"until\": \"2023-11-07T05:31:56Z\",\n \"max_runs\": 50000,\n \"session_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"device_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"timezone\": \"<string>\",\n \"model\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"loop": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"reason_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"name": "<string>",
"prompt": "<string>",
"enabled": true,
"status": "active",
"paused_reason": "<string>",
"schedule": {
"kind": "every",
"expression": "<string>",
"every_seconds": 123,
"timezone": "<string>",
"next_run_at": "2023-11-07T05:31:56Z"
},
"slack": {},
"execution_mode": "session",
"session_id": "<string>",
"latest_session_id": "<string>",
"device_id": "<string>",
"repository": "<string>",
"model": "<string>",
"notification_policy": "important_updates",
"until": "2023-11-07T05:31:56Z",
"max_runs": 123,
"run_count": 123,
"last_run": {
"status": "<string>",
"at": "<string>",
"session_id": "<string>"
},
"created_by_user_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"trigger_description": "<string>",
"wakes_on": [
{
"kind": "schedule",
"description": "<string>"
}
],
"event_trigger": {
"kind": "webhook",
"url": "<string>"
},
"viewer_access": {
"edit": true,
"stop": true
}
},
"webhook": {
"url": "<string>",
"key": "<string>"
}
}{
"error": "prompt_required"
}{
"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 Reason id, returned as id by listReasons and createReason.
The Loop id, returned as id by listReasonLoops and as loop.id by createReasonLoop.
Body
Only the fields sent change. wake_on replaces what wakes the Loop; send it with only name, prompt, notification_policy, until, max_runs and model.
New instructions for its future wakes.
1 - 1000001 - 200false pauses it; true resumes it from its next slot.
A new schedule for a Loop that has one, in the same forms as a wake_on schedule.
1 - 500A webhook Loop's signing secret or condition, changed in place.
Show child attributes
Show child attributes
Everything that wakes the Loop: at most one schedule, one webhook and one Slack listener, and GitHub events on one repository. A Loop woken by several things at once is in early access for some workspaces (403 wake_on_unavailable elsewhere). On update it replaces what wakes the Loop.
1 - 8 elementsWake on a schedule.
- Option 1
- Option 2
- Option 3
- Option 4
Show child attributes
Show child attributes
[
{ "schedule": "0 9 * * 1-5" },
{ "webhook": {} }
]
End of a scheduled Loop: no wake after this time, then it reads completed. null clears it. A Loop woken by events has no end of its own.
How many runs a scheduled Loop makes before it reads completed, counted from when it is set. null clears it.
1 <= x <= 100000session continues one Session across wakes, the one in session_id or else one of the Loop's own that its first wake opens; new_session opens a fresh Session on every wake. A Loop woken by events opens a Session per event (events sharing a correlation key continue one), so it takes neither.
session, new_session An existing Session of the caller's that each wake continues. null unbinds it.
A connected computer of the caller's (listDevices) that its runs use; null runs them on a Reason cloud machine.
When the Loop tells the person about a run: on important updates (the default) or only when a run fails.
important_updates, failed_runs_only IANA time zone a cron schedule is read in, such as America/Los_Angeles. Defaults to UTC, or keeps the Loop's own on update.
1 - 120Model its runs use, as a Session model id. null or auto runs it on the model of the Session it continues, or the workspace's. An id the workspace cannot pin returns 400 invalid_model.
1 - 200Response
The updated Loop, and a webhook it just gave out.
The Loop as saved, and the webhook it just gave out, when it did.

