Skip to content

OpenAPI (any internal API)

Any internal API with an OpenAPI 3 spec. GET only. Reads that look like they return secrets are refused until you say otherwise.

Policy openapi/<your-service>
Connection kind openapi
Upstream looks like https://orders.internal.example/api
Credential A read-only API key for your own API, or none
Tier 2 — Prodpeek is the only fence, and the profile says so
Time to set up about 5 minutes

Grant exactly these

The narrowest read-only key your API can issue

Prodpeek only ever sends GET and HEAD, and refuses every other operation the spec describes. If your API can mint a key that cannot write on its own, use it: then two fences hold instead of one.

No key at all, if the API has no authentication

Connect it with the credential header set to none. Nothing is sent and there is no drop link.

Do not grant these

Each of these would undo the point of the rest

An admin or service-owner key

The gateway refuses every write, but a key that can write is one bug in your API's own routing away from a write Prodpeek never saw as one. A GET handler that changes state is more common than it should be.

A key sent as a query parameter

The credential travels in a header you name. A key that only works in the URL ends up in your API's access logs, and Prodpeek does not put it there.

What it does

Your spec already says what your API can do. Prodpeek reads it and turns every operation into a tool, then decides each one:

  • GET or HEAD becomes an allowed read, with the spec's own enums, required parameters and maximums.
  • A parameter named limit, per_page, page_size, count or top is capped at 200, or lower if the spec says so.
  • A read that looks like it returns a secret is refused as read_leaks, with the word named. The words are token, secret, password, credential, api_key, private_key and connection_string, looked for in the path, the operationId, the summary, the parameters and the response fields.
  • A GET named like a change (logout, reset, purge, trigger, delete) is refused as write, for you to look at.
  • POST, PUT, PATCH and DELETE are refused as write. There is no way to allow one.

An argument the spec does not declare is refused too, rather than sent along.

Step 1: connect it

In the console: Services → Connect an internal API from its OpenAPI spec. Give it a name, the spec URL (or paste the document), and the header your API reads its key from. Leave the base URL empty to use the spec's servers[0].url.

From an agent:

add_openapi_service  name=orders  spec_url=https://orders.internal.example/openapi.json  auth_header=X-Api-Key

With no credential it returns a drop link for whoever holds the key.

The spec is fetched without a credential. If yours sits behind authentication, paste it instead.

Step 2: read what was generated

The policy lands in data/profiles/local/openapi/<name>.yaml, next to the spec it came from. It is yours to narrow: flip an allow to deny, lower a maximum. Prodpeek re-reads it on the next restart or refresh.

To accept a read that was refused as read_leaks because you have checked it does not return a secret, set it to allow, give it tier: 2, and add override: read_leaks_accepted. The console lists every such override in amber, and an agent calling prodpeek__explain sees them too.

A profile that allows a non-GET, or an operation the stored spec does not describe, or a read_leaks read without the override, is refused when it loads. The service then refuses every call until the file is fixed.

Step 3: when the API changes

Press Refresh spec (or call refresh_spec). Your edits are kept. Operations that disappeared are dropped. New reads arrive refused, noted new since, so nothing new is reachable before someone has looked at it. A read you allowed whose operation changed (it became a POST, or started returning a token) goes back to refused.

Check you got it right

  • [ ] Test connection lists your GET operations as allowed and every POST, PUT, PATCH and DELETE as refused.
  • [ ] Anything listed under 'these reads may return secrets' really does. Leave it refused unless you have checked.
  • [ ] The generated profile in data/profiles/local/openapi/.yaml says verification.status: example.

If an agent is reading this

Call add_openapi_service with the spec URL (or the document) and a service name, and hand the returned drop link to a human for the key. Never ask for the key in chat. If a read you need is refused as read_leaks, tell the human which one and why; only they can accept it, by editing the profile.

Then test it

Press Test connection and read the lists: allowed, refused by the policy, and refused because they may return secrets.