curl --request PUT \
--url https://api.onecli.sh/v1/agents/{agentId}/grants/connections/{connectionId} \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"access": "full",
"resources": {
"repositories": [
"<string>"
]
}
}
'import requests
url = "https://api.onecli.sh/v1/agents/{agentId}/grants/connections/{connectionId}"
payload = {
"access": "full",
"resources": { "repositories": ["<string>"] }
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.put(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PUT',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({access: 'full', resources: {repositories: ['<string>']}})
};
fetch('https://api.onecli.sh/v1/agents/{agentId}/grants/connections/{connectionId}', 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.onecli.sh/v1/agents/{agentId}/grants/connections/{connectionId}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PUT",
CURLOPT_POSTFIELDS => json_encode([
'access' => 'full',
'resources' => [
'repositories' => [
'<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.onecli.sh/v1/agents/{agentId}/grants/connections/{connectionId}"
payload := strings.NewReader("{\n \"access\": \"full\",\n \"resources\": {\n \"repositories\": [\n \"<string>\"\n ]\n }\n}")
req, _ := http.NewRequest("PUT", 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.put("https://api.onecli.sh/v1/agents/{agentId}/grants/connections/{connectionId}")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"access\": \"full\",\n \"resources\": {\n \"repositories\": [\n \"<string>\"\n ]\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.onecli.sh/v1/agents/{agentId}/grants/connections/{connectionId}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Put.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"access\": \"full\",\n \"resources\": {\n \"repositories\": [\n \"<string>\"\n ]\n }\n}"
response = http.request(request)
puts response.read_body{
"agentId": "<string>",
"mode": "all",
"connections": [
{
"connectionId": "<string>",
"provider": "<string>",
"label": "<string>",
"scope": "workspace",
"access": "full",
"allow": [
"<string>"
],
"ask": [
"<string>"
],
"resources": {
"repositories": [
"<string>"
]
}
}
],
"secrets": [
{
"secretId": "<string>",
"name": "<string>",
"type": "<string>",
"scope": "workspace"
}
]
}{
"error": "<string>"
}{
"error": "<string>"
}{
"error": "<string>"
}Attach an app connection to an agent
Attaches an app connection to an agent or changes what it may do with it. Pick full access or custom tool lists. It applies immediately.
curl --request PUT \
--url https://api.onecli.sh/v1/agents/{agentId}/grants/connections/{connectionId} \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"access": "full",
"resources": {
"repositories": [
"<string>"
]
}
}
'import requests
url = "https://api.onecli.sh/v1/agents/{agentId}/grants/connections/{connectionId}"
payload = {
"access": "full",
"resources": { "repositories": ["<string>"] }
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.put(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PUT',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({access: 'full', resources: {repositories: ['<string>']}})
};
fetch('https://api.onecli.sh/v1/agents/{agentId}/grants/connections/{connectionId}', 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.onecli.sh/v1/agents/{agentId}/grants/connections/{connectionId}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PUT",
CURLOPT_POSTFIELDS => json_encode([
'access' => 'full',
'resources' => [
'repositories' => [
'<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.onecli.sh/v1/agents/{agentId}/grants/connections/{connectionId}"
payload := strings.NewReader("{\n \"access\": \"full\",\n \"resources\": {\n \"repositories\": [\n \"<string>\"\n ]\n }\n}")
req, _ := http.NewRequest("PUT", 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.put("https://api.onecli.sh/v1/agents/{agentId}/grants/connections/{connectionId}")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"access\": \"full\",\n \"resources\": {\n \"repositories\": [\n \"<string>\"\n ]\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.onecli.sh/v1/agents/{agentId}/grants/connections/{connectionId}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Put.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"access\": \"full\",\n \"resources\": {\n \"repositories\": [\n \"<string>\"\n ]\n }\n}"
response = http.request(request)
puts response.read_body{
"agentId": "<string>",
"mode": "all",
"connections": [
{
"connectionId": "<string>",
"provider": "<string>",
"label": "<string>",
"scope": "workspace",
"access": "full",
"allow": [
"<string>"
],
"ask": [
"<string>"
],
"resources": {
"repositories": [
"<string>"
]
}
}
],
"secrets": [
{
"secretId": "<string>",
"name": "<string>",
"type": "<string>",
"scope": "workspace"
}
]
}{
"error": "<string>"
}{
"error": "<string>"
}{
"error": "<string>"
}full for every tool, or custom with allow for tools that run freely and ask for tools that pause for approval. See Agent access.
Attach an app connection to an agent, or change what the agent may do with it. Takes effect immediately — there is no draft/publish step.
Send {"access": "full"} for every tool the app supports, or {"access": "custom", "allow": [...], "ask": [...]} to name tools: allow runs freely, ask pauses each call for human approval, and everything unnamed is blocked. Add resources to scope the credential to specific repositories or folders (Enterprise).
Authorizations
A workspace API key (oc_…) or organization API key (oc_org_…). Workspace-scoped endpoints called with an organization key also need X-Workspace-Id.
Body
- Full access
- Custom access
The grant to write. Two forms:
{"access": "full"}— every tool the app supports.{"access": "custom", "allow": [...], "ask": [...]}— named tools only.allowruns freely,askpauses for human approval, everything unnamed is blocked.
Validation laws on custom: the two lists together must name at least one tool (an all-blocked grant is a detach — use DELETE), and a tool can't appear in both lists. Tool ids come from GET /apps/{provider}/permission-definition.
resources is tri-state on both forms: omit it to keep the current scoping, send null to clear it, or send a session-policy object to set it. Setting resources is an Enterprise feature (resource-level access).
full Resource scoping for a connection's credential ("Resources"): an object keyed by the provider's resource axis. Exactly one key: repositories (GitHub, owner/repo), folders (Dropbox, absolute paths), or driveFolders (Google Drive, folder-id chains). Lists must be non-empty.
- GitHub repositories
- Dropbox folders
- Google Drive folders
Show child attributes
Show child attributes
Response
The agent's updated grant set
An agent's full grant set — returned by grant reads and by every grant write.