Tickets API walkthrough
This walkthrough exercises the deployed tickets application through its authenticated /v1/tickets/* routes. Those routes are available to onboarded accounts for managed preview and are absent from the generated public allowlist in the V1 route reference, so they are outside the self-service public API contract. It demonstrates the same Rust serde schema → CBOR → route → executor → dataset path described in the tickets architecture overview, using an sk-rg- key and curl.
Prerequisites
- A Redgold account and
sk-rg-API key. curlandjq.
Keep the key out of shell history by placing it in an environment variable:
export REDGOLD_API_KEY=sk-rg-...
export REDGOLD_API=https://api.redgold.ai
Every route below stamps or filters the authenticated caller as owner. Request bodies contain no ownerId field.
1. Create a ticket
create_response=$(curl --fail-with-body --silent --show-error \
"$REDGOLD_API/v1/tickets/upsert" \
-H "Authorization: Bearer $REDGOLD_API_KEY" \
-H "Content-Type: application/json" \
--data '{
"title": "Verify the example pipeline",
"body": "Run the documented request and record the result.",
"labels": ["docs", "example"],
"priority": 100
}')
ticket_id=$(printf '%s' "$create_response" | jq -r '.ticket_id')
printf 'created %s\n' "$ticket_id"
The response uses snake_case:
{
"ok": true,
"ticket_id": "tk-...",
"updated_ts_ms": 1785456000000
}
Creating a ticket without ticketId generates an id. Supplying an existing owned ticketId updates that ticket by appending another event.
2. Read it back
View one ticket. Requests use camelCase:
curl --fail-with-body --silent --show-error \
"$REDGOLD_API/v1/tickets/view" \
-H "Authorization: Bearer $REDGOLD_API_KEY" \
-H "Content-Type: application/json" \
--data "$(jq -nc --arg id "$ticket_id" '{ticketId: $id}')" | jq
List your tickets and filter by label:
curl --fail-with-body --silent --show-error \
"$REDGOLD_API/v1/tickets/list" \
-H "Authorization: Bearer $REDGOLD_API_KEY" \
-H "Content-Type: application/json" \
--data '{"label":"docs","limit":20,"offset":0}' | jq
The list response contains tickets and count. Results are newest-update first. Optional filters are state, label, limit, and offset.
3. Add and read a comment
curl --fail-with-body --silent --show-error \
"$REDGOLD_API/v1/tickets/comment" \
-H "Authorization: Bearer $REDGOLD_API_KEY" \
-H "Content-Type: application/json" \
--data "$(jq -nc --arg id "$ticket_id" \
'{ticketId: $id, body: "The example returned the expected rows."}')" | jq
Read the ticket's comments:
curl --fail-with-body --silent --show-error \
"$REDGOLD_API/v1/tickets/comments" \
-H "Authorization: Bearer $REDGOLD_API_KEY" \
-H "Content-Type: application/json" \
--data "$(jq -nc --arg id "$ticket_id" '{ticketId: $id}')" | jq
Comments are owner-scoped. A caller cannot use a ticket id to enumerate another account's ticket or comments.
4. Claim and release work
A claim records the executor identifier responsible for the ticket. Use a stable identifier from your own automation:
slot_id=docs-example-run
curl --fail-with-body --silent --show-error \
"$REDGOLD_API/v1/tickets/claim" \
-H "Authorization: Bearer $REDGOLD_API_KEY" \
-H "Content-Type: application/json" \
--data "$(jq -nc --arg id "$ticket_id" --arg slot "$slot_id" \
'{ticketId: $id, slotId: $slot}')" | jq
Release requires the exact slotId written by the successful claim. This prevents delayed cleanup from clearing a newer assignment:
curl --fail-with-body --silent --show-error \
"$REDGOLD_API/v1/tickets/release" \
-H "Authorization: Bearer $REDGOLD_API_KEY" \
-H "Content-Type: application/json" \
--data "$(jq -nc --arg id "$ticket_id" --arg slot "$slot_id" \
'{ticketId: $id, slotId: $slot}')" | jq
5. Close the ticket
curl --fail-with-body --silent --show-error \
"$REDGOLD_API/v1/tickets/close" \
-H "Authorization: Bearer $REDGOLD_API_KEY" \
-H "Content-Type: application/json" \
--data "$(jq -nc --arg id "$ticket_id" '{ticketId: $id}')" | jq
A final view should report state: "done".
Contract details
| Property | Contract |
|---|---|
| Authentication | Authorization: Bearer sk-rg-... |
| Requests | JSON with camelCase fields such as ticketId and slotId |
| Responses | JSON with snake_case fields such as ticket_id and updated_ts_ms |
| Ownership | Caller identity is verified at the edge; reads and writes are owner-scoped |
| Updates | Event-sourced; the latest event for a ticket id is the current view |
| States | open, in_progress, blocked, done, cancelled |
Pipeline implementation can move through staged rollout while this managed-preview HTTP contract remains under review. The routes are not a self-service public API until they appear in the generated V1 route reference.
Troubleshooting
401means the bearer key is missing, malformed, or revoked.400usually means a required camelCase field is absent or a state name is invalid.404means the route is unavailable on the selected host.{"error":"ticket not found"}means the ticket is absent or outside the caller's owner scope.- A failed release with an assignment mismatch means the ticket is held by a different
slotId; read the ticket before retrying.
Tickets
The issue-board app, walked end to end — one checked-in Rust serde schema encoded with CBOR, a set of pipeline routes, owner-scoped storage, and a GitOps deploy — as the worked example of the platform's narrow-app shape.
Case study: owner-scoped tickets
How the tickets application combines typed records, narrow routes, lifecycle transitions, and agent dispatch.