Skip to content
POST /access-request

Files a request for access. Any member may call it, with no permission required, because asking for a permission must not itself need one. A request is always filed as the caller, so the body carries no requester. `permission` is required and must be a known permission name when `reason` is `"permission"`, and forbidden (`400`) when `reason` is `"restriction"`: a restriction refusal never names the rule that blocked someone, and this resource must not become a second way to learn it. `reason` is never `"scope"`, because a scope refusal has no admin-side fix. **Filing never grants anything.** It creates a record for an admin to decide; approving a `restriction`-reason request is what can lift the restriction (see `POST /access-request/{id}/resolve`). **De-duplicated.** A second request for the same `tool` while an earlier one from the same requester is still `pending` returns the existing row (updating `note` when a different one was sent) with `200`. A genuinely new row is `201`. **A tool request that could never be granted is refused.** A `restriction`-reason `"tool"` request naming a `connector_slug` whose whole connector is restricted for the caller is `409 tool_request_connector_blocked`: approving it would lift nothing, because one tool cannot be carved out of a connector restricted whole. The message names the connector and says to ask for it instead; `error.details` carries `connector_slug`, `connector_label` and `pending_request` (the caller’s own open connector request, or null). Every tool row that can draw an ask carries `restricted_scope` (`"connector"`, `"tool"` or null), so a client can file the connector request up front.

Request Body

connector_slugstring

Only on a "tool" request (400 on a connector request): the connector the tool lives on. Lets an approval lift the restriction on exactly that tool; without it approving records a decision only.

notestring
permissionstring

Required when reason is "permission"; forbidden (400) when reason is "restriction".

reasonstring
Possible values:
permissionrestriction
resource_typestring
Possible values:
toolconnector
toolstring

The tool name the caller was blocked from calling, or a connector slug when resource_type is "connector".

Response Body

can_withdrawboolean

True when the caller is the requester and status is still pending.

connector_labelstring

Display name of connector_slug (or, on a "connector" request, of tool itself), falling back to the slug. Present on every view: the requester reads it in the self view exactly as an admin does in the queue.

connector_logostring,null

The connector’s logo for the slug connector_label names. null when the catalog has no logo for the slug; present under the same conditions as connector_label.

connector_slugstring,null

On a "tool" request, the connector the tool lives on when the request named one — what makes approving it able to lift the restriction on that tool. Always null on a "connector" request.

created_atstring · date-time
idstring

Access request id (areq_…).

notestring,null

Optional free text from the requester, ≤ 2000 characters.

permissionstring,null

Present only when reason is "permission" — never populated for a "restriction"-reason request, on either write or read. That is the disclosure rule: a restriction refusal never names the rule that blocked the caller, so this field must not become a second channel for the same fact.

reasonstring

What kind of refusal this request is asking to be reconsidered.

Possible values:
permissionrestriction
requester_user_idstring

User id (usr_…) of whoever filed the request.

resolution_notestring,null
resolved_atstring,null · date-time
resolved_by_user_idstring,null

User id (usr_…) of the admin who resolved it.

resource_typestring
Possible values:
toolconnector
restriction_liftedboolean,null

What an approval did to the requester’s access, on every view: true when it wrote a grant, false when the request was approved and nothing was lifted (a resolution: "policy" approval, access that was already open, or a shape no grant can open), null when the question does not apply (not approved, a permission request, a tool request with no connector_slug). It never says why; the connector’s own restricted, restricted_by and restricted_inherited_from do, within what the caller may be told. An older approval may read false for access it did give, so read the connector’s restricted for the live answer. It is the outcome at resolve time: a later revoke, expiry or replacement does not change it.

statusstring
Possible values:
pendingapproveddeniedwithdrawn
toolstring

What was asked for: a tool name, or a connector slug when resource_type is "connector".

updated_atstring · date-time
curl -X POST 'https://api.elaichi.ai/access-request' \
  -H 'Authorization: Bearer $ELAICHI_API_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{"tool":"your_tool","resource_type":"tool","connector_slug":"your_connector_slug","reason":"permission","permission":"your_permission","note":"your_note"}'
const body = {
  "tool": "your_tool",
  "resource_type": "tool",
  "connector_slug": "your_connector_slug",
  "reason": "permission",
  "permission": "your_permission",
  "note": "your_note"
};

const response = await fetch('https://api.elaichi.ai/access-request', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer ' + process.env.ELAICHI_API_TOKEN,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify(body),
});

const data = await response.json();
console.log(data);
import os
import requests

url = "https://api.elaichi.ai/access-request"
headers = {
    "Authorization": f"Bearer {os.environ['ELAICHI_API_TOKEN']}",
    "Content-Type": "application/json",
}
payload = {
    "tool": "your_tool",
    "resource_type": "tool",
    "connector_slug": "your_connector_slug",
    "reason": "permission",
    "permission": "your_permission",
    "note": "your_note"
}

response = requests.post(url, headers=headers, json=payload)
print(response.json())