Update an API permission
Update, not create: the path id names the existing API permission and the body replaces its actor, endpoint, type and rate limits. Returns 200.
Authorization
bearerAuth In: header
Path Parameters
API permission id
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Body of POST /v1/rbac/api-permissions/{id} (update). Same fields as the create body, but the write rules INVERT, because the storage layer calls GORM Updates() with a struct rather than a map and GORM skips zero-valued struct fields:
- an omitted active leaves the stored value UNCHANGED here, where on create it would have stored false;
- an explicit active: false behaves the same way and is also NOT written: populateAPIPermissionData turns both the omitted and the explicit form into the same false, which GORM skips. This route therefore cannot deactivate a grant — it answers 200 and leaves it active. Use DELETE to revoke one;
- an explicit rate_limit_per_minute: 0 is silently NOT written, because 0 is the zero value — while the -1 that an omitted limit turns into is non-zero and IS written, so leaving a limit out overwrites it with "unlimited" and setting it to 0 does nothing. To clear a limit, send -1 explicitly.
Response Body
application/json
application/json
application/json
application/json
application/json
application/json
application/json
application/json
curl -X POST "https://example.com/v1/rbac/api-permissions/497f6eca-6276-4993-bfeb-53cbbbba6f08" \ -H "Content-Type: application/json" \ -d '{ "api_endpoint_id": "fb253d37-e680-42f3-827b-b3200c221269", "actor_id": "04f37679-bfbf-4906-b749-01756515cecf", "type": "user" }'{
"api_endpoint_id": "fb253d37-e680-42f3-827b-b3200c221269",
"actor_id": "04f37679-bfbf-4906-b749-01756515cecf",
"type": "user",
"api_endpoint": {
"endpoint": "/v1/accounts/%",
"method": "GET",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"created_at": "2019-08-24T14:15:22Z",
"created_by": "ee824cad-d7a6-4f48-87dc-e8461a9201c4",
"modified_at": "2019-08-24T14:15:22Z",
"modified_by": "e8d4374d-93a1-4e98-a6c6-fdcf00c5059f",
"active": true,
"metadata": {}
},
"rate_limit_per_minute": 0,
"rate_limit_per_hour": 0,
"rate_limit_per_day": 0,
"rate_limit_per_week": 0,
"rate_limit_per_month": 0,
"rate_limit_per_year": 0,
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"created_at": "2019-08-24T14:15:22Z",
"created_by": "ee824cad-d7a6-4f48-87dc-e8461a9201c4",
"modified_at": "2019-08-24T14:15:22Z",
"modified_by": "e8d4374d-93a1-4e98-a6c6-fdcf00c5059f",
"active": true,
"metadata": {}
}{
"status": 400,
"code": "common.invalid_input",
"message": "Invalid input data",
"details": [
{
"field": "actor_id",
"rule": "required",
"param": "string",
"message": "actor_id is required"
}
],
"class": "validation",
"retryable": false
}{
"status": 400,
"code": "common.invalid_input",
"message": "Invalid input data",
"details": [
{
"field": "actor_id",
"rule": "required",
"param": "string",
"message": "actor_id is required"
}
],
"class": "validation",
"retryable": false
}{
"status": 400,
"code": "common.invalid_input",
"message": "Invalid input data",
"details": [
{
"field": "actor_id",
"rule": "required",
"param": "string",
"message": "actor_id is required"
}
],
"class": "validation",
"retryable": false
}{
"status": 400,
"code": "common.invalid_input",
"message": "Invalid input data",
"details": [
{
"field": "actor_id",
"rule": "required",
"param": "string",
"message": "actor_id is required"
}
],
"class": "validation",
"retryable": false
}{
"status": 429,
"message": "Global rate limit exceeded",
"code": "Global rate limit exceeded",
"class": "temporary",
"retryable": true
}{
"status": 400,
"code": "common.invalid_input",
"message": "Invalid input data",
"details": [
{
"field": "actor_id",
"rule": "required",
"param": "string",
"message": "actor_id is required"
}
],
"class": "validation",
"retryable": false
}{
"overall_status": "unhealthy",
"message": "Service is shutting down",
"timestamp": "2026-08-27T15:04:05Z"
}Grants an actor (user or role) the right to call a registered endpoint, with optional per-period rate limits. Idempotent on the `(api_endpoint_id, actor_id)` pair, and only on that pair: if a grant for it already exists, the stored row is returned unchanged with 201 and the rest of the request body is ignored — including `type` and every rate limit. So re-posting with a new `rate_limit_per_minute` answers 201 while the old limit stays in force, and posting `type: "role"` over an existing `user` grant returns the user row instead of creating a role grant. Use `POST /v1/rbac/api-permissions/{id}` to change an existing grant.
Adds a route to the endpoint registry. Returns 200 with the created entity, not 201.