We are running Backstage v1.37, and are trying to render our OpenAPI definitions by referencing them in the definition field, rather than hard-coding the content into our YAML files that define the catalog entry. Specifically as this allows the document itself to live separately from the Catalog entry.
In this case, we are specifically setting up an object of kind "API", as per docs, here: https://backstage.io/docs/features/software-catalog/descriptor-format/#kind-api
As an example, this is what the definition might look like:
---
apiVersion: backstage.io/v1alpha1
kind: API
metadata:
name: ourapi-api
description: An API that does things that we want it to do, because reasons.
title: Our API
annotations:
dev.azure.com/host-org: dev.azure.com/a-host-org
tags:
- net8
- api
links:
- url: https://domain.example/app/113235224
spec:
type: openapi
lifecycle: production
owner: my-owning-team
system: our-system
definition:
$text: https://domain.example/static/swagger.prod.json
As you can see, we're using the substitution setup, using $text to give us the option to pull in data from an external URL, in line with the documentation found here: https://backstage.io/docs/features/software-catalog/descriptor-format/#substitutions-in-the-descriptor-format
As "definition" is a text field, we must use $text. Using $json does not work (we have tried).
We have modified our Backstage app.config to include the relevant backend URLs we want to allow reading from, like so:
backend:
baseUrl: ...
reading:
allow:
- host: *.domain.example
Requesting the OpenAPI document from our hosting results in a 200 OK request, which looks like this, locally:

We've checked our OpenAPI doc is valid by pasting it into https://editor.swagger.io/, and receive no warnings / errors at all.
The actual error we receive from the Backstage UI is:
Unable to render this definition The provided definition does not specify a valid version field.
Please indicate a valid Swagger or OpenAPI version field. Supported version fields are swagger: "2.0" and those that match openapi: 3.x.y (for example, openapi: 3.1.0).
However, as you can clearly see in the screenshot above, the first property of the returned document is in fact the openapi version:
{
"openapi": "3.0.4",
"info": { ...
We are able to load the OpenAPI definition into Swagger UI hosted by our API, too, which suggests it is indeed valid.
As Backstage is not the most common tool, finding resources that touch specifically on this topic has not been easy - the ones that I have found, including asking CoPilot, google searching and looking at example repos, all seem to set things up in exactly the way described here. Any help would be appreciated!