Tracker Categories API
Create reusable category tags and assign them safely to team-owned tracker projects.
Summary
Tracker categories use Eigenn's reusable team tags. The /tags resource manages category definitions and names. The /tracker-categories resource manages the relationship between a tag and a tracker project.
Capabilities
Endpoints
| Method | Endpoint | Scope | Purpose |
|---|---|---|---|
GET | /tracker-categories | tracker-projects.read | List category assignments |
GET | /tracker-categories/{id} | tracker-projects.read | Retrieve one assignment |
POST | /tracker-categories | tracker-projects.write | Assign one category |
POST | /tracker-categories/bulk | tracker-projects.write | Assign 1–100 categories |
DELETE | /tracker-categories/{id} | tracker-projects.write | Remove one assignment |
GET | /tags | tags.read | List reusable category definitions |
GET | /tags/{id} | tags.read | Retrieve one reusable tag |
POST | /tags | tags.write | Create a category definition |
PATCH | /tags/{id} | tags.write | Rename a category on every project that uses it |
DELETE | /tags/{id} | tags.write | Delete a category definition and its assignments |
Prerequisites
Your team must have authenticated access with permissions for tracker projects and tags. Each action requires specific API scopes depending on the resource being managed, as detailed per endpoint.
Concepts
A category is a reusable tag that can be assigned to one or many tracker projects. Categories are defined separately from their assignments, and all assignments reference the team-owned tag UUIDs. Editing or deleting a tag will impact every assignment that uses it. Assignment reads and deletes are scoped to the authenticated team; creation checks that both referenced records belong to that team. These tags are separate from transaction accounting categories selected by categorySlug. A tag can also be used on customers and transactions.
Workflow
Assign a Category
Create the tag first if it does not exist using POST /tags with { "name": "Design" }. The response is a bare { "id": "...", "name": "Design" } object. The current handler returns 200, although its OpenAPI declaration advertises 201. GET /tags returns the team’s definitions in data, ordered by name. Replace the example UUIDs below with real IDs, then attach the tag to a project.
curl --request POST \
--url https://api.eigenn.io/v1/tracker-categories \
--header "Authorization: Bearer $EIGENN_API_TOKEN" \
--header "Content-Type: application/json" \
--header "Idempotency-Key: category-project-design" \
--data '{
"projectId": "b3b6e2c2-1f2a-4e3b-9c1d-2a4b6e2c21f2",
"tagId": "b3b7c8e2-1f2a-4c3d-9e4f-5a6b7c8d9e0f"
}'Eigenn checks both UUIDs against the authenticated team before the insert. A UUID from another team returns 404. Eigenn creates no relationship.
The 201 response contains:
| Field | Description |
|---|---|
id | Assignment UUID for the retrieve and delete operations |
createdAt | Assignment timestamp |
projectId | Tracker project UUID |
tagId | Reusable tag UUID |
Use GET /tags and match the returned tag ID when you need the category's current display name.
List Assignments
GET /tracker-categories accepts:
projectId, an optional tracker project UUIDlimit, an integer from 1 to 100 that defaults to 50offset, a non-negative integer that defaults to 0
The response includes data plus meta.limit, meta.offset, and meta.returned. It does not include a total count. Increase offset by limit while returned equals limit. Stop when a page is shorter; a full final page requires another request.
Assignments are ordered by creation time, newest first. Changes during pagination can shift results, so avoid concurrent writes during a full inventory and deduplicate by assignment ID. A project filter with no matching team assignments returns empty data; it does not prove that the project exists or return an ownership error.
Bulk Assignment
POST /tracker-categories/bulk accepts:
{
"tags": [
{
"projectId": "b3b6e2c2-1f2a-4e3b-9c1d-2a4b6e2c21f2",
"tagId": "b3b7c8e2-1f2a-4c3d-9e4f-5a6b7c8d9e0f"
}
]
}Eigenn confirms every project and tag before the batch insert starts. A successful response uses 201 and returns the created assignments in data. This is an insert, not an upsert: duplicate project/tag pairs, including duplicates inside one batch, are rejected by the unique constraint. The batch is one insert statement, so a duplicate prevents that statement from inserting its other rows. An existing assignment is not silently reused.
Rename or Delete a Category
Rename through PATCH /tags/{tagId} with a required name field, for example { "name": "Research" }. The 200 response contains the tag ID and name. Projects reference the reusable tag UUID. Thus the new name appears on every assigned project. Eigenn does not replace the relationships.
Delete an assignment through DELETE /tracker-categories/{assignmentId} when only one project must lose the category. The assignment delete returns 200 with the deleted assignment. Delete the tag definition through /tags/{tagId} only when the tag must disappear from every project, customer, and transaction that uses it. The linked projects, customers, and transactions remain; their tag relationships are removed. The current tag-delete handler returns 200 with the deleted tag ID and name, although OpenAPI advertises 204.
Behavior specification
Missing Records and Retry Safety
Tracker-assignment GET and DELETE explicitly return 404 for an absent or foreign-team assignment. Assignment creation also returns 404 if a referenced project or tag is not in the team. The separate /tags/{id} handlers do not consistently map missing records to 404; GET, PATCH, or DELETE can return 500 instead.
Use a new idempotency key for each distinct mutation. The shared guard replays successful responses without comparing the new body, and does not cache failures as successful writes. After an uncertain response, list the saved tags and assignments before retrying.
Common Errors
| Status | Cause |
|---|---|
401 | Missing or invalid bearer token |
403 | Missing tracker project or tag scope |
404 | Assignment lookup/delete or assignment-creation reference check failed |
409 | Duplicate assignment when the database error is mapped, or an in-progress idempotency key |
400 / 422 | Invalid UUID, batch size, limit, offset, or request shape |
429 | Request-rate limit exceeded |
500 | Missing tag result, response-validation failure, or an unmapped database error |
Diagrams
Rendering diagram…
Screenshots
Not applicable: this page describes an API or a non-visual workflow rather than an application screen.
Verification
- Create a tag and confirm the response supplies its identifier.
- Assign the tag to a project in the same team and confirm the assignment appears when you list that project’s categories.
- Rename the tag and confirm the new name appears wherever the tag is used.
- Remove one assignment and confirm other assignments remain.
- Use a separate disposable tag to check that deleting a tag removes its project, customer, and transaction assignments without deleting those records.
- Check duplicate batches, foreign-team references, missing tags versus missing assignments, and offset pagination during concurrent changes.
These are pending runtime acceptance checks. Source review alone does not establish a verified deployment.