curl --request POST \
--url https://api.reasonmachines.com/v3/organizations/{orgId}/sessions/{sessionId}/cancel \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{
"mode": "hard"
}'import requests
url = "https://api.reasonmachines.com/v3/organizations/{orgId}/sessions/{sessionId}/cancel"
payload = { "mode": "hard" }
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({mode: 'hard'})
};
fetch('https://api.reasonmachines.com/v3/organizations/{orgId}/sessions/{sessionId}/cancel', 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}/sessions/{sessionId}/cancel",
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([
'mode' => 'hard'
]),
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}/sessions/{sessionId}/cancel"
payload := strings.NewReader("{\n \"mode\": \"hard\"\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}/sessions/{sessionId}/cancel")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"mode\": \"hard\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.reasonmachines.com/v3/organizations/{orgId}/sessions/{sessionId}/cancel")
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 \"mode\": \"hard\"\n}"
response = http.request(request)
puts response.read_body{
"ok": true,
"requested": true,
"status": "running",
"mode": "graceful"
}{
"error": "<string>",
"message": "<string>",
"required_scope": "<string>"
}{
"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"
}
}Cancel a session
Requests cancellation of a running session. The optional body selects the cancel mode: graceful (default, also used when the body is absent) stops the agent and tries to preserve the workspace with a final snapshot; hard stops immediately and relies on the last verified checkpoint. Sending hard while a graceful cancel is in progress upgrades it. Either way an explicitly cancelled Session ends suspended, never error. Returns whether the request newly flagged (or upgraded) the cancellation. Cancellation is asynchronous: requested: true means the stop is under way, and status is the Session’s status after this request, so it is suspended when the Session had not started and still running while a running Session stops. Poll the Session until its status leaves running.
runcurl --request POST \
--url https://api.reasonmachines.com/v3/organizations/{orgId}/sessions/{sessionId}/cancel \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{
"mode": "hard"
}'import requests
url = "https://api.reasonmachines.com/v3/organizations/{orgId}/sessions/{sessionId}/cancel"
payload = { "mode": "hard" }
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({mode: 'hard'})
};
fetch('https://api.reasonmachines.com/v3/organizations/{orgId}/sessions/{sessionId}/cancel', 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}/sessions/{sessionId}/cancel",
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([
'mode' => 'hard'
]),
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}/sessions/{sessionId}/cancel"
payload := strings.NewReader("{\n \"mode\": \"hard\"\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}/sessions/{sessionId}/cancel")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"mode\": \"hard\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.reasonmachines.com/v3/organizations/{orgId}/sessions/{sessionId}/cancel")
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 \"mode\": \"hard\"\n}"
response = http.request(request)
puts response.read_body{
"ok": true,
"requested": true,
"status": "running",
"mode": "graceful"
}{
"error": "<string>",
"message": "<string>",
"required_scope": "<string>"
}{
"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 session id, returned as session_id by createSession and listSessions.
Body
graceful (default) stops the agent and tries to preserve the workspace with a final snapshot before the Session ends. hard stops immediately without waiting for a snapshot; the Session resumes from its last verified checkpoint. A later hard request upgrades an in-progress graceful cancel.
graceful, hard Response
Cancellation requested.
True when this request newly flagged, or upgraded, the cancellation.
True when cancellation is requested for the Session, by this or an earlier request. The Session may still be stopping.
Public Session status read after this request: suspended once the Session has stopped (at once for a Session that had not started), running while a running Session is still stopping.
The cancel mode this request asked for.
graceful, hard 
