Modules API
Register and list permission modules.
Modules represent functional areas of your application. They are used by the Full authorization model to define action sets that can be assigned to roles.
Scope: permissions:manage
Rate limit: 500/hr
List modules
GET /api/v1/permissions/modules
Returns all registered modules for the tenant.
curl https://api.platformxe.com/api/v1/permissions/modules \
-H "x-api-key: pxk_live_your_api_key_here"
const modules = await px.permissions.listModules();
Response
{
"success": true,
"data": {
"modules": [
{
"id": "mod_bookings",
"name": "BOOKINGS",
"description": "Booking management",
"actions": ["READ", "CREATE", "UPDATE", "DELETE", "LIST", "APPROVE"],
"createdAt": "2026-03-15T08:00:00.000Z"
}
]
}
}
Register a module
POST /api/v1/permissions/modules
Registration is synchronous: the module is written before the response is sent, and the response carries the stored module.
| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Module id, e.g. LT:PROPERTIES |
app | string | Yes | Registering application, e.g. lettings |
name | string | Yes | Display name |
description | string | No | Human-readable description |
paths | string[] | Yes | Paths this module covers (at least one) |
curl -X POST https://api.platformxe.com/api/v1/permissions/modules \
-H "Content-Type: application/json" \
-H "x-api-key: pxk_live_your_api_key_here" \
-d '{
"id": "LT:PROPERTIES",
"app": "lettings",
"name": "Properties",
"description": "Property listing management",
"paths": ["properties", "properties/publish"]
}'
await px.permissions.registerModule({
id: 'LT:PROPERTIES',
app: 'lettings',
name: 'Properties',
description: 'Property listing management',
paths: ['properties', 'properties/publish'],
});
Response
HTTP 200:
{
"success": true,
"data": {
"message": "Module registered",
"module": {
"id": "LT:PROPERTIES",
"app": "lettings",
"name": "Properties",
"description": "Property listing management",
"paths": ["properties", "properties/publish"],
"organizationId": "org_abc123",
"federatedKey": null,
"createdAt": "2026-09-15T08:00:00.000Z"
}
}
}
Before 2026-09-15 this endpoint answered 202 and wrote the module in a background job, so a rejected write could still report success. It now answers 200 only after the write commits. Treat any 2xx as success.
Module limits by plan
| Plan | Max modules |
|---|---|
| Free | 5 |
| Basic | 20 |
| Pro | 50 |
| Enterprise | Unlimited |
The limit counts the modules your organization has registered. Registering a new module beyond your plan limit returns MODULE_LIMIT_EXCEEDED (HTTP 402). Re-registering a module your organization already owns is an update and is always allowed.
Module registration is idempotent. Re-registering a module id your organization owns updates its name, description and paths rather than creating a duplicate. A module id is owned by the organization that first registered it: another organization registering the same id receives CONFLICT (HTTP 409) and the existing module is left unchanged.
Tenant scope
Modules belong to the organization that registered them. GET returns only your organization's modules plus legacy modules that have no owner — never another organization's modules. Role module permissions can only reference modules visible to your organization.
Error responses
| Code | Description |
|---|---|
BAD_REQUEST | Missing name or empty actions array |
CONFLICT | The module id is already registered by another organization (HTTP 409) |
MODULE_LIMIT_EXCEEDED | Module count exceeds plan limit (HTTP 402) |
FORBIDDEN | API key missing permissions:manage scope |