GunSpec
Pagination

Pagination

How a list is walked, what each plan may read of it, and every operation that pages. Read from the OpenAPI spec and the API's own limits, so the figures here are the ones the API enforces.

  • 41Operations with page + per_page
  • 6Capped lists with limit
  • 100Max per_page
  • 10,000Highest page number

Every list takes the same two query parameters, declared once in the spec and shared by every operation. Anything outside the bounds is a 400 with INVALID_PARAMETER; an unknown parameter is ignored, not refused.

pageinteger

Page number, from 1 to 10,000

Min
1
Max
10,000
Default
1
per_pageinteger

Items per page (max 100)

Min
1
Max
100
Default
20

per_page tops out at 100 almost everywhere. A larger ceiling (1000, 500, 50) applies to the bulk lists: /v1/firearms/media, /v1/contract/findings, /v1/data/tasks, /v1/updates.

6 operations are rankings rather than lists: they take a single limit, return the top rows and carry no pagination object: /v1/firearms/top, /v1/popular/firearms, /v1/stats/calibers/popular, /v1/stats/manufacturers/prolific, /v1/stats/feature-frequency, /v1/docs/guides/search.

A paged response wraps the page in the same object every time. The sample below is built from the schema's own examples, so it cannot drift from what the API sends.

Paged response
json
{  "success": true,  "data": [    /* one page of records */  ],  "pagination": {    "page": 1,    "per_page": 20,    "limit": 20,    "total": 42,    "totalPages": 3  }}
  • pagination.pageintegerrequired

    The page this response is, 1-based.

  • pagination.per_pageintegerrequired

    Page size. Same value as limit.

  • pagination.limitintegerrequired

    Page size. Alias of per_page.

  • pagination.totalintegeroptional

    Total records matching the query across every page.

  • pagination.totalPagesintegeroptional

    How many pages the result set spans at the current per_page.

Page-size is reported under both per_page (matching the request parameter) and limit (retained for existing integrations). They always carry the same value. total and totalPages are omitted for Explorer and anonymous callers.

The loop that works on every plan drives itself from the page it just received, not from totalPages. Four rules and the code in three languages.

DiagramReading every row of a list
100%
Reading every row of a listAsk for the largest page your plan allows, read the rows, and stop when a page comes back with fewer rows than you asked for. That is the last page on every plan. Do not drive the loop from total or totalPages: both are absent for anonymous and Explorer callers, so a loop testing page against totalPages reads one page and stops. Past your plan's page depth the answer is a 403, which is a signal to filter the list rather than to keep paging.
  1. 1Stop when a page comes back short. Fewer rows than per_page means it was the last page, on every plan.
  2. 2Treat total and totalPages as optional extras. They are absent on Explorer and anonymous calls, so a loop that tests page < totalPages stops after one page there.
  3. 3Ask for the largest page you can use. per_page=100 is 100× fewer requests against your per-minute limit and your daily allowance, and reaches the same rows.
  4. 4Walk once, then stay current by other means. Each page carries an ETag and answers 304 when unchanged, and data webhooks push catalog changes so a mirror never re-walks the list. More than 10 sequential pages inside 90 seconds is refused.
Read every rifle
cURL
# Page 1, then keep going while a page comes back fullcurl -H "X-API-Key: your_api_key" \  "https://api.gunspec.io/v1/firearms?category=rifle&per_page=100&page=1" curl -H "X-API-Key: your_api_key" \  "https://api.gunspec.io/v1/firearms?category=rifle&per_page=100&page=2"

Paging is where the plans differ most, and each rule below is enforced by the API rather than by convention. The figures come from the same configuration the middleware reads.

Page depth

The deepest page number a plan may request on the firearm lists. Past it the response is a 403; narrow the list with filters or upgrade.

Explorer
5 pages
Builder
25 pages
Studio
∞
Enterprise
∞

Total counts

Whether the envelope carries total and totalPages. Hidden on the free plan, so the size of the catalog cannot be read off a list.

Explorer
—
Builder
✓
Studio
✓
Enterprise
✓

Sequential-page burst

10 or more consecutive pages inside 90 seconds is a 429, per key or per address.

Aimed at crawlers. A reader paging a UI never reaches it; a script that wants the catalog should use per_page at its ceiling, filters, or webhooks.

Hard ceilings

page stops at 10,000 and per_page at 100 on every plan, including Enterprise.

A value above the ceiling is a 400, not a clamp: per_page=500 is refused rather than silently served as 100.

How a refused page request reads

  • The plan does not page this deep into a list. Narrow the list with filters, or upgrade for deeper paging.

  • Too many sequential pages in a short time. Slow the walk down, or use a larger per_page.

