Tenants API documentation
This document describes all Tenant-related API endpoints of the Patrowl Dashboard. It covers tenant information, resource capacity (EASM credits, pentest slots, greybox credits, retest credits), managing the organizations under a tenant, allocating resources to those organizations, and managing the users linked to a tenant.
Base URL:
Authentication: All requests require an API token in the
Authorization
header:
Authorization: Token <your-API-token>
What is a Tenant?
A Tenant represents your MSSP or customer account. It holds a pool of resource capacity — EASM credits, pentest slots, greybox credits, and retest credits — that you distribute across one or more Organizations it manages (for example, one organization per customer or business unit).
A tenant can manage multiple organizations.
Each resource type has three figures at any level: capacity (the total available), allocated (the portion assigned to organizations), and used (what has actually been consumed).
Permissions
Every endpoint in this document requires Tenant Administrator access:
You must be registered as an administrator of the specific tenant you are calling.
Requesting a tenant you do not administer returns
404 Not Found
.
Being an administrator of your own organization does not by itself grant tenant administrator access — it must be explicitly granted (see §5.2).
The tenant list endpoint (
GET /api/auth/tenants/
) only returns tenants you administer.
1. Tenant
1.1 List tenants
Returns a paginated list of the tenants you administer.
Item | Value |
Method | GET |
URL | /api/auth/tenants/ |
Permission | Tenant Administrator |
Example request
GET /api/auth/tenants/ Authorization: Token <your-API-token> Accept: application/json
Example response
200 OK
{ "count": 1, "next": null, "previous": null, "results": [ { "id": 1, "name": "Acme MSSP", "brand_image": "iVBORw0KGgoAAAANSUhEUgAA...", "updated_at": "2025-02-20T10:00:00Z", "resources": { "easm_credits": { "capacity": 500, "allocated": 350, "used": 5 }, "pentest_slots": { "capacity": 10, "allocated": 3, "used": 1 }, "greybox_credits": { "capacity": 20, "allocated": 5, "used": 0 }, "retest_credits": { "capacity": 20, "allocated": 5, "used": 0 } } } ] }
brand_image
is your tenant logo, encoded as a base64 string (or
null
if none is set).
Possible status codes
Code | Description |
200 | Success. Empty results if you administer no tenant. |
401 | Unauthorized. |
403 | You are not a Tenant Administrator for any tenant. |
1.2 Retrieve a tenant
Item | Value |
Method | GET |
URL | /api/auth/tenants/{id}/ |
Permission | Tenant Administrator (of this tenant) |
URL parameters
Parameter | Type | Description |
id | integer | Tenant ID. |
Example request
GET /api/auth/tenants/1/ Authorization: Token <your-API-token> Accept: application/json
Example response
200 OK
Same shape as a single item of §1.1's
results
.
Possible status codes
Code | Description |
200 | Success. |
401 | Unauthorized. |
403 | You are not a Tenant Administrator for this tenant. |
404 | Tenant not found. |
2. Tenant memberships
Add or remove users from organizations in bulk, within a tenant.
2.1 Bulk assign memberships
Adds every user in
user_ids
to every organization in
organization_ids
. Users already members of an organization are left unchanged.
Item | Value |
Method | POST |
URL | /api/auth/tenants/{id}/memberships/ |
Permission | Tenant Administrator (of this tenant) |
URL parameters
Parameter | Type | Description |
id | integer | Tenant ID. |
Request body (JSON)
Field | Type | Required | Description |
user_ids | array of integers | Yes | User IDs to add. At least one. |
organization_ids | array of integers | Yes | Organization IDs to add the users to. At least one. Every organization must belong to this tenant. |
Example request
POST /api/auth/tenants/1/memberships/ Authorization: Token <your-API-token> Content-Type: application/json Accept: application/json { "user_ids": [10, 11], "organization_ids": [5, 6] }
Example response
200 OK
{ "status": "created" }
Possible status codes
Code | Description |
200 | Success. |
400 | Invalid payload, or one or more organizations/users are outside the tenant. |
403 | You are not a Tenant Administrator for this tenant. |
404 | Tenant not found. |
2.2 Bulk remove memberships
Removes every user in
user_ids
from every organization in
organization_ids
. Removing a user from an organization also clears anything they own or are assigned to within that organization (assets, asset groups, vulnerabilities, remediations, team memberships, and pending notifications).
Item | Value |
Method | DELETE |
URL | /api/auth/tenants/{id}/memberships/ |
Permission | Tenant Administrator (of this tenant) |
URL parameters
Parameter | Type | Description |
id | integer | Tenant ID. |
Request body (JSON)
Field | Type | Required | Description |
user_ids | array of integers | Yes | User IDs to remove. At least one. |
organization_ids | array of integers | Yes | Organization IDs to remove the users from. At least one. Every organization must belong to this tenant. |
Example request
DELETE /api/auth/tenants/1/memberships/ Authorization: Token <your-API-token> Content-Type: application/json Accept: application/json { "user_ids": [10, 11], "organization_ids": [5, 6] }
Example response
200 OK
{ "status": "success" }
Possible status codes
Code | Description |
200 | Success. |
400 | Invalid payload, or one or more organizations/users are outside the tenant. |
403 | You are not a Tenant Administrator for this tenant. |
404 | Tenant not found. |
3. Tenant organizations
Manage the organizations your tenant provisions and owns.
3.1 List organizations for a tenant
Item | Value |
Method | GET |
URL | /api/auth/tenants/{id}/organizations/ |
Permission | Tenant Administrator (of this tenant) |
URL parameters
Parameter | Type | Description |
id | integer | Tenant ID. |
Query parameters
Parameter | Type | Required | Description |
search | string | No | Case-insensitive search on organization name. |
Example request
GET /api/auth/tenants/1/organizations/?search=acme Authorization: Token <your-API-token> Accept: application/json
Example response
200 OK
{ "count": 1, "next": null, "previous": null, "results": [ { "id": 5, "name": "Acme UK", "member_total": 3, "member_preview": [ { "id": 10, "email": "[email protected]" }, { "id": 11, "email": "[email protected]" } ], "created_by": "[email protected]", "created_at": "2025-01-10T09:00:00Z", "updated_at": "2025-02-20T10:00:00Z" } ] }
member_preview
lists up to 5 members of the organization.
created_by
may be
null
if unknown.
Possible status codes
Code | Description |
200 | Success. Empty page if search matches nothing. |
401 | Unauthorized. |
403 | You are not a Tenant Administrator for this tenant. |
404 | Tenant not found. |
3.2 Create an organization under a tenant
Creates a new organization managed by the tenant, with an optional logo and initial resource allocations (each defaults to
0
).
Item | Value |
Method | POST |
URL | /api/auth/tenants/{id}/organizations/ |
Permission | Tenant Administrator (of this tenant) |
URL parameters
Parameter | Type | Description |
id | integer | Tenant ID. |
Request body (JSON)
Field | Type | Required | Description |
name | string | Yes | Organization name, max 200 characters. Must be unique within the tenant. |
brand_image | string | No | Logo, encoded as a base64 string. |
easm_credits | integer | No | Initial allocation. Min 0 . Default 0 . |
pentest_slots | integer | No | Initial allocation. Min 0 . Default 0 . |
greybox_credits | integer | No | Initial allocation. Min 0 . Default 0 . |
retest_credits | integer | No | Initial allocation. Min 0 . Default 0 . |
Requested allocations cannot exceed the tenant's remaining (unallocated) capacity for each resource.
Example request
POST /api/auth/tenants/1/organizations/ Authorization: Token <your-API-token> Content-Type: application/json Accept: application/json { "name": "Acme UK", "easm_credits": 50, "pentest_slots": 2, "greybox_credits": 5, "retest_credits": 5 }
Example response
201 Created
{ "id": 5, "name": "Acme UK", "resources": { "easm_credits": { "capacity": 500, "allocated": 50, "used": 0 }, "pentest_slots": { "capacity": 10, "allocated": 2, "used": 0 }, "greybox_credits": { "capacity": 20, "allocated": 5, "used": 0 }, "retest_credits": { "capacity": 20, "allocated": 5, "used": 0 } }, "created_by": "[email protected]", "created_at": "2025-02-20T10:00:00Z", "updated_at": "2025-02-20T10:00:00Z" }
Possible status codes
Code | Description |
201 | Organization created. |
400 | Invalid payload; the name is already used within the tenant; or a requested allocation exceeds the tenant's remaining capacity. |
401 | Unauthorized. |
403 | You are not a Tenant Administrator for this tenant. |
404 | Tenant not found. |
502 | The organization could not be provisioned. Please try again later; contact support if the problem persists. |
3.3 Update an organization (rename / change logo)
Item | Value |
Method | PATCH |
URL | /api/auth/tenants/{id}/organizations/{org_id}/ |
Permission | Tenant Administrator (of this tenant) |
URL parameters
Parameter | Type | Description |
id | integer | Tenant ID. |
org_id | integer | Organization ID. Must belong to the tenant. |
Request body (JSON)
Field | Type | Required | Description |
name | string | No | New name, max 200 characters. At least one of name / brand_image required. |
brand_image | string | No | New logo, encoded as a base64 string. |
Example request
PATCH /api/auth/tenants/1/organizations/5/ Authorization: Token <your-API-token> Content-Type: application/json Accept: application/json { "name": "Acme UK Ltd" }
Example response
200 OK
{ "id": 5, "name": "Acme UK Ltd", "updated_at": "2025-02-21T08:00:00Z" }
Possible status codes
Code | Description |
200 | Success. |
400 | Neither name nor brand_image provided; or the name is already used within the tenant. |
401 | Unauthorized. |
403 | You are not a Tenant Administrator for this tenant. |
404 | Tenant or organization not found (or organization not in this tenant). |
502 | The update could not be applied. Please try again later; contact support if the problem persists. |
3.4 Bulk delete organizations
Deletes one or more organizations of a tenant. Their resource allocations are released back to the tenant's available capacity.
Item | Value |
Method | DELETE |
URL | /api/auth/tenants/{id}/organizations/ |
Permission | Tenant Administrator (of this tenant) |
URL parameters
Parameter | Type | Description |
id | integer | Tenant ID. |
Request body (JSON)
Field | Type | Required | Description |
ids | array of integers | Yes | Organization IDs to delete. Every id must belong to the tenant. |
Example request
DELETE /api/auth/tenants/1/organizations/ Authorization: Token <your-API-token> Content-Type: application/json Accept: application/json { "ids": [5, 6] }
Example response
200 OK
{ "deleted_ids": [5, 6] }
Example error response
400 Bad Request
(some ids outside the tenant)
{ "invalid_ids": [99] }
Possible status codes
Code | Description |
200 | Success; deleted_ids echoes the requested ids . |
400 | Invalid/empty ids , or one or more ids do not belong to the tenant ( invalid_ids ). |
401 | Unauthorized. |
403 | You are not a Tenant Administrator for this tenant. |
404 | Tenant not found. |
4. Tenant organization resources
View and adjust how much of the tenant's resource capacity is allocated to each organization.
4.1 List organization resources for a tenant
Item | Value |
Method | GET |
URL | /api/auth/tenants/{id}/organizations/resources/ |
Permission | Tenant Administrator (of this tenant) |
URL parameters
Parameter | Type | Description |
id | integer | Tenant ID. |
Query parameters
Parameter | Type | Required | Description |
search | string | No | Case-insensitive search on organization name. |
Example request
GET /api/auth/tenants/1/organizations/resources/?search=acme Authorization: Token <your-API-token> Accept: application/json
Example response
200 OK
{ "count": 1, "next": null, "previous": null, "results": [ { "id": 5, "name": "Acme UK", "asset_count": 42, "resources": { "easm_credits": { "capacity": 500, "allocated": 50, "used": 42 }, "pentest_slots": { "capacity": 10, "allocated": 2, "used": 1 }, "greybox_credits": { "capacity": 20, "allocated": 5, "used": 0 }, "retest_credits": { "capacity": 20, "allocated": 5, "used": 0 } }, "created_at": "2025-01-10T09:00:00Z", "updated_at": "2025-02-20T10:00:00Z" } ] }
asset_count
is the number of active assets monitored for that organization.
Possible status codes
Code | Description |
200 | Success. Empty page if search matches nothing. |
401 | Unauthorized. |
403 | You are not a Tenant Administrator for this tenant. |
404 | Tenant not found. |
4.2 Update an organization's resource allocations
Updates one or more of the organization's allocations (EASM credits, pentest slots, greybox credits, retest credits). At least one field is required.
Item | Value |
Method | PATCH |
URL | /api/auth/tenants/{id}/organizations/{org_id}/resources/ |
Permission | Tenant Administrator (of this tenant) |
URL parameters
Parameter | Type | Description |
id | integer | Tenant ID. |
org_id | integer | Organization ID. Must belong to the tenant. |
Request body (JSON)
Field | Type | Required | Description |
easm_credits | integer | No | New allocation. Min 0 . |
pentest_slots | integer | No | New allocation. Min 0 . |
greybox_credits | integer | No | New allocation. Min 0 . |
retest_credits | integer | No | New allocation. Min 0 . |
A new value cannot be set below what the organization is already using, and cannot exceed the tenant's remaining available capacity.
Example request
PATCH /api/auth/tenants/1/organizations/5/resources/ Authorization: Token <your-API-token> Content-Type: application/json Accept: application/json { "easm_credits": 100 }
Example response
200 OK
{ "resources": { "easm_credits": { "capacity": 500, "allocated": 100, "used": 42 }, "pentest_slots": { "capacity": 10, "allocated": 2, "used": 1 }, "greybox_credits": { "capacity": 20, "allocated": 5, "used": 0 }, "retest_credits": { "capacity": 20, "allocated": 5, "used": 0 } } }
Example error response
400 Bad Request
{ "easm_credits": "Cannot set easm_credits to 10: 42 are currently in use for this organization." }
or, when exceeding the tenant's remaining capacity:
{ "easm_credits": "Cannot set easm_credits to 600: tenant capacity allows 450 at most (500 total, 50 allocated to other organizations)." }
Possible status codes
Code | Description |
200 | Success. |
400 | No resource field provided, allocation below current usage, or allocation exceeds remaining tenant capacity. |
401 | Unauthorized. |
403 | You are not a Tenant Administrator for this tenant. |
404 | Tenant or organization not found (or organization not in this tenant). |
5. Tenant users
Directory of the users linked to a tenant, plus tenant-administrator management and CSV export.
5.1 List users for a tenant
Returns users linked to the tenant directly, or through membership in one of its organizations.
Item | Value |
Method | GET |
URL | /api/auth/tenants/{id}/users/ |
Permission | Tenant Administrator (of this tenant) |
URL parameters
Parameter | Type | Description |
id | integer | Tenant ID. |
Query parameters
Parameter | Type | Required | Description |
search | string | No | Free-text search (name/email). |
is_active | boolean | No | Filter by active status. |
role | string | No | Filter by user role. |
first_name | string | No | Filter by first name. |
last_name | string | No | Filter by last name. |
string | No | Filter by email. | |
org_id | integer | No | Filter by organization membership. |
org_not | integer | No | Exclude an organization's members. |
is_asset_owner | boolean | No | Filter users who own at least one asset. |
is_asset_group_owner | boolean | No | Filter users who own at least one asset group. |
is_vuln_owner | boolean | No | Filter users who own at least one vulnerability. |
is_vuln_solution_owner | boolean | No | Filter users who own at least one vulnerability solution. |
limit | integer | No | Page size (pagination), capped at 200. |
page | integer | No | Page number. |
Example request
GET /api/auth/tenants/1/users/?search=org_member@customer Authorization: Token <your-API-token> Accept: application/json
Example response
200 OK
{ "count": 1, "next": null, "previous": null, "results": [ { "id": 11, "email": "[email protected]", "first_name": "Org", "last_name": "Member", "is_active": true, "is_tenant_admin": false, "last_login": "2025-02-19T07:30:00Z", "organizations": [{ "id": 5, "name": "Acme UK", "slug": "acme-uk" }] } ] }
organizations
only lists organizations belonging to this tenant.
Possible status codes
Code | Description |
200 | Success. Empty page if filters match nothing. |
401 | Unauthorized. |
403 | You are not a Tenant Administrator for this tenant. |
404 | Tenant not found. |
5.2 Assign tenant administrator
Grants tenant-administrator access to an existing user.
Item | Value |
Method | POST |
URL | /api/auth/tenants/{id}/users/ |
Permission | Tenant Administrator (of this tenant) |
URL parameters
Parameter | Type | Description |
id | integer | Tenant ID. |
Request body (JSON)
Field | Type | Required | Description |
user_id | integer | Yes | ID of an existing user to promote. |
Example request
POST /api/auth/tenants/1/users/ Authorization: Token <your-API-token> Content-Type: application/json Accept: application/json { "user_id": 12 }
Example response
201 Created
{ "user_id": 12, "tenant_id": 1 }
Possible status codes
Code | Description |
201 | User assigned as tenant administrator. |
400 | Invalid payload (missing/invalid user_id ). |
401 | Unauthorized. |
403 | You are not a Tenant Administrator for this tenant. |
404 | Tenant not found (or user_id does not reference an existing user). |
409 | The user is already a tenant administrator. |
5.3 Revoke tenant administrator
Demotes a tenant administrator back to a standard tenant member. At least one administrator must always remain.
Item | Value |
Method | DELETE |
URL | /api/auth/tenants/{id}/users/ |
Permission | Tenant Administrator (of this tenant) |
URL parameters
Parameter | Type | Description |
id | integer | Tenant ID. |
Request body (JSON)
Field | Type | Required | Description |
user_id | integer | Yes | ID of the tenant administrator to demote. |
Example request
DELETE /api/auth/tenants/1/users/ Authorization: Token <your-API-token> Content-Type: application/json Accept: application/json { "user_id": 12 }
Example response
200 OK
{ "user_id": 12 }
Possible status codes
Code | Description |
200 | User demoted to standard tenant member. |
400 | Invalid payload, or this is the last remaining tenant administrator. |
401 | Unauthorized. |
403 | You are not a Tenant Administrator for this tenant, or you are not permitted to revoke this particular administrator. |
404 | Tenant not found, or the user is not a tenant administrator. |
5.4 Export tenant users (CSV)
Exports users linked to the tenant as a CSV file.
GET
exports according to the same filters as §5.1;
POST
exports only the given user ids.
Item | Value |
Method | GET or POST |
URL | /api/auth/tenants/{id}/users/export/ |
Permission | Tenant Administrator (of this tenant) |
URL parameters
Parameter | Type | Description |
id | integer | Tenant ID. |
GET Applies the same query parameters as §5.1. No body.
POST
Request body (JSON)
Field | Type | Required | Description |
users_id | array of integers | Yes | User IDs to export. At least one. |
Example request (GET)
GET /api/auth/tenants/1/users/export/?is_active=true Authorization: Token <your-API-token> Accept: text/csv
Example request (POST)
POST /api/auth/tenants/1/users/export/ Authorization: Token <your-API-token> Content-Type: application/json Accept: text/csv { "users_id": [10, 11] }
Response
200 OK
Content-Type:
text/csv
Content-Disposition:
attachment; filename="users_YYYY-MM-DD_HH-MM-SS.csv"
.
CSV columns (in order):
,
Firstname
,
Lastname
,
Enabled
,
Role
,
Last login
,
Organizations
(comma-separated list of the tenant's organizations the user belongs to).
A JSON response can be requested instead of CSV by sending
Accept: application/json
.
Possible status codes
Code | Description |
200 | CSV (or JSON) returned. |
400 | POST with invalid/empty users_id . |
401 | Unauthorized. |
403 | You are not a Tenant Administrator for this tenant. |
404 | Tenant not found. |
6. Common error response format
Errors are generally returned as a JSON body describing what went wrong, either as a general message:
{ "detail": "Human-readable description of the error." }
or as a field-specific message:
{ "<field_name>": "Human-readable description of the error." }
HTTP status codes used across this document:
Code | Usage |
200 | Success (including bulk operations and CSV/JSON export). |
201 | Resource created (organization, tenant-admin assignment). |
400 | Bad request (invalid/missing parameters or body; a business rule was violated, such as a resource limit or a duplicate name). |
401 | Unauthorized (missing/invalid token). |
403 | Forbidden (you are not a Tenant Administrator for this tenant, or an administrative rule prevents the action). |
404 | Not found (tenant, organization, or user not found, or outside your scope). |
409 | Conflict (the user is already a tenant administrator). |
502 | The request could not be completed due to a downstream error. Please try again later. |
7. Summary table
Action | Method | URL | Permission |
List tenants | GET | /api/auth/tenants/ | Tenant Administrator |
Retrieve tenant | GET | /api/auth/tenants/{id}/ | Tenant Administrator |
Bulk assign memberships | POST | /api/auth/tenants/{id}/memberships/ | Tenant Administrator |
Bulk remove memberships | DELETE | /api/auth/tenants/{id}/memberships/ | Tenant Administrator |
List organizations of a tenant (filter: search ) | GET | /api/auth/tenants/{id}/organizations/ | Tenant Administrator |
Create organization under a tenant | POST | /api/auth/tenants/{id}/organizations/ | Tenant Administrator |
Update organization (name/logo) | PATCH | /api/auth/tenants/{id}/organizations/{org_id}/ | Tenant Administrator |
Bulk delete organizations | DELETE | /api/auth/tenants/{id}/organizations/ | Tenant Administrator |
List organization resources (filter: search ) | GET | /api/auth/tenants/{id}/organizations/resources/ | Tenant Administrator |
Update organization resource allocations | PATCH | /api/auth/tenants/{id}/organizations/{org_id}/resources/ | Tenant Administrator |
List users linked to a tenant (filters: see §5.1) | GET | /api/auth/tenants/{id}/users/ | Tenant Administrator |
Assign tenant administrator | POST | /api/auth/tenants/{id}/users/ | Tenant Administrator |
Revoke tenant administrator | DELETE | /api/auth/tenants/{id}/users/ | Tenant Administrator |
Export tenant users (CSV/JSON) | GET / POST | /api/auth/tenants/{id}/users/export/ | Tenant Administrator |
