Operation Approval API
Require approval before a user performs a sensitive operation, and manage those approvals through the Permit Elements API. This page is for developers who build a custom approval flow on top of Permit Elements, the embeddable UI components. A user requests approval for an operation on a resource, and a reviewer approves or denies the request.
The requests on this page run as a user signed in to an element, with the session that your server-side login route creates. If you already added a login route for the Access Request API, skip to Operation approval endpoints.
- For every endpoint and schema, see Operation Approval in the API reference.
- For the embedded UI, see the Operation Approval element.
- For a working application that uses the Operation Approval API, see the Mesa Verde banking demo on GitHub.
Prerequisites
- An environment API key, used to initialize the Permit SDK in your backend. See Get your API key.
- The ID or key of your project and environment. See Get the project and environment IDs.
- The ID of the Operation Approval element configuration, used as
elements_config_id. See List the elements in an environment.
Sign in the element user
Initialize the Permit SDK
Initialize one instance of the Permit SDK in your backend. The same instance serves your permission checks and Permit Elements. Pass your environment API key to the Permit constructor.
const { Permit } = require("permitio");
const permit = new Permit(
{token: permit_key_SECRET}
);
Add a server-side login route
Create a route in your backend that signs the current user in to the element with loginAs. Match the route to the authentication method your application uses, such as a bearer token or cookies.
The loginAs method takes the unique ID of the user, usually read from the user's JSON Web Token (JWT), and the key or ID of the tenant:
permit.elements.loginAs({ userId, tenantId });
If the user is not a member of the tenant passed to loginAs, the login fails with the error USER_NOT_FOUND.
The session applies to one tenant. To switch a user to a different tenant, sign the user out and call loginAs again with the other tenant.
Passing the tenant is required for a server-side login.
Operation approval endpoints
All paths start with https://api.permit.io/v2/elements/{proj_id}/{env_id}/config/{elements_config_id}. Replace <COOKIE FROM LOGIN> in the examples with the session cookie from the login route.
| Method | Path suffix | Operation | Who calls it |
|---|---|---|---|
POST | /operation_approval | Create an operation approval | Requesting user |
GET | /operation_approval/{operation_approval_id} | Get an operation approval | Reviewer |
GET | /operation_approval | List operation approvals | Reviewer, or a user for their own approvals |
PATCH | /operation_approval/{operation_approval_id}/reviewer | Update the reviewer comment | Reviewer |
PUT | /operation_approval/{operation_approval_id}/approve | Approve an operation approval | Reviewer |
PUT | /operation_approval/{operation_approval_id}/deny | Deny an operation approval | Reviewer |
PUT | /operation_approval/{operation_approval_id}/cancel | Cancel an operation approval | Requesting user |
An operation approval has one of these status values: pending, approved, denied, or canceled.
Create an operation approval
Send a POST request to /operation_approval with the details of the operation.
| Field | Required | Description |
|---|---|---|
access_request_details.tenant | Yes | ID or key of the tenant the operation runs in |
access_request_details.resource | Yes | ID or key of the resource the operation applies to |
access_request_details.resource_instance | No | ID or key of the resource instance the operation applies to |
reason | No | Business justification from the requesting user |
curl -X POST \
'https://api.permit.io/v2/elements/{proj_id}/{env_id}/config/{elements_config_id}/operation_approval' \
-H 'cookie: <COOKIE FROM LOGIN>' \
-H 'Content-Type: application/json' \
--data-raw '{
"access_request_details": {
"tenant": "34f5c98e-f430-457b-a812-92637d0c6fd0",
"resource": "4d5215ed-38bb-48ed-879a-fdb9ca58522f",
"resource_instance": "2d98d9f8-e1b7-4f1d-baad-2edbf6fa6c66"
},
"reason": "I need to make transfer for my client"
}'
The API returns the created operation approval, with type set to operation_approval:
{
"id": "b7a6cfc2-6a4e-4d0f-9d0a-3f0f1f0b6a11",
"requesting_user_id": "1c1e4ada-f282-40e6-b3b7-20b3a51c93b5",
"access_request_details": {
"tenant": "34f5c98e-f430-457b-a812-92637d0c6fd0",
"resource": "4d5215ed-38bb-48ed-879a-fdb9ca58522f",
"resource_instance": "2d98d9f8-e1b7-4f1d-baad-2edbf6fa6c66"
},
"reason": "I need to make transfer for my client",
"organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
"project_id": "405d8375-3514-403b-8c43-83ae74cfe0e9",
"environment_id": "40ef0e48-a11f-4963-a229-e396c9f7e7c4",
"created_at": "2019-08-24T14:15:22Z",
"updated_at": "2019-08-24T14:15:22Z",
"status": "pending",
"reviewer_user_id": null,
"reviewed_at": null,
"reviewer_comment": null,
"type": "operation_approval"
}
The response includes the approval's id, which you pass as {operation_approval_id} in the other calls.
Reviewer actions
Get an operation approval
Send a GET request to /operation_approval/{operation_approval_id}.
curl 'https://api.permit.io/v2/elements/{proj_id}/{env_id}/config/{elements_config_id}/operation_approval/{operation_approval_id}' \
-H 'cookie: <COOKIE FROM LOGIN>'
The API returns the operation approval:
{
"id": "b7a6cfc2-6a4e-4d0f-9d0a-3f0f1f0b6a11",
"requesting_user_id": "1c1e4ada-f282-40e6-b3b7-20b3a51c93b5",
"access_request_details": {
"tenant": "34f5c98e-f430-457b-a812-92637d0c6fd0",
"resource": "4d5215ed-38bb-48ed-879a-fdb9ca58522f",
"resource_instance": "2d98d9f8-e1b7-4f1d-baad-2edbf6fa6c66"
},
"reason": "string",
"organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
"project_id": "405d8375-3514-403b-8c43-83ae74cfe0e9",
"environment_id": "40ef0e48-a11f-4963-a229-e396c9f7e7c4",
"created_at": "2019-08-24T14:15:22Z",
"updated_at": "2019-08-24T14:15:22Z",
"status": "approved",
"reviewer_user_id": "1b287364-14ff-4b72-8953-b40399093a6f",
"reviewed_at": "2019-08-24T14:15:22Z",
"reviewer_comment": "transfer for a new client",
"type": "operation_approval"
}
List operation approvals
Send a GET request to /operation_approval. Filter and paginate the list with these query parameters:
| Query parameter | Description |
|---|---|
status | Only approvals with this status: pending, approved, denied, or canceled |
resource | Only approvals for this resource |
resource_instance | Only approvals for this resource instance |
page | Page number, starting at 1. Default 1. |
per_page | Results per page, maximum 100. Default 30. |
curl -G 'https://api.permit.io/v2/elements/{proj_id}/{env_id}/config/{elements_config_id}/operation_approval' \
-H 'cookie: <COOKIE FROM LOGIN>' \
--data-urlencode 'status=pending' \
--data-urlencode 'resource=<RESOURCE_KEY>' \
--data-urlencode 'resource_instance=<RESOURCE_INSTANCE_KEY>' \
--data-urlencode 'page=1' \
--data-urlencode 'per_page=30'
The API returns a page of operation approvals. Each item also includes the requesting user's email, first name, and last name, and the resource and resource instance keys:
{
"data": [
{
"id": "b7a6cfc2-6a4e-4d0f-9d0a-3f0f1f0b6a11",
"requesting_user_id": "1c1e4ada-f282-40e6-b3b7-20b3a51c93b5",
"access_request_details": {
"tenant": "34f5c98e-f430-457b-a812-92637d0c6fd0",
"resource": "4d5215ed-38bb-48ed-879a-fdb9ca58522f",
"resource_instance": "2d98d9f8-e1b7-4f1d-baad-2edbf6fa6c66"
},
"reason": "I need to make transfer for my client",
"organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
"project_id": "405d8375-3514-403b-8c43-83ae74cfe0e9",
"environment_id": "40ef0e48-a11f-4963-a229-e396c9f7e7c4",
"created_at": "2019-08-24T14:15:22Z",
"updated_at": "2019-08-24T14:15:22Z",
"status": "approved",
"reviewer_user_id": "1b287364-14ff-4b72-8953-b40399093a6f",
"reviewed_at": "2019-08-24T14:15:22Z",
"reviewer_comment": "transfer for a new client",
"type": "operation_approval",
"requesting_user_email": "john@permit.io",
"requesting_user_first_name": "John",
"requesting_user_last_name": "Doe",
"resource_key": "transfer",
"resource_instance_key": "transfer-1"
}
],
"total_count": 1,
"page_count": 1
}
Users who are not reviewers see only their own operation approvals in the list.
Update the reviewer comment
Send a PATCH request to /operation_approval/{operation_approval_id}/reviewer. The body is optional and accepts reviewer_comment.
curl -X PATCH \
'https://api.permit.io/v2/elements/{proj_id}/{env_id}/config/{elements_config_id}/operation_approval/{operation_approval_id}/reviewer' \
-H 'cookie: <COOKIE FROM LOGIN>' \
-H 'Content-Type: application/json' \
--data-raw '{
"reviewer_comment": "transfer for a new client"
}'
The API returns the updated operation approval:
{
"id": "b7a6cfc2-6a4e-4d0f-9d0a-3f0f1f0b6a11",
"requesting_user_id": "1c1e4ada-f282-40e6-b3b7-20b3a51c93b5",
"access_request_details": {
"tenant": "34f5c98e-f430-457b-a812-92637d0c6fd0",
"resource": "4d5215ed-38bb-48ed-879a-fdb9ca58522f",
"resource_instance": "2d98d9f8-e1b7-4f1d-baad-2edbf6fa6c66"
},
"reason": "I need to make transfer for my client",
"organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
"project_id": "405d8375-3514-403b-8c43-83ae74cfe0e9",
"environment_id": "40ef0e48-a11f-4963-a229-e396c9f7e7c4",
"created_at": "2019-08-24T14:15:22Z",
"updated_at": "2019-08-24T14:15:22Z",
"status": "approved",
"reviewer_user_id": "1b287364-14ff-4b72-8953-b40399093a6f",
"reviewed_at": "2019-08-24T14:15:22Z",
"reviewer_comment": "transfer for a new client",
"type": "operation_approval"
}
Approve an operation approval
Send a PUT request to /operation_approval/{operation_approval_id}/approve. The body is optional and accepts reviewer_comment.
curl -X PUT \
'https://api.permit.io/v2/elements/{proj_id}/{env_id}/config/{elements_config_id}/operation_approval/{operation_approval_id}/approve' \
-H 'cookie: <COOKIE FROM LOGIN>' \
-H 'Content-Type: application/json' \
--data-raw '{
"reviewer_comment": "transfer for a new client"
}'
The API returns the approved operation approval with status set to approved:
{
"id": "b7a6cfc2-6a4e-4d0f-9d0a-3f0f1f0b6a11",
"requesting_user_id": "1c1e4ada-f282-40e6-b3b7-20b3a51c93b5",
"access_request_details": {
"tenant": "34f5c98e-f430-457b-a812-92637d0c6fd0",
"resource": "4d5215ed-38bb-48ed-879a-fdb9ca58522f",
"resource_instance": "2d98d9f8-e1b7-4f1d-baad-2edbf6fa6c66"
},
"reason": "I need to make transfer for my client",
"organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
"project_id": "405d8375-3514-403b-8c43-83ae74cfe0e9",
"environment_id": "40ef0e48-a11f-4963-a229-e396c9f7e7c4",
"created_at": "2019-08-24T14:15:22Z",
"updated_at": "2019-08-24T14:15:22Z",
"status": "approved",
"reviewer_user_id": "1b287364-14ff-4b72-8953-b40399093a6f",
"reviewed_at": "2019-08-24T14:15:22Z",
"reviewer_comment": "transfer for a new client",
"type": "operation_approval"
}
Deny an operation approval
Send a PUT request to /operation_approval/{operation_approval_id}/deny. The body is optional and accepts reviewer_comment.
curl -X PUT \
'https://api.permit.io/v2/elements/{proj_id}/{env_id}/config/{elements_config_id}/operation_approval/{operation_approval_id}/deny' \
-H 'cookie: <COOKIE FROM LOGIN>' \
-H 'Content-Type: application/json' \
--data-raw '{
"reviewer_comment": "need more info"
}'
The API returns the denied operation approval:
{
"id": "b7a6cfc2-6a4e-4d0f-9d0a-3f0f1f0b6a11",
"requesting_user_id": "1c1e4ada-f282-40e6-b3b7-20b3a51c93b5",
"access_request_details": {
"tenant": "34f5c98e-f430-457b-a812-92637d0c6fd0",
"resource": "4d5215ed-38bb-48ed-879a-fdb9ca58522f",
"resource_instance": "2d98d9f8-e1b7-4f1d-baad-2edbf6fa6c66"
},
"reason": "I need to make transfer for my client",
"organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
"project_id": "405d8375-3514-403b-8c43-83ae74cfe0e9",
"environment_id": "40ef0e48-a11f-4963-a229-e396c9f7e7c4",
"created_at": "2019-08-24T14:15:22Z",
"updated_at": "2019-08-24T14:15:22Z",
"status": "denied",
"reviewer_user_id": "1b287364-14ff-4b72-8953-b40399093a6f",
"reviewed_at": "2019-08-24T14:15:22Z",
"reviewer_comment": "need more info",
"type": "operation_approval"
}
Requesting user actions
Cancel an operation approval
Send a PUT request to /operation_approval/{operation_approval_id}/cancel. The request has no body.
curl -X PUT \
'https://api.permit.io/v2/elements/{proj_id}/{env_id}/config/{elements_config_id}/operation_approval/{operation_approval_id}/cancel' \
-H 'cookie: <COOKIE FROM LOGIN>'
The API returns the canceled operation approval:
{
"id": "b7a6cfc2-6a4e-4d0f-9d0a-3f0f1f0b6a11",
"requesting_user_id": "1c1e4ada-f282-40e6-b3b7-20b3a51c93b5",
"access_request_details": {
"tenant": "34f5c98e-f430-457b-a812-92637d0c6fd0",
"resource": "4d5215ed-38bb-48ed-879a-fdb9ca58522f",
"resource_instance": "2d98d9f8-e1b7-4f1d-baad-2edbf6fa6c66"
},
"reason": "I need to make transfer for my client",
"organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
"project_id": "405d8375-3514-403b-8c43-83ae74cfe0e9",
"environment_id": "40ef0e48-a11f-4963-a229-e396c9f7e7c4",
"created_at": "2019-08-24T14:15:22Z",
"updated_at": "2019-08-24T14:15:22Z",
"status": "canceled",
"reviewer_user_id": null,
"reviewed_at": null,
"reviewer_comment": null,
"type": "operation_approval"
}