An API Responded: Does It Cover the Data You Need?
Check API data completeness with a coverage matrix, pagination evidence and a worked Search Console example. Keep unknown data out of false totals.
A reporting job receives a successful API response, parses the rows and produces a chart. The chart can still describe only part of the population the business asked about. Before accepting the report, check API data completeness against that intended population.
The useful question is specific: did this extraction cover the required periods, categories and entities, at the level of detail needed for this decision? An empty page, a shorter table and a different total each need an explanation. They do not all mean the connector lost records.
Define the population before counting rows
Write the intended decision first. “Report the complete customer base” is too loose if the endpoint returns only active customers visible to one account. “Count active customers in the agreed regions at the reporting cutoff” gives the reviewer a population to check.
Record what one row means: a customer, an event, a day, a page or an aggregate. A row count is not automatically the population size. Keep the requested scope separate from the scope the source can actually expose.
For API data completeness, build one row in a coverage matrix for each required slice:
| Record | What to capture | What it prevents |
|---|---|---|
| Population | Required entities/categories; inventory or unknown count |
Calling a subset the whole population |
| Period | Dates, timezone, final-data cutoff |
Mixing periods |
| Row and metric | Row meaning, aggregation, metric unit |
Comparing unlike counts |
| Request | Endpoint/version, role, filters and grouping |
Missing scope restrictions |
| Extraction | Pages/cursors, end condition, duplicate-key check |
Stopping after page one |
| Source limits | Caps, withholding, unsupported or unknown scope |
Promising unavailable data |
| Decision | Comparable control, gap, permitted use |
Passing an unresolved gap |
Choose the expected slices before inspecting the result. Otherwise, a missing category can disappear from both the report and its definition of completeness.
Separate pagination from source coverage
Start with the endpoint’s paging contract. For example, GitHub documents next-page links in the response header. It also notes that an excessive requested page size can be reduced while the request still succeeds. A successful first request therefore does not establish that the caller consumed all available pages.
Record the continuation evidence, follow the documented termination rule and check duplicate keys. For a changing dataset, also record whether the source offers a stable snapshot or whether records can move between requests. Do not invent snapshot consistency because a cursor exists.
Then ask a different question: does exhausting those pages expose the whole required population? The Search Analytics API reference says its internal limits can restrict results to top rows. It documents a maximum rowLimit of 25,000 and paging with startRow; consuming those pages does not remove the source’s reporting limits.
Increasing the page size can address a paging mistake. It cannot establish that withheld or unsupported data has become available.
A measured example: four views of the same period
In a first-party Search Console extraction retrieved on 16 October 2026, the requested window was 16 September–13 October 2026, inclusive: 28 days in Pacific Time. Every request used web search, final data and no dimension filters. The property and individual page/query keys are omitted here; the table contains aggregate measurements only.
The request settings shared these values:
{
"startDate": "2026-09-16",
"endDate": "2026-10-13",
"type": "web",
"dataState": "final",
"rowLimit": 25000,
"startRow": 0
}
The four requests grouped by no dimensions, date, page and query, respectively. They requested byProperty, except the page request, which used auto. The last column names the aggregation returned by the API.
| View | Rows | Impressions | Clicks | Returned grain |
|---|---|---|---|---|
| Property | 1 | 443 | 5 | byProperty |
| Daily | 28 | 443 | 5 | byProperty |
| Pages | 50 | 466 | 5 | byPage |
| Queries | 29 | 40 | 1 | byProperty |
Each returned set was below the requested page size; the saved extraction recorded paging as exhausted. All expected date keys were present and unique. Summing the daily rows reproduced the property total. These checks establish agreement for the requested daily view. They do not prove that every underlying search or query is available.
The page total is larger because it uses a different counting level. Google’s property-versus-page documentation distinguishes a property appearing in a result from the individual URLs appearing there. The 466 page impressions are not a substitute for 443 property impressions, and their difference is not evidence of lost ingestion.
The query view answers another question. Google documents anonymized queries and row truncation: query details are not an exhaustive view of all search activity. Here, visible query rows accounted for 40 of the 443 property impressions. The remaining 403 impressions had no attribution in that returned query view. That is not a count of 403 missing records, nor evidence that every part of the gap has one cause.
This is one small reporting window, not a benchmark or a growth result. The original responses were retained and their arithmetic rechecked on 19 October. The saved data does not identify every reason for the query gap, and the underlying query population is unknown.
Turn the example into a coverage decision
The same extraction can be suitable for one task and insufficient for another. Use a decision column rather than a single “complete” flag for the whole source.
| Required slice | Evidence from the example | Permitted conclusion |
|---|---|---|
| Daily summary | 28 expected date keys; sum matches property total |
Matched for this period and aggregation |
| Page distribution | 50 page rows;byPage response |
Returned page view; not a property total |
| Query inventory | 29 visible rows; unknown population count |
Unknown coverage; not an exhaustive inventory |
| Query attribution | 40 query impressions / 443 property impressions |
Partial attribution; no complete intent breakdown |
An independent control must match the claim. Daily and dimensionless property totals provide a reconciliation check, but both come from the same provider. They cannot independently certify that provider’s underlying collection. For an entity inventory, a separately maintained list can supply a denominator only if its scope and cutoff also match.
Copy this coverage worksheet
Create one record per required slice. Keep observations blank until checked; record why a field is unknown or not applicable.
Decision this data must support:
Required slice / entities / categories:
Expected population and basis, or UNKNOWN with reason:
Period / timezone / final-data cutoff:
Source / endpoint version / authorised role:
Filters / grouping / returned aggregation:
Meaning of one row / metric unit:
Returned row count / distinct key count / metric total:
Paging evidence / termination / snapshot limitation:
Documented source caps / withholding / unsupported scope:
Comparable control and its limitations:
State / unresolved gap / evidence reference:
Permitted claim / blocked claim:
Reviewer / decision date / next check:
Use explicit states. Matched means the declared check agrees with its control. Partial means a known part of the required detail is available. Unknown means the evidence does not establish coverage. Missing means a required slice has no validated result. Use not applicable only with a reason agreed for the task.
A measured zero is a value, not a replacement for any of those states. A failed request, an omitted date and a genuinely observed zero need separate records. Search Analytics can omit dates without data; its query reference recommends an unfiltered date query to identify days with data. If that control cannot resolve an absent day, keep the slice unresolved instead of filling it with zero.
Test the report’s acceptance rule
Before accepting a connector, use synthetic fixtures to test the final reporting decision:
- Leave a next-page indicator unconsumed. The extraction must not claim paging is finished.
- Supply an aggregate at a different grain. The report must not treat it as a matching control.
- Remove a required slice or fail its request. The result must stay missing or unknown rather than defaulting to zero.
- Leave the expected population unknown. The report must not calculate a completeness percentage from the returned rows alone.
- Mark a slice outside the agreed task. Preserve the reason for excluding it instead of silently improving a score.
These are proposed acceptance tests, not a claim that every connector has been tested here. The silent-no-op audit case covers another boundary: whether a pipeline produced fresh, usable output. This worksheet asks which population that output can represent.
If the team cannot explain the request scope, reconcile comparable totals or name an unresolved slice, request an audit scope with the source, intended decision and one redacted example. Agree the permitted use of the data before an agent turns it into a confident business conclusion.
- Name the required population and the unit of each returned row.
- Keep pagination exhaustion separate from the source's reporting limits.
- Compare totals only when period, filters and aggregation agree.
- Retain unknown and withheld slices in the acceptance record.