curl --request GET \
--url https://api.reasonmachines.com/v3/self \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.reasonmachines.com/v3/self"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.reasonmachines.com/v3/self', 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/self",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.reasonmachines.com/v3/self"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.reasonmachines.com/v3/self")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.reasonmachines.com/v3/self")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"principal_type": "service_user",
"service_user_id": "key_3f9a",
"service_user_name": "ci-bot",
"org_id": "org_8c2d1e",
"scopes": [
"run",
"sessions:read",
"repos:read"
]
}{
"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"
}
}Verify credentials
Returns the principal behind the current credential, its granted scopes, and the organization it can act on. Call this first to discover your org_id and available capabilities.
REST quickstart
A Reason is the long-running agent a person keeps: its own conversation, instructions, Loops (standing work woken by a schedule or an event) and the Sessions it runs. Give it work by messaging it.
- Create a key at reasonmachines.com/customize?tab=api (Settings > API). Send it only in
Authorization: Bearer <key>, never in a URL. - Call this endpoint and keep the returned
org_id. - List your Reasons with
GET /v3/organizations/{orgId}/reasons(sessions:read). Your main Reason comes first; create a named one withPOST /reasons(run). - Message it with
POST /v3/organizations/{orgId}/reasons/{reasonId}/messages(run) and read its replies withGETon the same path. Configure it withPATCH /reasons/{reasonId}(instructions, default model, default repositories), give it standing work withPOST /reasons/{reasonId}/loops(automations:write), and read or edit memory with/memory/files,/memory/fileand/memory/search(scope=personalfor the key owner’s own,teamfor the workspace’s;memory:read,memory:write). - For one unattended task, start a Session instead: POST a prompt to
/v3/organizations/{orgId}/sessionswithreason_id,completion_mode: run_outcomeand anidempotency_keyin the JSON body (HTTP 201 creates; 200 replays). Poll it with GET until status leaves running. Lifecycle exit does not prove success: only outcome success is a successful task; failure, action_required and null need handling. FollowRetry-Afteron HTTP 429.
Runnable Node.js example
Download api-session.mjs, review it, and run it with Node.js 20 or newer. It creates real work that may incur usage. Set REASON_API_KEY, REASON_PROMPT, and a stable REASON_IDEMPOTENCY_KEY in your environment, then run node api-session.mjs. Optional REASON_REPO and REASON_PROJECT_ID (a Reason id) select resources explicitly. The example exits nonzero for failed, suspended, unresolved, or action-required tasks and times out after ten minutes without cancelling the remote session.
MCP is a separate client connection
For an MCP client, connect to https://mcp.reasonmachines.com/mcp using that client’s supported OAuth setup. See Connect over MCP for the commands. The REST workflow above uses the HTTP API and does not require installing an MCP client.
curl --request GET \
--url https://api.reasonmachines.com/v3/self \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.reasonmachines.com/v3/self"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.reasonmachines.com/v3/self', 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/self",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.reasonmachines.com/v3/self"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.reasonmachines.com/v3/self")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.reasonmachines.com/v3/self")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"principal_type": "service_user",
"service_user_id": "key_3f9a",
"service_user_name": "ci-bot",
"org_id": "org_8c2d1e",
"scopes": [
"run",
"sessions:read",
"repos:read"
]
}{
"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).
Query Parameters
Include the current cloud activation state for this credential's workspace. Does not start work or reserve credit.
1 Response
The authenticated principal.
API keys resolve to service_user; MCP OAuth grants resolve to user.
service_user, user Organization pinned to the current credential.
Capabilities granted to the current API key or OAuth token.
Present when principal_type is service_user.
Present when principal_type is service_user.
Present when principal_type is user.
Present when principal_type is user.
Present when principal_type is user.
Display name of the organization pinned to this credential.
URL slug of the organization pinned to this credential.
Optional cloud entitlement read requested with cloud_activation=1. Null when this flow is unavailable; readiness does not reserve credit or compute.
Show child attributes
Show child attributes
Present only for an admin API key (its single scope is the admin scope): where that key's admin capabilities are documented.
Present when principal_type is user: active MCP OAuth client grants for the signed-in user and organization.
Show child attributes
Show child attributes

