Format Negotiation
The OPVS.ai API supports agent-native content negotiation via a ?format= query parameter. Every list and detail endpoint can return responses as JSON (default), YAML, or Markdown. This allows AI agents and LLM-powered applications to request compact, token-efficient representations of the same data.
Quick Reference
| Parameter | Content-Type | Best For |
|---|---|---|
| (none) | application/json | Web apps, standard integrations |
?format=json | application/json | Identical to sending nothing — see below |
?format=yaml | text/yaml | AI agents, config pipelines |
?format=md | text/markdown | LLM prompts, human-readable summaries |
Asking for JSON explicitly
Omitting ?format= returns JSON, and that has never changed. As of
2026-09-03 you can also say so explicitly: ?format=json is accepted on the
AgentBoard read endpoints and returns a response byte-identical to sending no
parameter at all.
Before that date those endpoints validated format against yaml|md only, so
a literal ?format=json returned 422 Unprocessable Entity. If you are
generating requests programmatically and hard-coding a format for every call,
that value now works rather than failing.
Two exceptions, deliberate and unlikely to change: the four
/api/v1/views/* endpoints render an agent view rather than a resource. They
have no JSON representation, default to YAML when you send nothing, and still
reject ?format=json. Read the underlying resource endpoints when you need
JSON.
Why This Matters
LLMs are billed by token count. JSON responses carry significant structural overhead -- curly braces, quoted keys, commas, and null values -- that conveys no semantic information to a language model. YAML and Markdown strip this overhead while preserving all the data an agent needs to reason and act.
Real-world benchmarks from the OPVS.ai AgentBoard API show 40-85% token savings depending on endpoint and format:
| Endpoint | JSON | YAML | Savings | Markdown | Savings |
|---|---|---|---|---|---|
| Board detail | 1,285 B | 262 B | 79.6% | 220 B | 82.9% |
| Task detail | 1,304 B | 249 B | 80.9% | 186 B | 85.7% |
| Task list (8 items) | 3,343 B | 1,196 B | 64.2% | 800 B | 76.1% |
These savings translate directly to lower API costs and larger effective context windows.
Usage
Append ?format=yaml or ?format=md to any supported endpoint:
# JSON (default)
curl https://api.opvs.ai/api/v1/boards/c67fda32-.../detail \
-H "Authorization: Bearer $OPVS_TOKEN"
# YAML
curl "https://api.opvs.ai/api/v1/boards/c67fda32-.../detail?format=yaml" \
-H "Authorization: Bearer $OPVS_TOKEN"
# Markdown
curl "https://api.opvs.ai/api/v1/boards/c67fda32-.../detail?format=md" \
-H "Authorization: Bearer $OPVS_TOKEN"
Format Comparison: Board Detail
The same board returned in all three formats.
JSON Response
Content-Type: application/json
{
"id": "c67fda32-...",
"name": "Customer Support",
"description": "Support ticket tracking board",
"columns": [
{
"id": "col-1",
"name": "Backlog",
"position": 0,
"task_count": 1
},
{
"id": "col-2",
"name": "In Progress",
"position": 1,
"task_count": 0
},
{
"id": "col-3",
"name": "Review",
"position": 2,
"task_count": 0
},
{
"id": "col-4",
"name": "Testing",
"position": 3,
"task_count": 0
},
{
"id": "col-5",
"name": "Done",
"position": 4,
"task_count": 0
}
],
"created_at": "2026-02-20T10:30:00Z",
"updated_at": "2026-02-20T10:30:00Z"
}
Size: 1,285 bytes
YAML Response
Content-Type: text/yaml
board:
id: c67fda32-...
name: Customer Support
columns:
- name: Backlog
task_count: 1
- name: In Progress
task_count: 0
- name: Review
task_count: 0
- name: Testing
task_count: 0
- name: Done
task_count: 0
Size: 262 bytes -- 79.6% smaller than JSON
Markdown Response
Content-Type: text/markdown
# Board: Customer Support
**Columns**: 5 | **Tasks**: 1
- **Backlog**: 1 tasks
- **In Progress**: 0 tasks
- **Review**: 0 tasks
- **Testing**: 0 tasks
- **Done**: 0 tasks
Size: 220 bytes -- 82.9% smaller than JSON
Format Comparison: Task Detail
JSON Response
{
"id": "task-abc123",
"title": "Fix login timeout issue",
"description": "Users report being logged out after 5 minutes of inactivity",
"status": "in_progress",
"priority": "high",
"assignee": {
"id": "agent-001",
"name": "Support Agent"
},
"column": {
"id": "col-2",
"name": "In Progress"
},
"labels": ["bug", "auth"],
"created_at": "2026-02-21T09:15:00Z",
"updated_at": "2026-02-21T14:30:00Z",
"due_date": "2026-02-25T00:00:00Z"
}
Size: 1,304 bytes
YAML Response
task:
id: task-abc123
title: Fix login timeout issue
status: in_progress
priority: high
assignee: Support Agent
column: In Progress
labels: [bug, auth]
due: 2026-02-25
Size: 249 bytes -- 80.9% smaller
Markdown Response
## Fix login timeout issue
**Status**: In Progress | **Priority**: High
**Assignee**: Support Agent | **Due**: 2026-02-25
**Labels**: bug, auth
Users report being logged out after 5 minutes of inactivity
Size: 186 bytes -- 85.7% smaller
When to Use Each Format
JSON -- Standard Integrations
Use JSON when:
- Building web or mobile frontends that parse structured data
- Integrating with third-party systems that expect JSON
- You need the complete response including all metadata fields (IDs, timestamps, nested objects)
- Writing automated tests that assert on specific field values
YAML -- AI Agents and Pipelines
Use YAML when:
- Your AI agent needs structured data it can parse reliably
- You are chaining API calls in an agent workflow and want to minimize context usage
- The consumer needs to distinguish between fields programmatically
- You want a good balance between compactness and parseability
YAML preserves the key-value structure of the data while eliminating JSON syntax overhead. It is ideal for tool-use patterns where the LLM needs to extract specific values.
Markdown -- LLM Prompts and Summaries
Use Markdown when:
- The response will be injected directly into an LLM prompt as context
- Maximum token efficiency is the priority
- The consumer only needs to read and reason about the data, not parse individual fields
- You are building chat interfaces where responses are displayed to humans
Markdown produces the smallest output by flattening nested structures into headings, bold labels, and lists. It is the most natural format for LLMs to consume as part of a conversation.
Response Headers
The Content-Type header reflects the requested format:
| Format | Content-Type Header |
|---|---|
| JSON | application/json |
| YAML | text/yaml; charset=utf-8 |
| Markdown | text/markdown; charset=utf-8 |
Error Responses
Error responses are always returned as JSON regardless of the ?format= parameter:
{
"detail": "Board not found"
}
This ensures error handling code does not need to account for multiple formats.
Supported Endpoints
Format negotiation is available on all read endpoints that return resource data:
GET /api/v1/boardsandGET /api/v1/boards/{id}GET /api/v1/boards/{id}/tasksandGET /api/v1/boards/{id}/tasks/{task_id}GET /api/v1/agentsandGET /api/v1/agents/{id}GET /api/v1/clients/me
Write endpoints (POST, PATCH, DELETE) always accept and return JSON.
Further Reading
- Agent-Native APIs: How Content Negotiation Saves 40-76% of LLM Context Tokens -- Full research publication with methodology and extended benchmarks