Pingtower Docs
Docs The addons agent httpcheck

httpcheck

Fetch a URL and time every stage of it separately, because a slow resolver and a slow server wake up different people.

Parameters

ParameterDefaultMeaning
urlREQUIREDhttp or https.
methodGET
headersMap of request headers.
bodyRequest body, sent as-is.
expect_status200Any other status is down. The default is dropped when an assertion targets status; set explicitly, it applies as well.
body_matchesRE2 pattern the body must match, else down.
max_ttfbTime to first byte above this is degraded.
follow_redirectstrue
assertionsUp to 20 checks on the response. All must pass, else down. See Assertions.
authnonebasic, bearer, mtls or oauth_client_credentials. See Authentication.
auth_usernameUser name for basic.
client_certClient certificate for mtls, inline PEM (one or more certificates), not a path.
oauth_token_urlToken endpoint for oauth_client_credentials.
oauth_client_idClient id for oauth_client_credentials.
oauth_scopesList of scopes to request.
oauth_paramsMap of extra form fields sent to the token endpoint, such as audience.
oauth_client_authbasicHow the client id and secret reach the token endpoint: basic (an Authorization header) or body (form fields).

expect_status and body_matches work as before. A check without a status assertion behaves exactly as it did.

Assertions

Each assertion has a target, an operator and a value, which is always a string. header and jsonpath also take a property: the header name, or the JSONPath into a JSON body.

TargetpropertyOperators
statusequals, not_equals, less_than, greater_than
response_time_msequals, not_equals, less_than, greater_than
headerheader nameall six
jsonpathJSONPathall six
body_sha256equals, not_equals

The six operators are equals, not_equals, contains, matches (an RE2 pattern), less_than and greater_than. response_time_ms is total_ms: from the start of the request until the body has been read. less_than and greater_than compare numbers. body_sha256 takes 64 hex characters, in either case. body_sha256 and jsonpath read at most the first 1 MiB of the body; a larger body fails them.

with:
  url: https://api.acme.example/v1/status
  assertions:
    - {target: status, operator: equals, value: "200"}
    - {target: header, property: Content-Type, operator: contains, value: json}
    - {target: jsonpath, property: $.database.state, operator: equals, value: ok}
    - {target: response_time_ms, operator: less_than, value: "800"}

Assertions run in list order and stop at the first failure. That one makes the run down and is named in the result, numbered from 1, with what the response actually had (a secret the response echoes back shows as [redacted]):

assertion 2 (header Content-Type contains "json") failed: got "text/html"

The event also carries its number as the key failed_assertion (a string, "2") next to detail.

Authentication

authSettingsSecret
basicauth_usernamePASSWORD
bearerTOKEN
mtlsclient_certCLIENT_KEY, the PEM private key
oauth_client_credentialsoauth_token_url, oauth_client_id, and optionally oauth_scopes, oauth_params, oauth_client_authCLIENT_SECRET

The secret is never a with parameter. Set from the portal or the API, it is sealed at rest and write-only: reading the check back shows which secrets are set, never their values. A secret is tied to exactly where it is sent: any change to url, oauth_token_url or the method, even only the path, or a change to client_cert, without sending the secret again is refused with a 422. So is adding a region or source to sources: env: sources now include <names> the env was not sealed for; re-supply env (or send {} to clear it). Removing or reordering sources keeps it.

So authentication that needs a secret works only on checks Pingtower assigns to the agent, not on checks in a local agent.yaml. A local check naming one of these auth types is refused when the config loads:

param auth: bearer needs env TOKEN, which only a tower-assigned check carries

With basic, bearer or oauth_client_credentials, an Authorization entry in headers is refused, as is a setting that belongs to another mode. Assertions work the same in both.

With oauth_client_credentials, the agent fetches a token from oauth_token_url and reuses it until 30 seconds before it expires. If the target answers 401, the next run fetches a fresh one. The token request goes through the same network guard as the check itself.

Measurements

KeyUnit
dns_ms, connect_ms, tls_ms, ttfb_ms, total_msmilliseconds, each stage on its own
body_bytesbytes

Rules for it

{"name":"slow-ttfb","match":{"tags":["addon:httpcheck"]},
 "conditions":[{"key":"ttfb_ms","op":"gte","value":500}]}
{"name":"probe-down","match":{"tags":["addon:httpcheck"],"min_level":400},
 "fire_after":{"count":2,"window_minutes":5,"distinct_sources":true}}
Last updated 4 Oct 2026 Report a problem with this page