← Blog
API Blueprint & Formats

API Blueprint Media Types: Documenting Content-Type Negotiation

API Blueprint Media Types: Documenting Content-Type Negotiation

In API Blueprint, media types are declared directly inside + Request and + Response blocks using parentheses after the status code or request label. Apidoke renders those declarations in its three-column live viewer and passes the correct Content-Type header when a reader fires a request from the try-it console, so the server always receives the type you specified, not a browser default.

  • Every request and response in API Blueprint can carry an explicit media type in parentheses, for example + Response 200 (application/json).
  • The plus-sign format modifier (for example application/json+hal or application/vnd.myapi.v2+json) signals both the base format and the structured extension, and Apidoke preserves the full string in the rendered docs.
  • A single action can document multiple response media types by repeating the + Response block with a different type, giving readers a clear side-by-side of what the server can return.
  • Vendor media types (the vnd. prefix) are the right choice when your API returns a custom schema; declaring them explicitly stops consumers from guessing what the body structure is.

What is content-type negotiation and why does it belong in your docs?

Content-type negotiation (sometimes called content negotiation) is the HTTP mechanism by which a client and server agree on the format of a response body. The client sends an Accept header listing the types it can handle; the server replies with the type it actually used in the Content-Type response header. When those two do not align, the server should return a 406 Not Acceptable status code, as defined in RFC 9110, Section 12.

Documenting that negotiation is not optional. If your reference docs only show application/json examples but your API also accepts application/xml or a vendor type like application/vnd.myapi.order+json, consumers write clients that hard-code the wrong type, hit 406 or 415 errors, and spend hours debugging. Good media-type documentation prevents that entirely.

How API Blueprint represents media types

API Blueprint is a Markdown-based format built on top of the API Blueprint specification. The specification treats media types as first-class citizens of every transaction, not as an afterthought buried in a prose paragraph.

The basic syntax

The type goes in parentheses immediately after the status code on a + Response line, or after a request label on a + Request line:

## Create Order [POST /orders]

+ Request (application/json)

    + Body

            {
                "product_id": "SKU-001",
                "quantity": 3
            }

+ Response 201 (application/json)

    + Body

            {
                "id": "ord_8821",
                "status": "created"
            }

When Apidoke publishes this, the navigation column lists the action, the centre column renders the type labels, and the try-it console pre-fills both the Content-Type: application/json request header and expects a JSON body in return. No configuration is needed beyond what you wrote in the Blueprint.

What happens when you omit the media type?

The API Blueprint specification treats a missing type as unspecified, not as application/json by default. Some parsers fall back to a tool-level default, but you should never rely on that. Always declare the type explicitly. If a response truly has no body, use status codes like 204 No Content and leave the body block out entirely.

The plus-sign format modifier explained

The structured syntax media type modifier, commonly called the plus-sign modifier, is an IANA convention described in RFC 6838, Section 4.2.8. It takes the form type/subtype+suffix, where the suffix tells a generic parser how to decode the bytes even if it does not understand the specific subtype.

Common examples:

Media type stringWhat it meansWhen to use it
application/jsonPlain JSON, no schema impliedGeneric REST responses
application/hal+jsonHAL hypermedia, serialised as JSONHypermedia APIs following the HAL spec
application/problem+jsonRFC 9457 problem details, serialised as JSONStandardised error bodies
application/vnd.myapi.v2+jsonVendor type, version 2, JSON-encodedVersioned custom schemas
application/xmlPlain XMLEnterprise or legacy integrations
application/vnd.myapi.order+xmlVendor order schema, XML-encodedTyped XML responses for a specific resource

In API Blueprint, you drop the full string into parentheses exactly as it appears. The parser does not validate or transform it:

+ Response 200 (application/hal+json)

    + Body

            {
                "_links": {
                    "self": { "href": "/orders/ord_8821" },
                    "items": { "href": "/orders/ord_8821/items" }
                },
                "id": "ord_8821",
                "status": "created"
            }

Documenting vendor media types

