Pagination
Every endpoint that returns a list of records is paginated. A page holds up to
20 records, and you move through pages with the page query parameter. Each
response tells you how big the full result is and gives you ready-made URLs for
the pages around you, so you rarely have to build a paging URL by hand.
Requesting a page
Pages are 1-based. Omit page and you get the first one.
curl "https://api.floracodex.com/v2/species?page=2" \
-H "Authorization: ApiKey YOUR_KEY"const res = await fetch("https://api.floracodex.com/v2/species?page=2", {
headers: { Authorization: "ApiKey YOUR_KEY" },
});
const data = await res.json();import requests
res = requests.get(
"https://api.floracodex.com/v2/species",
params={"page": 2},
headers={"Authorization": "ApiKey YOUR_KEY"},
)
data = res.json()The page size is fixed at 20 and is the same across every collection. There is no parameter to change it.
The response
A paginated response carries three top-level keys: data is the page of
records, links is the set of URLs for navigating, and meta describes the
result as a whole.
{
"data": [],
"links": {
"self": "/v2/species?page=2",
"first": "/v2/species?page=1",
"prev": "/v2/species?page=1",
"next": "/v2/species?page=3",
"last": "/v2/species?page=25"
},
"meta": {
"total": 481,
"per_page": 20,
"current_page": 2,
"last_page": 25
}
}
The meta block
Four fields, enough to render a page indicator or build your own paginator:
totalis the number of records that matched, across all pages.per_pageis the page size. Always 20.current_pageis where you are now, 1-based.last_pageis the index of the final page, equal toceil(total / per_page).
If you only need the result count, read total from page one and stop. You do
not have to walk the pages to know how many there are.
The links block
The links block hands you the URLs for the pages around the current one, so
walking a result set is a matter of following next until it is gone:
selfis the canonical URL for the page you are on.firstandlastare the ends of the result.prevandnextare the neighbors.
Two omissions tell you where the edges are. prev is absent on the first page,
and next is absent on the last. Treat their presence, not the page number, as
the signal to keep going:
let url = "https://api.floracodex.com/v2/species";
do {
const res = await fetch(url, {
headers: { Authorization: "ApiKey YOUR_KEY" },
});
const page = await res.json();
for (const record of page.data) handle(record);
url = page.links.next ? `https://api.floracodex.com/v2${page.links.next.replace("/v2", "")}` : null;
} while (url);import requests
url = "https://api.floracodex.com/v2/species"
while url:
res = requests.get(
url, headers={"Authorization": "ApiKey YOUR_KEY"}
)
page = res.json()
for record in page["data"]:
handle(record)
nxt = page["links"].get("next")
url = f"https://api.floracodex.com/v2{nxt.replace('/v2', '')}" if nxt else NoneEvery link preserves the query parameters from your original request. If you
asked for ?q=oak&order[year]=desc, the next and prev URLs carry that
search and sort forward, so each page lands on the same window. You do not have
to re-attach your filters when paging.
Empty results
When nothing matches, data is an empty array and meta.total is 0. The
links block keeps self but drops first, last, prev, and next, so
there is no "page 1 of 0" to special-case. Check total or the length of
data, not the links.