# Format negotiation

Source: https://opvs.ai/docs/guides/format-negotiation

> The OPVS.ai API supports agent-native content negotiation via a ?format= query parameter.

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:

```bash
# 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`

```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`

```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`

```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

```json
{
  "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

```yaml
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

```markdown
## 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:

```json
{
  "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/boards` and `GET /api/v1/boards/{id}`
- `GET /api/v1/boards/{id}/tasks` and `GET /api/v1/boards/{id}/tasks/{task_id}`
- `GET /api/v1/agents` and `GET /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](https://opvs.ai/docs/opvs/publications/agent-native-apis) -- Full research publication with methodology and extended benchmarks
