API Rate Limits and Efficient Polling
The TridentStack Control API limits how many requests a caller can send in a period of time. The limits protect the platform for every customer, and they are set well above what a well-built integration needs. This page explains how to tell when you are close to a limit, what to do when you reach one, and how to get the data you need in as few requests as possible.
How the limits apply
- Requests made with an API key count toward that key's own limits. Reading data and changing data have separate allowances, so a busy report does not hold up a change.
- All of your organization's API keys also share an overall allowance, so creating more keys does not raise the total.
- Requests without a valid API key are limited per source IP address. Every request that reaches the API from the same office, home network, or cloud egress address without a valid key shares one allowance.
- Some endpoints have their own, stricter limits, mainly ones that change data or handle sensitive settings.
The exact numbers may change as the platform grows. Build your integration to read the headers below rather than relying on a fixed number.
Reading the rate limit headers
Responses from rate-limited endpoints include standard headers that tell you where you stand:
| Header | Meaning |
|---|---|
RateLimit-Limit | The number of requests allowed in the current window. |
RateLimit-Remaining | How many requests you have left in the current window. |
RateLimit-Reset | Seconds until the window resets. |
If RateLimit-Remaining is getting low, slow down before you reach zero.
Handling a 429 response
When you go over a limit, the API returns 429 Too Many Requests with a Retry-After header giving the number of seconds to wait.
- Stop sending requests from that integration.
- Wait at least the number of seconds in
Retry-After. - Resume at a slower pace. If you get another 429, double the wait each time and add a small random delay, so several clients do not retry at the same moment.
The response body names the limit you reached: key-read or key-write for one API key, tenant-read or tenant-write for all of your organization's keys together.
Do not retry a 429 immediately or in a tight loop. Every retry counts as a request and keeps the limit in place longer.
Getting more done with fewer requests
Start with a summary, then drill down
Most questions can be answered from a list endpoint with a filter. Ask for the summary first and fetch per-endpoint detail only for the rows that need it. Fetching detail for every endpoint, one request at a time, is the most common way integrations hit the limits.
Filter on the server
Use the filters an endpoint offers, such as status, policy, or endpoint, instead of downloading everything and filtering in your own code. The API Reference lists the filters for each endpoint.
Use the largest page size
When you need a full list, request the maximum page size the endpoint allows. Fewer, larger pages cost fewer requests than many small ones.
Send requests one at a time
Run requests in sequence from a single queue rather than in parallel. Parallel requests reach the limit faster and gain little, because they share the same allowance.
Poll no faster than the data changes
Data in TridentStack Control updates on a schedule. For example, Endpoint Checks results update on each policy's evaluation interval, so polling more often than that returns the same answer. Choose a polling interval that matches how fresh you need the data to be, and keep what you have already read instead of reading it again.
Use one API key per integration
Give each integration its own API key. It is easier to tell your integrations apart in the audit log, and you can revoke one without affecting the others. Each key also has its own allowance, so one busy integration does not slow the others down.
Example: reporting on Endpoint Checks
To keep a dashboard or ticketing system in step with Endpoint Checks, ask for what changed instead of re-reading every endpoint:
- List policies with counts.
GET /api/agent-validation/policies?withCounts=truereturns every policy with its endpoint count and failing count in one request. Skip a policy only when itsfailingCountis0. If the counts are missing from a response, treat them as unknown and check that policy in the next step. - First run: read everything that is failing once.
GET /api/agent-validation/results?status=failed&limit=1000returns one row per failing endpoint and check. FollownextCursoruntil it isnull, and keep theasOfvalue from the response. - Every poll after that: ask what changed.
GET /api/agent-validation/results?changedSince=<asOf>returns only the checks whose status changed since then. A row with statusfailedstarted failing, or is a new failing result. A row with statuspassedrecovered, or is a new passing result, such as a check newly added to a policy or an endpoint newly in scope. Apply each row to your own records. FollownextCursoruntil it isnull, then keep theasOffrom that response for the next poll; every page carries the sameasOf, so storing the first page's value and stopping early loses the later pages.asOftrails the current time by about two minutes so that no change is missed, so always use the value the response gives you rather than your own clock. A poll with nothing new returns an empty list. - Once a day, repeat step 2. An endpoint that joins or leaves a policy's scope, a policy that is turned off and on again, and a failure caused by a tag condition may not appear as changes, and results that changed before this feature was introduced have no change time. Reading the failing set again about once a day reconciles those. Send the
ETagfrom your last response in anIf-None-Matchheader. It returns304when no result in the set changed, including evaluation times, so on an active fleet expect a full response most of the time. A304still counts toward your rate limits.
For a full report instead, GET /api/agent-validation/policies/compliance-report.csv returns one row per failing endpoint and check, with the failure reason and when the check first failed on that endpoint. That date is not reset when a check recovers and later fails again. Add policyId to limit it to one policy. A very large report returns 413 Payload Too Large; if that happens, request it one policy at a time. You can also page through one policy's failing endpoints with GET /api/agent-validation/policies/{id}/cohort?status=failing&limit=100, which returns the failing endpoints with their failing checks, plus status totals for the whole policy.
Read one endpoint's full results only when you need every check on that endpoint: GET /api/agent-validation/agents/{agentId}/results?policyId={id} returns that endpoint's checks with each one's status, an explanation of the result, and when it was last evaluated. For an endpoint with a very large number of checks the response is shortened, with failing checks listed first, and truncated is true. Do not treat a truncated response as the complete list.
For most fleets, one full read of the failing set followed by changedSince polls answers "what is failing right now" with a small request each time.
Guidance for AI assistants
If an AI assistant, such as one connected through an MCP server, calls the TridentStack Control API for you, give it these instructions:
- Plan the requests before making them, and use the summary and filtered endpoints above before any per-endpoint request.
- Do not fetch detail for every endpoint in a loop. Fetch detail only for the items the question is about.
- Send requests one at a time.
- On a 429 response, stop, report it, and wait for the
Retry-Afterperiod before trying again. Do not retry in a loop.
The TridentStack Control documentation MCP server can look up this page and the API Reference, so an assistant can check the right endpoint and its filters before calling the API.