Where a list can be ordered it declares a sort vocabulary and an order direction; the default order is the one the reference shows for each. Every other list has a fixed order the operation's description states.

    • name
    • weight
    • year
    • caliber
    • created_at
    • favorites

    order: asc | desc

    • created_at
    • updated_at
    • status
    • priority

    order: asc | desc

41 operations take page and per_page and answer with the envelope; 6 take a single limit. Each row links to its reference page.

RowEndpointStyleDefaultMaxPlan
01/v1/firearmsList firearmspage + per_page20100Explorer
02/v1/firearms/searchFull-text searchpage + per_page20100Builder
03/v1/firearms/mediaIndex every firearm that has imagerypage + per_page2501000Explorer
04/v1/firearms/topRank firearms by a superlativelimit1025Builder
05/v1/features/iconsList feature iconspage + per_page20100Explorer
06/v1/firearms/by-featureFilter by featurepage + per_page20100Builder
07/v1/firearms/by-actionFilter by action typepage + per_page20100Explorer
08/v1/firearms/by-materialFilter by construction materialpage + per_page20100Builder
09/v1/firearms/by-designerFilter by designerpage + per_page20100Builder
10/v1/firearms/by-conflictFilter by conflictpage + per_page20100Studio
11/v1/firearms/power-ratingRank by composite power ratingpage + per_page20100Builder
12/v1/firearms/timelineBrowse the catalog chronologicallypage + per_page50100Builder
13/v1/popular/firearmsList the most viewed firearmslimit1020Explorer
14/v1/manufacturersList manufacturerspage + per_page20100Explorer
15/v1/manufacturers/{id}/firearmsList a manufacturer firearmspage + per_page20100Explorer
16/v1/calibersList caliberspage + per_page20100Explorer
17/v1/calibers/{id}/firearmsList firearms in a caliberpage + per_page20100Explorer
18/v1/calibers/{id}/ammunitionList ammunition for a caliberpage + per_page20100Builder
19/v1/ammunitionList ammunition loadspage + per_page20100Builder
20/v1/categories/{slug}/firearmsList firearms in a categorypage + per_page20100Explorer
21/v1/stats/calibers/popularRank calibers by adoptionlimit20100Explorer
22/v1/stats/manufacturers/prolificRank manufacturers by outputlimit20100Explorer
23/v1/stats/feature-frequencyRank features by frequencylimit50100Builder
24/v1/data/tasksList data remediation taskspage + per_page50500Explorer
25/v1/data/verificationsList accepted verificationspage + per_page20100Explorer
26/v1/data/sourcesList cited sourcespage + per_page20100Explorer
27/v1/data/outcomesList accepted results on catalogue taskspage + per_page20100Explorer
28/v1/data/gaps/recordsList records missing a fieldpage + per_page20100Enterprise
29/v1/data/confidenceGet per-record confidence scorespage + per_page20100Enterprise
30/v1/me/favoritesList your favoritespage + per_page20100Explorer
31/v1/me/reportsList your data reportspage + per_page20100Explorer
32/v1/me/supportList your support ticketspage + per_page20100Explorer
33/v1/me/webhooksList your webhook endpointspage + per_page20100Explorer
34/v1/game-stats/versions/{version}/firearmsList firearms in a snapshotpage + per_page20100Builder
35/v1/changelogList changelog entriespage + per_page20100Explorer
36/v1/updatesList site updatespage + per_page2050Explorer
37/v1/contract/findingsOne check's findings from the latest runpage + per_page1001000Explorer
38/v1/docs/guides/searchSearch the documentation guideslimit825Explorer
39/v1/blogList blog postspage + per_page20100Explorer
40/v1/attachmentsList attachmentspage + per_page20100Explorer
41/v1/attachments/{id}/firearmsList firearms an attachment fitspage + per_page20100Studio
42/v1/vendor/offersRead back your listingspage + per_page20100Enterprise
43/v1/interfaces/{id}/firearmsList firearms exposing a standardpage + per_page20100Studio
44/v1/papersList research paperspage + per_page20100Explorer
45/v1/releasesList new firearm modelspage + per_page20100Explorer
46/v1/changesList changes to the cataloguepage + per_page20100Explorer
47/v1/me/changesList changes to my saved firearmspage + per_page20100Explorer

The official SDKs expose an auto-paging iterator that applies every rule on this page: it fetches pages on demand, stops on a short page and never reads totalPages.

TypeScript
typescript
for await (const firearm of client.firearms.listAutoPaging({ category: 'rifle' })) {  console.log(firearm.name); // pages are fetched on demand}
Python
python
for firearm in client.firearms.list_auto_paging({"category": "rifle"}):    print(firearm["name"])  # pages are fetched on demand

Handing this to a coding agent? The agent packs and llms.txt carry the same rules in a form a model can act on: page from the short-page signal, cap per_page, and read error.reason on a 403 or 429 before retrying.