API
Four services, one set of conventions.
| Service | Aspire name | Holds |
|---|---|---|
| Library set API | api-libraryset | Tag groups, tags, library sets, variables, values, import |
| Account API | api-account | Organizations, users, groups, permissions, API keys |
| Identity API | api-identity | JWT minting, renewal, API key exchange, JWK generation |
| Audit API | api-audit | The change log |
Each exposes an OpenAPI document at /openapi/v1.json, with a JWT auth option wired into the UI.
API permissions has every endpoint in the product with its permissions in one table.
Authentication
Every request carries a JWT in the x-tagshape-auth header (or a cookie of the same name, from a browser). See
JWT for how to get one, and Headers for the full list.
The handful of endpoints that are anonymous are listed in API permissions.
Organization scoping
Every query is filtered by the org claim. An ID belonging to another organization answers 404, not 403 —
as far as the query is concerned the record is not there.
The organization is never a parameter. There is no way to ask a service about another organization's data, and no
endpoint accepts an organization ID for that purpose. (GET /users/{id}/permissions takes an organizationId
query parameter, but it is anonymous and exists for session renewal.)
Status codes
| Code | Used for |
|---|---|
200 OK | Read succeeded, or a write returning the resulting record |
201 Created | POST /users/me/apikeys only |
204 No Content | API key deletion |
400 Bad Request | Malformed input, or a valid request asking for something the caller may not have — such as a never-expiring key |
401 Unauthorized | An API key that named nobody; an unauthenticated audit write of a non-allow-listed type |
403 Forbidden | Permissions insufficient. Body does not say which. |
404 Not Found | Not there, or not in your organization |
409 Conflict | Two values of a variable carrying the same tag combination |
500 Internal Server Error | A fault on our side |
Errors use RFC 7807 problem details where the framework produces them:
{
"title": "Forbidden",
"detail": "You do not hold the permissions required for this request.",
"status": 403
}
List responses
Collection endpoints answer with a wrapper carrying a total alongside the items, so a pager knows how many pages there are:
{
"total": 42,
"items": [ … ]
}
items is a list for record collections, and an object keyed by name for the variable-value endpoints,
whose whole purpose is to be poured into a settings file.
The total is counted before paging and off the unordered query — how results are ordered makes no difference to
how many there are.
Paging, sorting and filtering
Supported by the audit list endpoints:
| Parameter | Default |
|---|---|
take | 10 |
skip | 0 |
sortField | LoggedAt |
sortDescending | false |
Filtering uses POST /filter with a body of filter objects rather than a query string, so a filter can carry more
than a string comparison. See the audit API.
Versioning and concurrency
Tag groups, library sets and variables carry a version that increments on update, plus createdAt,
createdById, updatedAt and updatedById. Send the version you read back on a PUT to detect a concurrent
change.
The library set API does not store users, so it asks the account API to put names to the IDs it holds — via
POST /users/names/lookup, which answers only about IDs it is given. That is why records come back with both a
raw createdById and a resolved createdBy: { id, name }.
Auditing
Every create, update and delete writes an entry to the audit API, carrying the before and after state as JSON. The one deliberate exception is import, which writes one entry describing the whole operation with counts rather than one entry per entity — a file with hundreds of variables in it would otherwise spend longer being audited than imported.
See Audit entries.
Service discovery
Services find each other through .NET Aspire service discovery rather than configured URLs:
| Service | Calls |
|---|---|
| Account | Audit |
| Identity | Account, Audit |
| Library set | Account, Audit |
| Auth UI | Identity, Account, Audit, Library set |
| Management UI | Account, Audit, Library set |
See Architecture.