Labels, Tags & Organization
Labels are colored markers you attach to tickets for visual categorization
(e.g. bug, feature, urgent). Tags are arbitrary key-value pairs you attach
to any entity (projects, tickets, users, teams, time entries) for filtering and
reporting. This guide covers creating, assigning, searching, and filtering with
both.
1. Prerequisites
You need a running Alloy server and a registered user. Set these shell variables for the examples below:
BASE_URL="http://localhost:3000"
Register a user and capture the token:
curl -s -X POST "$BASE_URL/api/v1/auth/register" \
-H "Content-Type: application/json" \
-d '{
"email": "guide-lt@alloy.dev",
"password": "guide-lt-pass1",
"display_name": "LT Guide User"
}' | jq .
{
"user_id": "...",
"email": "guide-lt@alloy.dev",
"display_name": "LT Guide User",
"access_token": "..."
}
Save the token and user ID:
TOKEN="<access_token from above>"
USER_ID="<user_id from above>"
Create an organization:
curl -s -X POST "$BASE_URL/api/v1/orgs" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{
"name": "LT Guide Org",
"slug": "guide-lt-org"
}' | jq .
{
"id": "...",
"name": "LT Guide Org",
"slug": "guide-lt-org"
}
ORG_ID="<id from above>"
Create a project and a ticket for the examples that follow:
curl -s -X POST "$BASE_URL/api/v1/projects" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d "{
\"org_id\": \"$ORG_ID\",
\"key\": \"LTAG\",
\"name\": \"Labels Tags Demo\"
}" | jq .
{
"id": "...",
"org_id": "...",
"key": "LTAG",
"name": "Labels Tags Demo",
"ticket_counter": 0
}
PROJECT_ID="<id from above>"
curl -s -X POST "$BASE_URL/api/v1/projects/$PROJECT_ID/tickets" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d "{
\"title\": \"Tag demo ticket\",
\"priority\": \"Medium\",
\"reporter_id\": \"$USER_ID\"
}" | jq .
{
"id": "...",
"project_id": "...",
"ticket_number": 1,
"title": "Tag demo ticket",
"status": "Backlog",
"priority": "Medium",
"reporter_id": "...",
"created_at": "...",
"updated_at": "..."
}
TICKET_ID="<id from above>"
2. Create Labels
Labels belong to an organization and have a name and hex color. Create a few labels to categorize tickets:
curl -s -X POST "$BASE_URL/api/v1/orgs/$ORG_ID/labels" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "bug", "color": "#FF0000"}' | jq .
{
"id": "...",
"org_id": "...",
"name": "bug",
"color": "#FF0000",
"created_at": "...",
"updated_at": "..."
}
Create a second label:
curl -s -X POST "$BASE_URL/api/v1/orgs/$ORG_ID/labels" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "feature", "color": "#00FF00"}' | jq .
{
"id": "...",
"org_id": "...",
"name": "feature",
"color": "#00FF00",
"created_at": "...",
"updated_at": "..."
}
CLI shortcut:
alloy label create --org $ORG_ID --name bug --color "#FF0000"
3. List & Get Labels
List all labels in your organization:
curl -s "$BASE_URL/api/v1/orgs/$ORG_ID/labels" \
-H "Authorization: Bearer $TOKEN" | jq .
{
"items": [
{
"id": "...",
"org_id": "...",
"name": "...",
"color": "...",
"created_at": "...",
"updated_at": "..."
}
],
"next_cursor": null,
"has_more": false
}
Fetch a single label by ID:
curl -s "$BASE_URL/api/v1/labels/$LABEL_ID" \
-H "Authorization: Bearer $TOKEN" | jq .
{
"id": "...",
"org_id": "...",
"name": "...",
"color": "...",
"created_at": "...",
"updated_at": "..."
}
4. Update & Delete Labels
Rename a label or change its color with a PATCH:
curl -s -X PATCH "$BASE_URL/api/v1/labels/$LABEL_ID" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "critical-bug", "color": "#CC0000"}' | jq .
{
"id": "...",
"org_id": "...",
"name": "critical-bug",
"color": "#CC0000",
"created_at": "...",
"updated_at": "..."
}
To delete a label that is not in use, send a DELETE request. If tickets
reference the label, use ?cascade=true to remove all associations first
(or ?cascade=true&dry_run=true to preview the impact).
5. Assign Labels to Tickets
Add a label to a ticket:
curl -s -X POST "$BASE_URL/api/v1/tickets/$TICKET_ID/labels/$LABEL_ID" \
-H "Authorization: Bearer $TOKEN" | jq .
[
{
"id": "...",
"org_id": "...",
"name": "...",
"color": "...",
"created_at": "...",
"updated_at": "..."
}
]
List all labels on a ticket:
curl -s "$BASE_URL/api/v1/tickets/$TICKET_ID/labels" \
-H "Authorization: Bearer $TOKEN" | jq .
[
{
"id": "...",
"org_id": "...",
"name": "...",
"color": "...",
"created_at": "...",
"updated_at": "..."
}
]
To replace all labels on a ticket at once, POST a label_ids array:
curl -s "$BASE_URL/api/v1/tickets/$TICKET_ID/labels" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d "{\"label_ids\": [\"$LABEL_ID\"]}" | jq .
[
{
"id": "...",
"org_id": "...",
"name": "...",
"color": "...",
"created_at": "...",
"updated_at": "..."
}
]
To remove a single label from a ticket, send a DELETE:
curl -s -X DELETE "$BASE_URL/api/v1/tickets/$TICKET_ID/labels/$LABEL_ID" \
-H "Authorization: Bearer $TOKEN"
This returns 204 No Content.
CLI shortcut:
alloy ticket label add $TICKET_ID $LABEL_ID
6. Set Tags on Entities
Tags are key-value pairs that attach to any entity type: project, ticket,
user, team, or time_entry. Use PUT to set or upsert tags — if a key
already exists, its value is updated.
Tag a project:
curl -s -X PUT "$BASE_URL/api/v1/orgs/$ORG_ID/project/$PROJECT_ID/tags" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"tags": [
{"key": "department", "value": "engineering"},
{"key": "environment", "value": "staging"}
]
}' | jq .
[
{
"id": "...",
"org_id": "...",
"entity_type": "project",
"entity_id": "...",
"key": "department",
"value": "engineering",
"created_at": "...",
"updated_at": "..."
},
{
"id": "...",
"org_id": "...",
"entity_type": "project",
"entity_id": "...",
"key": "environment",
"value": "staging",
"created_at": "...",
"updated_at": "..."
}
]
Retrieve all tags on an entity:
curl -s "$BASE_URL/api/v1/orgs/$ORG_ID/project/$PROJECT_ID/tags" \
-H "Authorization: Bearer $TOKEN" | jq .
[
{
"id": "...",
"org_id": "...",
"entity_type": "project",
"entity_id": "...",
"key": "...",
"value": "...",
"created_at": "...",
"updated_at": "..."
}
]
Delete a single tag by key:
curl -s -X DELETE "$BASE_URL/api/v1/orgs/$ORG_ID/project/$PROJECT_ID/tags/environment" \
-H "Authorization: Bearer $TOKEN"
This returns 204 No Content.
Supported entity types:
project,ticket,user,team,time_entry
7. Search by Tags
Find all entities with a matching tag key-value pair using the search endpoint. Results are paginated.
curl -s "$BASE_URL/api/v1/orgs/$ORG_ID/tags/search?key=department&value=engineering" \
-H "Authorization: Bearer $TOKEN" | jq .
{
"items": [
{
"id": "...",
"org_id": "...",
"entity_type": "project",
"entity_id": "...",
"key": "department",
"value": "engineering",
"created_at": "...",
"updated_at": "..."
}
],
"next_cursor": null,
"has_more": false
}
This returns all tagged entities across types — projects, tickets, users,
teams, and time entries. Use the entity_type and entity_id fields in each
result to look up the full entity.
8. Filter Reports by Tags
Capitalization reports support tag-based filtering via the tag query
parameter. Use comma-separated key:value pairs to filter — multiple tags
combine with AND logic.
For example, to generate a report scoped to a department:
GET /api/v1/reports/capitalization?period=2026-03&tag=department:engineering
Combine multiple tags:
GET /api/v1/reports/capitalization?period=2026-03&tag=department:engineering,environment:production
See the API Reference — Capitalization Reports for the full set of query parameters and response format.
Next: Teams, Roles & Permissions covers managing who can do what within your organization.