POST /v1/tenants/{tenant_id}/schemas/write
The Write Schema endpoint accepts a Permify schema string and stores it as a new versioned schema for the tenant. Each successful write produces a unique schema_version that can be referenced in subsequent read, check, and data-write requests.
The schema must be sent as a single string — newlines should be represented as \n. Use the Permify Playground to model and copy your schema as a formatted string. A VS Code extension with syntax highlighting is also available (file extension .perm).
Path Parameters
The tenant identifier. Use t1 for single-tenant deployments. Must match ^([a-zA-Z0-9_\-@\.:+]{1,128}|\*)$.
Request Body
The full authorization schema written in Permify DSL. Entities, relations, attributes, and actions are all defined here.
Response
The version identifier for the newly written schema. Use this value in metadata.schema_version on subsequent requests to pin them to this schema version.
Example
curl --location --request POST 'localhost:3476/v1/tenants/{tenant_id}/schemas/write' \
--header 'Content-Type: application/json' \
--data-raw '{
"schema": "entity user {}\n\nentity organization {\n\n relation admin @user\n relation member @user\n\n action create_repository = (admin or member)\n action delete = admin\n}\n\nentity repository {\n\n relation owner @user\n relation parent @organization\n\n action push = owner\n action read = (owner and (parent.admin and parent.member))\n action delete = (parent.member and (parent.admin or owner))\n}"
}'
Request body
{
"schema": "entity user {}\n\nentity organization {\n\n relation admin @user\n relation member @user\n\n action create_repository = (admin or member)\n action delete = admin\n}\n\nentity repository {\n\n relation owner @user\n relation parent @organization\n\n action push = owner\n action read = (owner and (parent.admin and parent.member))\n action delete = (parent.member and (parent.admin or owner))\n}"
}
Response
{
"schema_version": "cnbe6se5fmal18gpc66g"
}
Error Codes
| HTTP Status | Description |
|---|
400 | Bad request — schema parse error or missing fields |
401 | Unauthorized |
404 | Tenant not found |
429 | Rate limit exceeded |
500 | Internal server error |