Skip to content
POST /access-request/{id}/resolve

**Approving a `restriction`-reason request lifts that restriction for the requester alone** — a whole connector, or one tool on the connector a tool request names in `connector_slug`. The requester’s own member-level rules are edited (and a block rule the approval empties is removed); where their ROLE’s rules stand in the way, one lasting `except` rule is written naming exactly the approved connector or tool (`origin: "access_request"`, `access_request_id` set). Role rules themselves are never edited or copied, so every other role rule — including one added later — keeps binding the requester. A tool on a connector blocked whole cannot be carved out and is not lifted. `will_lift_restriction` on the admin view previews whether approving will change anything. Every other approval — a `permission`-reason request, or a tool request with no `connector_slug` — records a decision only; widening access there is a separate act through `PATCH /member/{userId}` or the restriction APIs. Requires `member:manage`. Refuses with `409` when the request has already left `pending` — a decision is recorded once. A BROWSER SESSION must additionally carry a fresh step-up reauthentication (`X-Step-Up-Token`, obtained from `/auth/step-up`); without one the call answers `428 step_up_required` and `error.details` names the action and resource to prove. A governance decision is recorded once and never re-opened, so the person recording it re-proves they are still the person holding the session. An organization API token is not challenged: step-up re-proves the person behind a session, and a token has no person behind it. **An admin may not decide their own request: `403`**, whichever decision they send and however many permissions they hold — self-approval of a restriction request would be a self-grant, and beyond that the record is the product: "approved by Roopi" on Roopi’s own ask reads downstream exactly like an approval a second person signed. Enforced on the route, not only by `can_resolve`, so a client that ignores the capability field is refused rather than obeyed. The requesting admin keeps `can_withdraw` on that row instead.

Path Parameters

idstring
required·

Access request id (areq_…).

Request Body

decisionstring
Possible values:
approveddenied
notestring

Response Body

can_resolveboolean

True while status is still pending and the row is not the caller’s own — the two preconditions resolve itself enforces (409 and 403 respectively).

can_withdrawboolean

True when the caller is the requester and status is still pending. Present on this shape as well as on the self view: an admin’s own request sits in their own queue, and withdrawing it is the one verb on that row that is theirs.

connector_labelstring

Display name of connector_slug on a tool request that names one (falls back to the slug).

connector_restricted_for_requesterboolean

On the same rows, for a TOOL request only: true when approving lifts nothing because the requester’s WHOLE connector is restricted — one tool cannot be carved out of a connector restricted whole, and an approval never opens the whole connector for a one-tool ask. Their connector access is what an admin would have to grant instead.

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
requesterobject

Resolved member profile. Falls back to { id } alone when the profile row no longer resolves.

emailstring · email
idstring

User id (usr_…).

namestring,null
requester_user_idstring

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

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

Resolved member profile. Falls back to { id } alone when the profile row no longer resolves.

emailstring · email
idstring

User id (usr_…).

namestring,null
resolved_by_user_idstring,null

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

resource_typestring
Possible values:
toolconnector
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
will_lift_restrictionboolean

On a pending restriction-reason request approving could act on (a connector request, or a tool request naming its connector_slug): whether approving it would actually lift anything. Absent on every other row.

curl -X POST 'https://api.elaichi.ai/access-request/<id>/resolve' \
  -H 'Authorization: Bearer $ELAICHI_API_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{"decision":"approved","note":"your_note"}'
const body = {
  "decision": "approved",
  "note": "your_note"
};

const response = await fetch('https://api.elaichi.ai/access-request/<id>/resolve', {
  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/<id>/resolve"
headers = {
    "Authorization": f"Bearer {os.environ['ELAICHI_API_TOKEN']}",
    "Content-Type": "application/json",
}
payload = {
    "decision": "approved",
    "note": "your_note"
}

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