Skip to Content

How do I keep the credentials for JSON API endpoints safe when an AI SRE looks into crash loops?

Tares keeps the credential for a JSON API endpoint on the http_poll source, stored as a secret that the API never returns and exports never include. Tares polls the endpoint itself and stores one event per item. A Postgres source works the same way: its connection string is stored as a secret on the source.

How it works

Each source holds its own connection details, and Tares makes the requests.

  • JSON API credential. The credential field holds the whole header value. It is stored as a secret, never returned by the API and never exported. credential_header names the header it travels in, Authorization by default.
  • One credential, one header. Other headers the API wants on every request go in headers. That map is not secret, so keep keys and tokens out of it.
  • Postgres connection string. The dsn is stored as a secret. It is redacted in the API and left out of catalog exports.
  • Events come from polls. Tares calls the endpoint on the source’s schedule and stores one event per item. The payload is stored as received, so labels you declare later can still reach every field.

For more on the investigation side, see AI SRE.

Set it up

  1. In Tares, open Sources → Add source → HTTP API (poll).
  2. Fill in the method and URL. Put the secret in the credential field: one header name and one value, stored as a secret.
  3. Put non-secret headers in additional headers, and the JSON body for a POST.
  4. Press Discover. Tares calls the API once, shows the reply and fills in what becomes an event. Pick the entity key, then create the source.

In YAML, a bearer token for an API looks like this:

config: url: https://api.github.com/user credential: Bearer ghp_xxx # a bearer token credential_header: Authorization

An API key in a custom header looks like this:

config: url: https://api.example.com/v1/readings credential: abc123 # an API key credential_header: X-API-Key

You can also POST /api/sources with the same object.

For a database, open Sources → Add source → Postgres, enter the Connection URL (dsn) and press Discover. Tares lists the tables it can see and proposes the cursor and labels. Details are on the Postgres connector page.

- name: orders connector: postgres poll: 10s config: dsn: postgresql://user:pass@host:5432/appdb table: orders cursor_column: updated_at columns: id,tenant_id,status,amount,updated_at # empty = every column labels: - { name: tenant_id, field: tenant_id, primary: true } - { name: status, field: status }

Open the source afterwards. Recent events shows each poll’s events, and Fields lists every field seen with its coverage. The HTTP API (poll) connector page covers the reply mapping in full.

What you get

  • The secret stays on the source. The API does not return the credential or the dsn, and catalog exports leave them out.
  • Each source carries its own credential. A key you give one endpoint is not shared with another source.
  • Polling you can reason about. The connector refuses a poll under 10 seconds. On a 429 or any 5xx it backs off, doubling the wait from the poll interval up to an hour, and it uses Retry-After when the API sends it. Any other 4xx shows on the source’s health as a config error with the status and a slice of the reply.
  • A place to check the data. Recent events and Fields show what each poll stored, so you can confirm the key field is reliably present.

When something else fits

  • The credential field holds one header value. If an API needs more than one secret header, headers is not secret, so this connector is not a safe fit for that case.
  • If a system should call Tares instead of Tares calling it, use the webhook connector, which is for systems that call Tares.
  • If the data you need is already a table in your application database, the Postgres source with a dsn is the more direct path.

Still stuck? Get help

Last updated on