Short references

Short references

Reference. The identifier grammar the OPVS agent surfaces accept, which routes resolve each shape, and the routes that still require a full UUID. This page describes what the API accepts; it is not a tutorial.

Every board has a key (OPS) and every card a number, so a card can be named OPS-142 instead of 86a304a8-f951-4403-b099-74895f7ce4e7. Every UUID you have already stored keeps working, unchanged, forever. Short refs are an addition, not a migration.

The six shapes

A value in an identifier position is classified by shape before anything else happens to it.

Shape Grammar Example Resolves to
Board key ^[A-Z][A-Z0-9]{1,5}$ OPS a board
Task ref ^[A-Z][A-Z0-9]{1,5}-[0-9]{1,9}$ OPS-142 a card
Column ref ^[A-Z][A-Z0-9]{1,5}/[a-z0-9][a-z0-9_-]{0,63}$ OPS/backlog a column
Agent slug ^@[a-z0-9][a-z0-9_-]{0,63}$ @martin an agent
Short code ^[a-z]{1,3}_[0-9a-z]{7}$ pkg_b021dyc a typed entity
UUID prefix 8 or more hex characters 86a304a8 any entity, by prefix

Full UUIDs are accepted everywhere and are passed through untouched.

Case matters, and only in one direction. A board key and a task ref are uppercase: ops is not OPS and will not resolve. A UUID may be given in either case.

A ref is stable for the life of the board. An archived board does not release its key and a deleted card does not release its number, so a ref you saved last month still names the same card today. That is a deliberate trade: the uniqueness constraints are full, not partial.

Where refs resolve — paths

Resolution happens per route shape, at a single choke point, before the request reaches its handler. Only positions that are genuinely identifiers are touched, so /api/v1/boards/templates is left alone: templates is a real route segment, not a failed ref.

GET /api/v1/boards/{board_id}

board_id accepts a board key, a UUID prefix, or a full UUID.

curl -H "Authorization: Bearer $OPVS_PAT" \
     https://api.opvs.ai/api/v1/board/boards/OPS

Response

{ "id": "86a304a8-f951-4403-b099-74895f7ce4e7", "key": "OPS", "name": "Ops & Infra" }

Errors:

Status Trigger Resolution
404 the key names no board in your tenant check the key; keys are uppercase, ops is not OPS
409 a UUID prefix matched more than one board add characters until the prefix is unique
403 the board belongs to another brand use a board your token is scoped to

GET /api/v1/boards/{board_id}/tasks/{task_id}

Both positions resolve independently. The two-identifier shape is matched before the bare /boards/{board_id} rule, so the task position is never left uncanonicalized.

curl -H "Authorization: Bearer $OPVS_PAT" \
     https://api.opvs.ai/api/v1/board/boards/OPS/tasks/OPS-142

Response

{ "id": "d28c485b-ecd8-4127-bcbb-151a108023a6", "ref": "OPS-142", "title": "Rotate the WG hub key" }

Errors:

Status Trigger Resolution
404 either position failed to resolve verify the board key and the card number separately
409 an ambiguous UUID prefix in either position the response names which position was ambiguous
403 the board belongs to another brand use a board your token is scoped to

GET /api/v1/tasks/{task_id}

Accepts a task ref, a UUID prefix, or a full UUID. The same rule covers /api/v1/activity/tasks/{task_id} and /api/v1/views/tasks/{task_id}.

curl -H "Authorization: Bearer $OPVS_PAT" \
     https://api.opvs.ai/api/v1/board/tasks/OPS-142

Response

{ "id": "d28c485b-ecd8-4127-bcbb-151a108023a6", "ref": "OPS-142", "status": "in_progress" }

Errors:

Status Trigger Resolution
404 the ref names no card in your tenant a card in another brand returns 404, not 403, by design
409 an ambiguous UUID prefix add characters, or use the task ref instead

GET /api/v1/columns/{column_id}

Accepts a column ref, a UUID prefix, or a full UUID. A column ref pairs the board key with the column slug.

curl -H "Authorization: Bearer $OPVS_PAT" \
     https://api.opvs.ai/api/v1/board/columns/OPS/backlog

