Appearance
Pagination
Search endpoints return results one page at a time. Instead of page numbers, they use a cursor: an opaque string that marks where the last page ended. This applies to Search Tenders, Search Organisations and Organisation Tenders.
How it works
- Send your request with an optional
limit. Default is 25, maximum is 100. - The response contains a
pageobject. If there are more results,nextCursorholds a string. - Send the exact same request again with
cursorset to that string. - Repeat until
nextCursorisnull.
json
{
"tenders": [ ... ],
"page": {
"nextCursor": "eyJkIjoiMjAyNS0wMy0xNSIsImlkIjoiLi4uIn0",
"total": { "count": 4821, "capped": false }
}
}| Field | Type | Description |
|---|---|---|
page.nextCursor | string | null | Pass as cursor to get the next page. null on the last page. |
page.total | object | null | Number of matching results. Only present on the first page, null when you send a cursor. |
page.total.count | integer | Number of matches, counted up to 10 000. |
page.total.capped | boolean | true when there are more than 10 000 matches and count stopped at 10 000. |
Cursors are tied to the request
A cursor only works with the same filters, sort field and sort order it was created with. If you change anything, drop the cursor and start from the first page. Otherwise you get a 400 error with the message invalid cursor.
Example: fetch all pages
bash
# First page
curl -X POST https://api.tenderapi.eu/api/v1/tenders/search \
-H "Content-Type: application/json" \
-d '{"buyerCountries": ["SVN"], "limit": 100}'
# Next page, using nextCursor from the previous response
curl -X POST https://api.tenderapi.eu/api/v1/tenders/search \
-H "Content-Type: application/json" \
-d '{"buyerCountries": ["SVN"], "limit": 100, "cursor": "PASTE_NEXT_CURSOR_HERE"}'python
import requests
url = "https://api.tenderapi.eu/api/v1/tenders/search"
body = {"buyerCountries": ["SVN"], "limit": 100}
tenders = []
while True:
data = requests.post(url, json=body).json()
tenders.extend(data["tenders"])
cursor = data["page"]["nextCursor"]
if not cursor:
break
body["cursor"] = cursor
print(len(tenders))ts
const url = "https://api.tenderapi.eu/api/v1/tenders/search";
const body: Record<string, unknown> = { buyerCountries: ["SVN"], limit: 100 };
const tenders = [];
while (true) {
const res = await fetch(url, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(body),
});
const data = await res.json();
tenders.push(...data.tenders);
if (!data.page.nextCursor) break;
body.cursor = data.page.nextCursor;
}
console.log(tenders.length);Sorting
Tender endpoints accept sortBy and sortOrder. Sorting changes the order results come in, and therefore the cursor.
sortBy | Default sortOrder | Sorts by |
|---|---|---|
publicationDate | desc | Date the notice was published. This is the default. |
deadline | asc | Submission deadline. |
estimatedValue | desc | Estimated contract value, compared in EUR. |
sortOrder can be asc or desc. When you sort by deadline or estimatedValue, tenders that have no deadline or no estimated value are left out of the results.
json
{
"statuses": ["open"],
"sortBy": "deadline",
"sortOrder": "asc",
"limit": 50
}