> ## Documentation Index
> Fetch the complete documentation index at: https://docs.oleria.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Working with Access Requests

> Submit, track, and cancel access requests from your own tools.

The Access Requests API lets you drive [access requests](https://docs.oleria.com/governance/access-requests.md) from your own tools. You can submit a request from a service desk or chat bot, track it to a decision, and cancel it before it's decided. This page covers the request lifecycle and the errors to branch on.

## Before you begin

**1. Create an API key**

Create an API key in **Settings** -> **Manage API Keys** and exchange its client credentials for an access token. See [Generate an API Token](https://docs.oleria.com/developer-docs/api-reference/generate-token.md).

**2. Find your base URL**

Send every call to the **API URL** shown on the key, for example `https://devx.YOUR_TENANT.oleria.io`. See [API Overview](https://docs.oleria.com/developer-docs/api-reference/overview.md) for the conventions, errors, and rate limits shared by every Oleria API.

**3. Set up what can be requested**

Requests can only be made for access you've made requestable. If you haven't yet, set up [approval chains](https://docs.oleria.com/governance/approval-chains.md) and at least one request source - [SSO applications](https://docs.oleria.com/governance/sso-applications.md), [integrated applications](https://docs.oleria.com/governance/integrated-applications.md), or [Custom Access](https://docs.oleria.com/governance/custom-access.md) - in the Governance App.

Each endpoint requires one scope, named in its reference page:

| Scope | Allows |
| :- | :- |
| `https://devx.YOUR_TENANT.oleria.io/read` | Reading requests and requestable access. |
| `https://devx.YOUR_TENANT.oleria.io/write` | Submitting and canceling requests. |

New API keys get both scopes. An older key may have only `read`. If submitting or canceling returns `403`, contact Customer Success to add `write` to the key.

> [!NOTE]
>
> An API key identifies your integration, not a person. When a call acts for an employee - browsing what they can request, submitting a request, or canceling one - you name the employee with `requesterEmail`. It must belong to an active user in your workspace. Make sure your integration has already confirmed who that person is.

## What you can work with

| Resource | Path | What it is |
| :- | :- | :- |
| Access requests | `/v1/access-requests` | Requests people have made, with their status and activity. |
| Requestable subjects | `/v1/requestable-subjects` | The catalog of access people can request, with who would review each request. |

## Submit a request

**1. Find what to request**

`GET /v1/requestable-subjects?requesterEmail=...` lists everything the employee can request. Applications are limited to those federated by an identity provider the employee belongs to. Filter the list with `subjectType` (`Application`, `CustomAction`, or `DirectIntegration`) or `applicationId`.

Each item's `id` is the id of the config that makes it requestable - you pass it as `accessRequestConfigId`. `GET /v1/requestable-subjects/{id}?requesterEmail=...` returns one item by that id. The item also says what the requester can choose:

* **Applications** list `subject.application.groupAssignmentConfigs`. Pass the chosen one's `id` as `selectedGroupAssignmentConfigId`.
* **Direct integrations** list the groups and roles on offer. Pass the chosen one as `selectedDirectIntegrationGroupId` or `selectedDirectIntegrationRoleId`.
* **Custom actions** may declare input fields in `subject.customAction`. Pass the answers in `actionInputValues`, keyed by field name.

**2. Create the request**

`POST /v1/access-requests` submits the request and starts its approval chain. It returns `201` with the new request.

```bash cURL theme={null}
curl -X POST https://devx.YOUR_TENANT.oleria.io/v1/access-requests \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "accessRequestConfigId": "6f1c2b0e-8a4d-4f7e-9b3a-2d5e7c9a1b04",
    "selectedGroupAssignmentConfigId": "0b9e4d2a-3c7f-4a1e-8d6b-5f2c9e7a3d18",
    "requesterEmail": "jordan@example.com",
    "justification": "Quarter-end reporting",
    "accessDurationMinutes": 10080
  }'
```

```python Python theme={null}
import requests

resp = requests.post(
    "https://devx.YOUR_TENANT.oleria.io/v1/access-requests",
    headers={"Authorization": f"Bearer {access_token}"},
    json={
        "accessRequestConfigId": "6f1c2b0e-8a4d-4f7e-9b3a-2d5e7c9a1b04",
        "selectedGroupAssignmentConfigId": "0b9e4d2a-3c7f-4a1e-8d6b-5f2c9e7a3d18",
        "requesterEmail": "jordan@example.com",
        "justification": "Quarter-end reporting",
        "accessDurationMinutes": 10080,
    },
)
resp.raise_for_status()
access_request = resp.json()
```

```javascript Node.js theme={null}
const res = await fetch("https://devx.YOUR_TENANT.oleria.io/v1/access-requests", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${access_token}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    accessRequestConfigId: "6f1c2b0e-8a4d-4f7e-9b3a-2d5e7c9a1b04",
    selectedGroupAssignmentConfigId: "0b9e4d2a-3c7f-4a1e-8d6b-5f2c9e7a3d18",
    requesterEmail: "jordan@example.com",
    justification: "Quarter-end reporting",
    accessDurationMinutes: 10080,
  }),
});
const accessRequest = await res.json();
```

Send `justification` when the config's `requireJustification` is `true`. Send a duration only when the access lets the requester choose one, up to its `maxAccessDurationMinutes`. If the employee already holds an active grant of the same access, the new request extends it and `previousAccessRequestId` is set on the response.

**3. Track it to a decision**

`GET /v1/access-requests/{id}` returns the request with its `currentStatus`, `activities` (its status history), and the overall review decision once there is one.

The response from create doesn't include `requestNumber`, the short number shown to people as `#N`. Read the request back to get it.

Approvers are notified and decide as usual. See [Reviewing and approving requests](https://docs.oleria.com/governance/access-requests.md#reviewing-and-approving-requests).

> [!TIP]
>
> Approval can take hours or days. Poll infrequently - every few minutes at most - or check on requests in a scheduled job, rather than holding a request open.

## Find requests

`GET /v1/access-requests` lists requests, newest first. Combine these filters to narrow it:

| Parameter | Returns |
| :- | :- |
| `status` | Requests currently in one of these statuses. Repeat it to pass more than one, for example `?status=PendingApproval&status=Approved`. |
| `subjectType` | Requests for one kind of subject. |
| `requesterEmail` | Requests made by one person. |

Every list endpoint is paged. Pass `pageSize` to set the page size, and pass the response's `nextPageToken` as `pageToken` to get the next page. `nextPageToken` is absent on the last page.

### Request statuses

The API reports a more detailed status than the Governance App shows. Each maps to one [request status](https://docs.oleria.com/governance/access-requests.md#request-statuses):

| `currentStatus` | Shown as | Meaning |
| :- | :- | :- |
| `Requested` | Pending approval | Submitted, and the approval chain is starting. |
| `PendingApproval` | Pending approval | In an active step of the approval chain. |
| `Approved` | Approved | Every step approved. Provisioning starts next. |
| `Denied` | Denied | A step denied the request. |
| `Provisioning` | Provisioning | Access is being granted. |
| `ManualActionRequired` | Provisioning | A Custom Access manual action is waiting for someone to carry it out. |
| `Provisioned` | Access granted | Access is active. |
| `ManuallyProvisioned` | Manually provisioned | A Custom Access manual action was completed. |
| `ProvisioningFailed`, `RequestFailed` | Failed | Access couldn't be granted. |
| `RevokeRequested`, `Revoking`, `ManualRevokeRequired` | Access granted | Access is being removed. It stays active until removal finishes. |
| `RevokingFailed` | Failed | Access couldn't be removed. |
| `Revoked`, `ManuallyRevoked` | Revoked | Access was removed. |
| `Expired` | Expired | A time-bound grant reached the end of its duration. |
| `Cancelled` | Canceled | The request was withdrawn before a decision. |
| `Superseded` | Superseded | A later request extended the same access and took over. |

When access is active, `revokeAt` is when it's due to be removed. It's empty for access with no end date.

## Cancel a request

`POST /v1/access-requests/{id}/cancel?requesterEmail=...` withdraws a request for the employee who made it. It's allowed until the request is decided, and pending reviews are canceled with it. It returns the updated request.

## Errors

Errors use the `code` and `message` body described in [API Overview](https://docs.oleria.com/developer-docs/api-reference/overview.md#errors). A `409` means the request is valid but the state of something doesn't allow it. Branch on `code`:

| `code` | Returned by | What to do |
| :- | :- | :- |
| `ACCESS_REQUEST_NOT_ALLOWED` | Create a request | The employee already has an open request for this access, the grant being extended already has an extension in flight, or the grant is scheduled to be revoked. Check the employee's open requests, or wait for the pending extension or revocation to finish. |
| `ACCESS_REQUEST_NOT_CANCELLABLE` | Cancel | The request has already been decided. |

## Contact us

For questions about the Access Requests API, contact us at [support@oleria.com](mailto:support@oleria.com).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.