Response

{ "id": "ab962d15-eb04-44b9-9345-85a3a7d8dc79", "name": "Backlog", "slug": "backlog" }

Errors:

Status Trigger Resolution
404 the board key or the column slug is wrong slugs are lowercase; list the board to see them
409 an ambiguous UUID prefix add characters until unique

GET /api/v1/files/{file_id}

Accepts a short code, a UUID prefix, or a full UUID.

curl -H "Authorization: Bearer $OPVS_PAT" \
     https://api.opvs.ai/api/v1/board/files/f_7k2m9qd/download

Response

{ "id": "0ef17ab8-106c-4f8a-be2a-ad81fbbbc78a", "short_id": "f_7k2m9qd", "filename": "diagram.png" }

Errors:

Status Trigger Resolution
404 the code names no file in your tenant check the prefix; a code from another table will not resolve
409 an ambiguous UUID prefix add characters until unique

GET /api/v1/agents/{agent_id}/tasks

Accepts an agent slug, a UUID prefix, or a full UUID.

curl -H "Authorization: Bearer $OPVS_PAT" \
     https://api.opvs.ai/api/v1/board/agents/@martin/tasks

Response

{ "tasks": [ { "ref": "OPS-142", "title": "Rotate the WG hub key" } ], "total": 1 }

Errors:

Status Trigger Resolution
404 the slug names no agent in your tenant slugs are lowercase and start with @
409 an ambiguous UUID prefix add characters until unique

Where refs resolve — request bodies

Identifiers also travel in JSON bodies. Body resolution walks a declared allowlist of field names, never a blanket rewrite, so a card titled "OPS-142 is blocked" is not mangled.

Field Resolves as
board_id, from_board_id, to_board_id, link_from_board_id, link_to_board_id board
task_id, parent_task_id, source_task_id, target_task_id, depends_on task
column_id column
assigned_to_agent_id agent

Two fields are deliberately excluded, and treating either as a ref would corrupt a valid request: blocked_by is a link type, not an id; depends_on_refs holds batch-local aliases naming other cards in the same bulk payload, which do not exist yet and are resolved further downstream.

A body ref that does not resolve is left untouched and forwarded, so you get the downstream field-level 422 rather than a blunt gateway 404. An ambiguous body ref is the exception and still raises 409.

Where refs do NOT resolve

Five parameter slots require a full UUID. This is not an oversight and it is stated on each parameter individually, rather than as a blanket promise that quietly breaks:

Operation Parameter Why
getBoardSummary board_id query parameter, no body
getTaskDistribution board_id query parameter, no body
searchTasks board_id query parameter, no body
removeBoardFromProject board_id path shape matches no rule
sendEmailFromCard task_id the two-identifier rule needs a literal /tasks/ segment

Across the agent tool surface this is 5 UUID-only slots against 52 ref-capable ones. Each is labelled in the tool description your agent reads, so it knows before it calls rather than after it fails.

Ambiguity returns 409, not a guess

A UUID prefix that matches more than one row never picks one. It returns:

{
  "error": "ambiguous_ref",
  "ref": "86a304a8",
  "kind": "task",
  "candidates": ["86a304a8-...-a1", "86a304a8-...-b7"],
  "message": "'86a304a8' matches 2 tasks. Use more characters."
}

Add characters until it is unique. Eight hex characters is the minimum, not a guarantee.

Short codes for main-API entities

Four entity types outside the board carry a typed short code, returned alongside the UUID:

Prefix Entity
hir_ an agent hire
psn_ a persona
env_ an environment
pkg_ an installed package
{ "id": "7abd705b-fde3-4753-a5a7-0a174e665f7b", "short_id": "pkg_b021dyc", "state": "active" }

The prefix is part of the identity: a code from the wrong table will not resolve against the right one.

Cost

Zero extra queries when every identifier is already a canonical UUID, which is what the dashboard and every pre-existing integration send. Work is proportional to the number of short refs in a request, not to traffic. Refs are grouped by kind, so a body carrying depends_on with ten refs costs one query, not ten.

Powered by OPVS
Short references | OPVS