Skip to content

Pagination

List operations return one page at a time. Every page has the same envelope:

{
"data": [ { "id": "0199…", "…": "…" } ],
"has_more": true,
"next_cursor": "0199…"
}
Field Meaning
data The items on this page.
has_more true if there is at least one more page.
next_cursor The value to send as cursor for the next page. null on the last page.

Some lists add fields beside these, such as pending_count on listApprovals.

Two query parameters control paging:

  • limit: how many items per page. Most lists accept 1 to 100 and default to 50. Each list’s reference page gives its range.
  • cursor: where to continue. Leave it out for the first page.
Terminal window
curl -s "$ELE_API_BASE/api/v1/organizations/$ORG_ID/transactions?limit=100" \
-H "Authorization: Bearer $ELE_TOKEN"

While has_more is true, send next_cursor as cursor to fetch the next page. Keep every other parameter the same:

Terminal window
curl -s "$ELE_API_BASE/api/v1/organizations/$ORG_ID/transactions?limit=100&cursor=$NEXT_CURSOR" \
-H "Authorization: Bearer $ELE_TOKEN"

Stop when has_more is false.

Treat the cursor as an opaque value. Some lists happen to use the last item’s ID, but always take the cursor from next_cursor rather than building one.

On listAttentionItems, a cursor whose item has since been resolved returns an empty page. Start again from the first page.

This program lists every transaction of an organization, newest first. The transactions function returns a Go iterator (iter.Seq2) that fetches each page only when the loop reaches it. Breaking out of the loop stops the fetching:

pagination/main.go
// Pagination: list every transaction of an organization, newest first, one
// page at a time. The iterator fetches the next page only when the loop
// reaches it, and stops fetching when the loop stops.
//
// ELE_TOKEN=… go run ./pagination <organization_id>
package main
import (
"context"
"fmt"
"iter"
"log"
"net/url"
"os"
"github.com/elephants-labs/ele/developers/examples/internal/ele"
)
// transaction holds the fields this example prints. Transactions have many
// more, which depend on their type.
type transaction struct {
ID string `json:"id"`
Type string `json:"type"`
RecordedAt string `json:"recorded_at"`
Effect *effect `json:"effect"`
}
type effect struct {
Direction string `json:"direction"`
Total string `json:"total"`
Currency string `json:"currency"`
}
type page struct {
Data []transaction `json:"data"`
HasMore bool `json:"has_more"`
NextCursor *string `json:"next_cursor"`
}
func main() {
if len(os.Args) != 2 {
log.Fatal("usage: go run ./pagination <organization_id>")
}
ctx := context.Background()
c := ele.FromEnv()
for t, err := range transactions(ctx, c, os.Args[1]) {
if err != nil {
log.Fatal(err)
}
if t.Effect == nil {
fmt.Printf("%s %-18s\n", t.RecordedAt, t.Type)
continue
}
fmt.Printf("%s %-18s %-3s %s %s\n", t.RecordedAt, t.Type, t.Effect.Direction, t.Effect.Total, t.Effect.Currency)
}
}
// transactions yields each transaction of the organization. On an error it
// yields the error once and stops.
func transactions(ctx context.Context, c *ele.Client, organizationID string) iter.Seq2[transaction, error] {
path := "/api/v1/organizations/" + url.PathEscape(organizationID) + "/transactions"
return func(yield func(transaction, error) bool) {
query := url.Values{"limit": {"100"}}
for {
var p page
if err := c.Do(ctx, "GET", path+"?"+query.Encode(), nil, &p); err != nil {
yield(transaction{}, err)
return
}
for _, t := range p.Data {
if !yield(t, nil) {
return
}
}
if !p.HasMore || p.NextCursor == nil {
return
}
query.Set("cursor", *p.NextCursor)
}
}
}
Terminal window
ELE_TOKEN=… go run ./pagination "$ORG_ID"

listTransactions also takes filters, such as date_start and date_end. Add them to the first request and keep them on every later one.