Vendor media types use the vnd. prefix in the subtype to signal that the format belongs to a specific organisation or product. They give your consumers a precise contract: if a client sends Accept: application/vnd.myapi.order+json and gets a 200, it knows the body conforms to your order schema, not some generic JSON structure it has to guess at.

Real-world vendor type example

# Group Orders

## Order [/orders/{id}]

+ Parameters
    + id: `ord_8821` (string, required) - Unique order identifier

### Retrieve an Order [GET]

+ Request

    + Headers

            Accept: application/vnd.myapi.order+json

+ Response 200 (application/vnd.myapi.order+json)

    + Body

            {
                "id": "ord_8821",
                "customer_id": "cust_441",
                "total_cents": 5999,
                "currency": "USD",
                "status": "dispatched"
            }

+ Response 406 (application/problem+json)

    + Body

            {
                "type": "https://docs.myapi.com/errors/not-acceptable",
                "title": "Not Acceptable",
                "status": 406,
                "detail": "Supported types: application/vnd.myapi.order+json"
            }

Notice that the 406 response uses application/problem+json. That is the correct type for error bodies under RFC 9457 and it tells the client's error-handling code exactly what shape to parse, even in a failure path.

Documenting multiple accepted media types on one action

Real APIs often serve the same resource in two or more formats. API Blueprint handles this by repeating the + Response block with a different type. The spec allows multiple response blocks on a single action, and Apidoke renders each one as a labelled tab in the response section so readers can compare them without scrolling through a wall of prose.

### Retrieve a Product [GET /products/{id}]

+ Parameters
    + id: `prod_77` (string, required) - Product identifier

+ Response 200 (application/json)

    + Body

            {
                "id": "prod_77",
                "name": "Mechanical Keyboard",
                "price_cents": 12999
            }

+ Response 200 (application/xml)

    + Body

            ```xml
            
            
              prod_77
              Mechanical Keyboard
              12999
            
            ```

The same pattern applies to + Request blocks when a POST or PUT endpoint accepts multiple inbound formats. Repeat the block for each type the server can parse, include a realistic body, and Apidoke does the rest.

Side-by-side comparison of two API Blueprint response blocks in a 3-column doc layout, showing JSON and XML tabs in the response pane

Documenting the Accept and Content-Type request headers explicitly

Sometimes you want to document the headers themselves rather than relying on the parenthetical shorthand. The + Headers sub-block inside a + Request lets you show the exact header the client should send, including the quality factor (q) syntax used in real Accept header negotiation:

+ Request JSON with quality preference

    + Headers

            Accept: application/vnd.myapi.order+json;q=0.9, application/json;q=0.8
            Content-Type: application/json

    + Body

            {
                "quantity": 1
            }

This is useful when your API supports preference ordering. A q value (quality factor) runs from 0 to 1; the client prefers the highest number. Showing this in the docs tells integrators they can send a preference list, not just a single fixed type.

Combining media types with MSON attribute descriptions

MSON (Markdown Syntax for Object Notation) is the API Blueprint sub-language for describing data structures inline. When you combine MSON attributes with a typed response, readers get both the schema and the wire format in one place. The deep-dive on API Blueprint request and response bodies covers MSON attributes in detail; the short version is that you add an + Attributes block alongside your + Body block:

+ Response 200 (application/vnd.myapi.order+json)

    + Attributes (object)
        + id: `ord_8821` (string, required) - Unique order identifier
        + total_cents: 5999 (number, required) - Total in cents
        + currency: `USD` (string, required) - ISO 4217 currency code
        + status: `dispatched` (enum[string], required)
            + Members
                + `pending`
                + `dispatched`
                + `cancelled`

    + Body

            {
                "id": "ord_8821",
                "total_cents": 5999,
                "currency": "USD",
                "status": "dispatched"
            }

The MSON block describes the schema; the Body block shows a concrete sample. Both sit under the same typed response, so the consumer knows exactly what application/vnd.myapi.order+json looks like in schema and in reality.

Common media-type documentation mistakes to avoid

Using a generic type when a vendor type applies

If your endpoint returns a custom envelope with a predictable schema, document it as a vendor type. Using application/json for everything tells the consumer nothing about the shape. Vendor types are a free, standards-backed way to communicate schema identity without extra infrastructure.

