On this page

API

Pagination

Collections return data, next_cursor and has_more. Pass next_cursor back as cursor, size pages with limit up to 100, and let the SDKs follow pages for you.

Every collection returns an object, never a bare array:

json
{
  "data": [ { "id": "itm_invoiceextr2", "full_name": "acme/invoice-extractor" } ],
  "next_cursor": "eyJlIjoxNzkzNzYxODYxLCJkIjpb...",
  "has_more": true,
  "total": 37
}
FieldMeaning
dataThe page of results, in the order the operation documents.
next_cursorAn opaque string. Pass it back as cursor to get the next page. It is null on the last page.
has_moretrue while there is another page. Stop on has_more: false.
totalThe number of matches, present on search where it is cheap to count. Do not rely on it elsewhere.

Parameters

ParameterMeaning
limitPage size from 1 to 100, default 30. The ledger feed (list_ledger_events) allows up to 500. A larger value answers 400 invalid_parameter with errors[0].code: "out_of_range".
cursorThe next_cursor of the previous page. Send it with the same filters and sort.

Cursors

  • A cursor is opaque. Do not build, parse or store it for later: it encodes the sort position of the last row and a signature, and it expires after 24 hours.
  • Because it encodes a position rather than an offset, rows inserted while you page do not cause duplicates or skipped rows.
  • A cursor that is tampered with, expired, or used with different filters answers 400 invalid_cursor. Restart the listing from the first page.
  • The response also has a Link: <...>; rel="next" header that mirrors next_cursor, for clients that follow links.

Walking every page

curl

bash
cursor=""
while :; do
  page=$(curl -sS -G https://reuseforge.com/api/v1/items --data-urlencode 'q=pdf' --data-urlencode 'limit=100' ${cursor:+--data-urlencode "cursor=$cursor"})
  echo "$page" | jq -r '.data[].full_name'
  [ "$(echo "$page" | jq -r .has_more)" = "true" ] || break
  cursor=$(echo "$page" | jq -r .next_cursor)
done

Python

python
import reuseforge

client = reuseforge.Client()
page = client.search_items(q="pdf", limit=100)
print(page.data[0]["full_name"], page.has_more, page.next_cursor)

for item in client.search_items(q="pdf"):                 # iterating fetches further pages lazily
    print(item["full_name"])
for item in client.search_items(q="pdf", max_items=250):  # stop after 250 rows
    pass
for p in client.search_items(q="pdf").pages():            # page objects instead of rows
    print(len(p.data))

JavaScript

javascript
import { ReuseForge } from '@reuseforge/sdk';

const client = new ReuseForge();
const first = await client.searchItems({ q: 'pdf', limit: 100 });     // a Page: first.data, first.has_more, first.next_cursor
const next = await first.nextPage();                                  // null when there is none

for await (const item of client.searchItems({ q: 'pdf' })) console.log(item.full_name);   // lazily, across pages
const some = await client.searchItems({ q: 'pdf', maxItems: 250 }).toArray();
for await (const page of client.searchItems({ q: 'pdf' }).pages()) console.log(page.data.length);

CLI

bash
rf search pdf --limit 100               # one page; the JSON output has next_cursor
rf search pdf --cursor eyJ...           # the next page
rf search pdf --all                     # follow every page (up to 10000 rows)

The SDKs stop if a cursor repeats, so a misbehaving server cannot make a loop run forever.

Which operations paginate

Every operation that returns a list: search_items, list_reviews, list_versions, list_tokens, list_orders, list_payouts, list_projects, list_webhooks, list_webhook_deliveries, list_ledger_events and the other list_* operations. Their pages are in the reference. The sort order is part of each operation's documentation; search_items takes sort (relevance, trending, stars, downloads, updated, newest, rating, price_asc, price_desc).

Last updated: