Skip to Content

How do I keep JSON API credentials safe when an AI SRE looks into slow database queries?

Tares keeps credentials on the source, stored as secrets, and the agent works with the events the source produces, not the connection. The http_poll connector sends one credential in one header, and the Postgres connector takes a connection string as a secret. Neither is returned by the API or included in exports.

How it works

Each source holds its own connection details. When an AI SRE investigates slow database queries, it works from the events those sources have stored in the timeline.

JSON API endpoints (http_poll)

  • Tares calls the endpoint itself on the source’s schedule and stores one event per item. No script runs on your side.
  • credential holds the whole credential value and is stored as a secret. The API never returns it and exports never include it.
  • credential_header names the header that carries it. The default is Authorization.
  • Other headers the API needs go in headers. That map is not secret, so put only non-sensitive values there.

Postgres (postgres)

  • The dsn is the source’s connection URL, in the form postgresql://user:pass@host:port/dbname.
  • The dsn is stored as a secret. The API redacts it and catalog exports omit it.
  • Tares polls the table incrementally on a cursor column and stores one event per new or changed row.
  • columns limits which columns are pulled. The cursor, key and time columns are always included.

The agent’s view is the event stream. For an http_poll source that is the summary line and the payload fields. For a Postgres source it is the rows you chose to pull.

See the HTTP API (poll) connector and the Postgres connector for every field.

Set it up

  1. Decide which endpoint reports on slow queries, and which table holds the data you want next to it.
  2. Add the JSON API source. Go to Sources → Add source → HTTP API (poll). Fill in the method and URL, and enter the credential as one header name and value. 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.
  3. Or create the same source from YAML, or with POST /api/sources. A bearer token goes in the Authorization header:
config: url: https://api.github.com/user credential: Bearer ghp_xxx # a bearer token credential_header: Authorization
  1. 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
  1. Add the Postgres source. Go to Sources → Add source → Postgres, enter the Connection URL and press Discover. It lists the tables it can see and proposes the cursor, entity key and labels. Choose your columns and save. The YAML form is:
- 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 }
  1. You can also ask a connected agent to set a source up. For Postgres it calls discover_source, then test_source for a dry run that fetches sample rows, then create_source.
  2. Verify. Open each source. Recent events shows what each poll stored, and Fields lists every field seen with its coverage.

What you get

  • Credentials live in one place, the source configuration, as secrets. The API returns neither the credential nor the dsn in clear text, and exports leave both out.
  • The agent investigates from events and labels, so it needs no copy of the connection string or the API header.
  • Tares polls the API and the table itself, so no script holds the credential.
  • The polling is gentle on the upstream API. Tares refuses a poll under 10 seconds. It backs off on a 429 or any 5xx, and the wait doubles from the poll interval up to an hour. A 429 with Retry-After uses that value.
  • Problems show up on the source. Any other 4xx appears as a config error on the source’s health, with the status and a slice of the reply. A rate limit appears as “rate limited by the API, next try at HH:MM”. The backoff clears on the next good poll.
  • Payloads are stored as received, so labels you declare later can still reach every field.

When something else fits

  • If an API needs more than one secret header, note that http_poll sends one credential in one header, and the headers map is not secret.
  • If a system should push events to Tares instead of Tares polling it, the webhook connector fits better than http_poll.
  • If the data you need is in a table, use the Postgres connector instead of an API. It needs a Postgres reachable from the Tares host and a column that only ever grows as its cursor.

Still stuck? Get help

Last updated on