curl --request POST \
--url https://api.reasonmachines.com/v3/organizations/{orgId}/plugins/{slug}/sign-in/start \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"mcp_server_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"connection_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"reason_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"return_url": "<string>",
"idempotency_key": "<string>"
}
'import requests
url = "https://api.reasonmachines.com/v3/organizations/{orgId}/plugins/{slug}/sign-in/start"
payload = {
"mcp_server_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"connection_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"reason_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"return_url": "<string>",
"idempotency_key": "<string>"
}
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({
mcp_server_id: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
connection_id: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
reason_id: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
return_url: '<string>',
idempotency_key: '<string>'
})
};
fetch('https://api.reasonmachines.com/v3/organizations/{orgId}/plugins/{slug}/sign-in/start', 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}/plugins/{slug}/sign-in/start",
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([
'mcp_server_id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'connection_id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'reason_id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'return_url' => '<string>',
'idempotency_key' => '<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}/plugins/{slug}/sign-in/start"
payload := strings.NewReader("{\n \"mcp_server_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"connection_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"reason_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"return_url\": \"<string>\",\n \"idempotency_key\": \"<string>\"\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}/plugins/{slug}/sign-in/start")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"mcp_server_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"connection_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"reason_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"return_url\": \"<string>\",\n \"idempotency_key\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.reasonmachines.com/v3/organizations/{orgId}/plugins/{slug}/sign-in/start")
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 \"mcp_server_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"connection_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"reason_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"return_url\": \"<string>\",\n \"idempotency_key\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"sign_in_id": "<string>",
"status": "pending",
"authorize_url": "<string>",
"expires_at": "<string>",
"adapter": "mcp",
"plugin_slug": "<string>",
"mcp_server_id": "<string>",
"connection_id": "<string>",
"account_id": "<string>",
"account_name": "<string>",
"error_code": "<string>",
"error_message": "<string>",
"return_url": "<string>",
"completed_at": "<string>",
"created_at": "<string>"
}{
"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"
}
}Start a plugin sign-in
Starts the browser sign-in for an installed OAuth MCP plugin (catalog or custom HTTP server) or a native app connector and returns the provider’s consent authorize_url with a sign_in_id. Open the URL in the person’s browser, then poll getPluginSignIn. The path takes the plugin slug, or an installation’s mcp_server_id; with several installations, mcp_server_id, scope or reason_id picks one (default: the caller’s personal installation, else the workspace’s).
For an approved custom HTTP MCP server whose authorization server has no dynamic client registration, pass your own oauth_client, registered for the redirect_uri that inspectMcpServerEndpoint (or a 422 oauth_configuration_required here) returns. When sign-in ends, the browser goes to return_url (if given) with only sign_in_id, status, connection_id and error added. A retried start with the same idempotency_key returns the same sign-in. A new sign-in replaces the installation’s account only when it succeeds.
mcp:writecurl --request POST \
--url https://api.reasonmachines.com/v3/organizations/{orgId}/plugins/{slug}/sign-in/start \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"mcp_server_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"connection_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"reason_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"return_url": "<string>",
"idempotency_key": "<string>"
}
'import requests
url = "https://api.reasonmachines.com/v3/organizations/{orgId}/plugins/{slug}/sign-in/start"
payload = {
"mcp_server_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"connection_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"reason_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"return_url": "<string>",
"idempotency_key": "<string>"
}
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({
mcp_server_id: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
connection_id: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
reason_id: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
return_url: '<string>',
idempotency_key: '<string>'
})
};
fetch('https://api.reasonmachines.com/v3/organizations/{orgId}/plugins/{slug}/sign-in/start', 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}/plugins/{slug}/sign-in/start",
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([
'mcp_server_id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'connection_id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'reason_id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'return_url' => '<string>',
'idempotency_key' => '<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}/plugins/{slug}/sign-in/start"
payload := strings.NewReader("{\n \"mcp_server_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"connection_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"reason_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"return_url\": \"<string>\",\n \"idempotency_key\": \"<string>\"\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}/plugins/{slug}/sign-in/start")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"mcp_server_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"connection_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"reason_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"return_url\": \"<string>\",\n \"idempotency_key\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.reasonmachines.com/v3/organizations/{orgId}/plugins/{slug}/sign-in/start")
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 \"mcp_server_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"connection_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"reason_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"return_url\": \"<string>\",\n \"idempotency_key\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"sign_in_id": "<string>",
"status": "pending",
"authorize_url": "<string>",
"expires_at": "<string>",
"adapter": "mcp",
"plugin_slug": "<string>",
"mcp_server_id": "<string>",
"connection_id": "<string>",
"account_id": "<string>",
"account_name": "<string>",
"error_code": "<string>",
"error_message": "<string>",
"return_url": "<string>",
"completed_at": "<string>",
"created_at": "<string>"
}{
"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, devices:read, devices:write, devices:use, computers:read, computers:write, ssh:write, knowledge:read, memory:read, memory:write, skills:read, skills:write, pages:read, pages: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. devices:write, devices:use, computers:read, computers:write, ssh:write, network:read and network:write are opt-in, excluded from default keys. computers:read lists visible cloud and connected computers without waking them or granting execution access. devices:read discovers local Device targets; devices:use separately consents to local execution, so a discover-and-run local workflow needs both. devices:write manages enrollment and device grants; computers:write creates or deletes cloud computers; ssh:write manages retained SSH access. 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
Body
The MCP installation to sign in (from accounts). Omit to use the caller's personal installation of the plugin, else the workspace's (or the one in scope).
^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$Where the OAuth callback sends the browser when sign-in ends: https://, http://localhost or http://127.0.0.1, or an app scheme such as myapp://callback. javascript:, data:, vbscript:, file:, blob:, about:, protocol-relative URLs, backslashes, control characters and credentials are rejected. Reason sets only sign_in_id, status, connection_id and error on the redirect, never tokens or codes; parameters already in return_url are kept as they were.
2048Response
The pending sign-in (or the one this idempotency_key started).

