Documentation
How to consume the Vulnetix TEA server as another provider: DNS discovery, the OWASP OpenAPI specifications we target (0.4.0), and public unauthenticated example requests with their real responses.
The Transparency Exchange API is an OWASP specification for resolving software transparency data (SBOMs, VEX documents, attestations, and where a release is actually obtained) starting from a single identifier and following DNS.
Vulnetix runs a conformant TEA server. This page is for the other side of the exchange: you are a TEA provider, or building a TEA client, and you want to read what we publish.
TEA is developed in the open by the OWASP TEA working group. We track the specification rather than extending it. An implementation that adds fields is not interoperable, it is a dialect.
| Document | Where |
|---|---|
| Consumption API (the contract below) | CycloneDX/transparency-exchange-api → spec/openapi.yaml |
| Publication API (not yet upstream) | 0x73746F66/transparency-exchange-api → spec/publisher/openapi.yaml |
We currently target specification version 0.4.0, which is what our discovery document advertises. The publication document is generated from the consumption document so the two cannot drift apart.
Resolution starts from a domain, never from a URL somebody handed you. Take the domain out of whatever identifier you hold (a TEI, a purl, a vendor contact) and fetch its discovery document.
curl https://vulnetix.com/.well-known/tea
{
"schemaVersion": 1,
"endpoints": [
{
"url": "https://www.vulnetix.com/tea",
"versions": ["0.4.0"],
"priority": 1
}
]
}
versions: the specification versions this server implements.url: the API root. Append the major version you selected: https://www.vulnetix.com/tea/v1.priority: orders endpoints where a server advertises several.Every example below uses https://www.vulnetix.com/tea/v1 as the base.
If you already hold a TEI, /discovery tells you which product release it names and which servers can answer for it. This is the step that lets a client arrive knowing one string and nothing else.
curl 'https://www.vulnetix.com/tea/v1/discovery\
?tei=urn%3Atei%3Auuid%3Avulnetix.com%3A54e8820d-0803-5a4f-858d-88a279486564'
[
{
"productReleaseUuid": "8b406807-739d-5b4b-aae6-18ffb9e56c17",
"servers": [
{
"rootUrl": "https://www.vulnetix.com/tea/v1",
"versions": ["0.4.0"]
}
]
}
]
The TEI must be percent-encoded, because it contains colons.
A server that will not say what it publishes cannot be exchanged with, so the catalogue is readable with no credential. Only objects whose publisher marked them public appear here.
curl 'https://www.vulnetix.com/tea/v1/products?pageSize=2'
{
"hasNext": false,
"nextPageToken": "",
"results": [
{
"uuid": "54e8820d-0803-5a4f-858d-88a279486564",
"name": "Vulnetix/cli",
"identifiers": [
{
"idType": "TEI",
"idValue": "urn:tei:uuid:vulnetix.com:54e8820d-0803-5a4f-858d-88a279486564"
},
{ "idType": "PURL", "idValue": "pkg:github/Vulnetix/cli" }
]
}
]
}
Page with nextPageToken while hasNext is true.
A product holds releases. A product release points at the component releases it is assembled from, so follow components[].release, because that is where the downloads and the evidence live.
curl 'https://www.vulnetix.com/tea/v1\
/product/54e8820d-0803-5a4f-858d-88a279486564/releases'
{
"hasNext": false,
"nextPageToken": "",
"results": [
{
"uuid": "e5fe63be-d3d0-5b7a-a3bc-39525d15cf88",
"version": "v3.83.0",
"releaseDate": "2026-08-02T05:55:17Z",
"components": [
{
"uuid": "41714f49-4f06-5a3b-96d4-c83f7d78a270",
"release": "3e6a317c-6027-5448-abd7-5f260cec7e4b"
}
]
}
]
}
One read returns both halves, and they answer different questions:
distributions: how the release is obtained. Binaries with checksums, and install channels like Homebrew or Scoop that have no single file to fetch.latestCollection: the evidence published about the release: SBOMs, VEX documents, attestations.An SBOM is not an answer to “where do I download this”, which is why TEA keeps them apart.
curl 'https://www.vulnetix.com/tea/v1\
/componentRelease/3e6a317c-6027-5448-abd7-5f260cec7e4b'
{
"release": {
"uuid": "3e6a317c-6027-5448-abd7-5f260cec7e4b",
"componentName": "Vulnetix/cli",
"version": "v3.83.0",
"identifiers": [
{ "idType": "PURL", "idValue": "pkg:github/Vulnetix/cli@v3.83.0" }
],
"distributions": [
{
"distributionId": "c5142319-96cc-5959-ab0b-04e05462a28d",
"description": "vulnetix-darwin-amd64",
"url": "https://github.com/Vulnetix/cli/releases/download/v3.83.0/vulnetix-darwin-amd64",
"checksums": [
{
"algType": "SHA-256",
"algValue": "93d9a6b3ac331b8866f494c56b2be62a2593f18e341cfed8206cf2be37e4b846"
}
]
},
{
"distributionId": "…",
"description": "Homebrew: brew install Vulnetix/tap/vulnetix",
"url": "https://github.com/Vulnetix/homebrew-tap"
}
]
},
"latestCollection": {
"version": 1,
"updateReason": { "type": "INITIAL_RELEASE" },
"artifacts": [
{
"name": "vulnetix.cdx.json",
"type": "BOM",
"formats": [
{
"mediaType": "application/vnd.cyclonedx+json",
"url": "https://www.vulnetix.com/tea/v1/artifact/30054fe0-f6f8-58e8-970e-8105568bcd70/1/download"
}
]
}
]
}
}
That release carries 14 distributions in total: one per published binary, plus the install channels. Artifact url values are direct downloads and need no credential either.
The tea command speaks this protocol against any conformant server, not only ours. Point --server anywhere:
vulnetix tea discover vulnetix.com
vulnetix tea products --server https://www.vulnetix.com/tea/v1
vulnetix tea collection 3e6a317c-6027-5448-abd7-5f260cec7e4b
vulnetix tea resolve urn:tei:uuid:vulnetix.com:54e8820d-0803-5a4f-858d-88a279486564
Reading a public catalogue needs no credentials. See tea in the CLI reference for publishing your own.
Authentication is optional, and it only ever widens what you can see: a credential gets you objects shared with your organisation in addition to the public ones. It is never required to read a public catalogue. That is what makes this an exchange rather than a portal.
If you do send a credential it must be valid. An unrecognised one is refused with 401 rather than quietly downgraded to anonymous, so a stale key fails loudly instead of silently hiding the releases you expected to see.
| Scheme | Header |
|---|---|
| Bearer token | Authorization: Bearer <token> |
| API key | Authorization: ApiKey <orgId>:<hmac> |
| Basic | Authorization: Basic base64(orgId:hmac) |
404, not 403. Telling you an object exists but is not yours is itself a disclosure.