Forgetting the 415 and 406 error responses

A 415 Unsupported Media Type fires when the server cannot parse the request body type. A 406 Not Acceptable fires when the server cannot produce any type matching the client's Accept header. Both should appear as documented response variants. Leaving them out means your error handling section is incomplete, and consumers will be confused the first time they hit one in production.

+ Response 415 (application/problem+json)

    + Body

            {
                "type": "https://docs.myapi.com/errors/unsupported-media-type",
                "title": "Unsupported Media Type",
                "status": 415,
                "detail": "Request body must be application/json or application/vnd.myapi.order+json"
            }

Mixing up charset parameters

Some APIs append a charset to the media type, for example application/json; charset=utf-8. That semicolon-separated parameter is valid in HTTP headers but the API Blueprint parenthetical shorthand passes it through verbatim. Be consistent: either always include it or rely on the HTTP/1.1 default (UTF-8 for JSON) and leave it out. Inconsistency across response blocks confuses readers and linters alike.

How Apidoke's try-it console handles declared media types

When a reader opens Apidoke's three-column published view and clicks the try-it console for an action that declares application/vnd.myapi.order+json, the console pre-populates the Content-Type and Accept fields with that exact string. The reader can override them before firing the request. The HTTP call goes directly from the reader's browser to your API server; Apidoke's servers never see the request body or any auth tokens the reader enters. That matters when your API sits behind an auth wall and you want to let consumers test live without routing their credentials through a third-party proxy.

For more on the broader publishing and authoring workflow, the API Blueprint and Formats pillar hub is the best starting point, covering everything from basic structure to advanced mechanics like the ones described here.

Apidoke try-it console pre-filled with a vendor media type in the Content-Type field, showing a live 200 response in the right pane

Step-by-step: adding content negotiation to an existing Blueprint

  1. Open your Blueprint in Apidoke's split-pane CodeMirror editor and locate the action you want to update.
  2. Add the specific media type in parentheses on the + Request line, replacing any bare + Request label you had before.
  3. Add a matching + Response 200 (your/vendor+type) block with a realistic body sample.
  4. Add a second + Response 200 block for any alternative format the endpoint supports (for example XML or a different vendor type).
  5. Add + Response 406 and + Response 415 blocks with application/problem+json bodies describing what went wrong.
  6. Check the live preview pane on the right; Apidoke renders each response block as a labelled tab immediately.
  7. Publish. The version history records this snapshot so you can roll back if you change the media types in a future release.

Frequently asked questions

Can I document the same endpoint accepting both JSON and XML in API Blueprint?

Yes. Repeat the + Request block twice under the same action, once with (application/json) and once with (application/xml), each with its own body sample. Apidoke renders them as separate labelled variants in the published view.

What is the difference between application/json and application/vnd.myapi+json?

The vnd. prefix signals a vendor-specific media type registered to your organisation. It tells consumers the body conforms to your defined schema, not just generic JSON. Using a vendor type is a standards-backed way to version and identify your API's response shape without inventing a custom header.

Do I need to register my vendor media type with IANA?

Technically yes for production public APIs, but in practice many teams use unregistered vnd. types internally without issue. If your API is public-facing and widely consumed, registering the type with IANA prevents collisions with other organisations using the same string. The registration process is documented at iana.org.

What status code should my API return if none of the client's Accept types are supported?

Return 406 Not Acceptable, as specified in RFC 9110. The response body should list the types your server can actually produce so the client can retry with a supported type. Document all three (the 200, the 406, and the 415) in your Blueprint so consumers know what to expect.

Does API Blueprint validate that my body matches the declared media type?

No. The specification records the media type as a documentation declaration, not a schema validator. Validation is the job of a separate tool or a test harness on your server. Your Blueprint body sample should be accurate, but the parser will not reject it if you paste XML under an application/json declaration.

Ready to publish API docs that document content negotiation clearly and let readers test real endpoints without installing anything? Create your free Apidoke account and paste your first Blueprint into the editor in minutes.