Resources
Optional registration unlocks capacity pools, resource trees, and blocker co-acquisition.
Registration is optional
You can reserve any string as a resource without registering it first — the simple case just works. Registration is only needed when you want:
- Capacity pools — one logical name, N physical slots
- Blockers — resources that are always co-acquired together
- Tree hierarchies — ancestor nodes that gate access to leaf resources
Register resources
POST /api/v1/Resource/register
X-Api-Key: YOUR_API_KEY
Content-Type: application/json
[
{
"name": "Printer",
"capacity": 3,
"blocks": ["Ink"],
"treePath": "Equipment>Office"
}
]
Registration is idempotent — re-registering the same name overwrites the previous definition.
Registration fields
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | Yes | Logical resource name. Must be unique within your tenant. |
capacity |
integer | No | Number of physical slots. Default 1. Capacity > 1 auto-expands to Name_0, Name_1, … slots. |
blocks |
string[] | No | Names of resources that must be co-acquired whenever this resource is reserved. All-or-nothing. |
treePath |
string | No | Ancestor path using > as delimiter, e.g. "Company>Equipment>IT". Do not include the resource name itself. Ancestor nodes are auto-registered. |
Capacity pools
Register a resource with capacity: N and reservations automatically
claim the first available physical slot. Callers reserve the logical name
("Printer") and the server picks the slot ("Printer_0").
// Register: Printer with 3 slots → Printer_0, Printer_1, Printer_2
[{"name": "Printer", "capacity": 3}]
// Reserve the logical name — server assigns the slot
[{"requester": "print-job-7", "resource": "Printer"}]
// Response shows which slot was assigned
{
"status": "ACQUIRED",
"acquiredSlots": {"Printer": "Printer_0"}
}
Blockers
A blocker is a resource that is automatically co-acquired whenever the parent resource is reserved. If any blocker is unavailable, the entire acquire fails.
// "Printer" always co-acquires "Ink" and "PrintQueue"
[{"name": "Printer", "blocks": ["Ink", "PrintQueue"]}]
// Reserve Printer — Ink and PrintQueue are acquired automatically
[{"requester": "job-1", "resource": "Printer"}]
// Response
{
"status": "ACQUIRED",
"acquiredBlockers": ["Ink", "PrintQueue"]
}
Blockers are held under a system requester, not the caller. They are only released when no requester holding the logical resource still needs them (smart release). Do not attempt to release blockers directly.
Resource trees
Resources can be placed in a hierarchy using treePath. Reserving a leaf
resource automatically acquires all ancestor nodes (ALL_OR_NONE on the full chain).
If any ancestor is at capacity, the entire acquire fails.
// Register two printers under a shared Equipment > IT node
[
{"name": "Printer-A", "treePath": "Equipment>IT"},
{"name": "Printer-B", "treePath": "Equipment>IT"}
]
// Reserving Printer-A also holds Equipment and IT
[{"requester": "job-1", "resource": "Printer-A"}]
// Response
{
"status": "ACQUIRED",
"reservedAtPath": "Equipment>IT>Printer-A"
}
List registered resources
GET /api/v1/Resource/definitions X-Api-Key: YOUR_API_KEY
[
{
"name": "Printer",
"capacity": 3,
"blocks": ["Ink"],
"treePath": "Equipment>Office"
}
]
Check availability
GET /api/v1/Resource/available/{resource}
X-Api-Key: YOUR_API_KEY
Returns true if the resource has at least one free slot.
Get resource tree
GET /api/v1/Resource/tree X-Api-Key: YOUR_API_KEY
Returns the full hierarchy with live capacity state — how many slots are available at each node.
Delete a resource
DELETE /api/v1/Resource/{name}?cascade=false
X-Api-Key: YOUR_API_KEY
Returns 400 if the resource has active reservations or has children (without cascade=true).
Returns 404 if the name is not registered.
InMemory vs persistent modes
In InMemory mode (default, no database), resource definitions are held in memory
and lost on restart. In Sqlite or Postgres mode, definitions are
persisted to the database and reloaded into the resource manager on startup.