Skip to main content
The HopX API uses cursor-based pagination for list endpoints. This provides consistent, efficient pagination even when data is being added or removed.

List Response Format

All list endpoints return a consistent structure:
{
  "object": "list",
  "data": [
    {"id": "sandbox_1", ...},
    {"id": "sandbox_2", ...}
  ],
  "has_more": true,
  "next_cursor": "cursor_abc123",
  "url": "/v1/sandboxes",
  "request_id": "req_abc123"
}
FieldTypeDescription
objectstringAlways “list”
dataarrayArray of resource objects
has_morebooleanWhether more results exist
next_cursorstringCursor for next page (null if no more results)
urlstringEndpoint URL
request_idstringRequest ID

Pagination Parameters

cursor

Use the cursor query parameter to fetch the next page:
# First page
curl "https://api.hopx.dev/v1/sandboxes" \
  -H "Authorization: Bearer $HOPX_API_KEY"

# Next page (using cursor from previous response)
curl "https://api.hopx.dev/v1/sandboxes?cursor=cursor_abc123" \
  -H "Authorization: Bearer $HOPX_API_KEY"

limit

Control the number of results per page with the limit parameter:
curl "https://api.hopx.dev/v1/sandboxes?limit=50" \
  -H "Authorization: Bearer $HOPX_API_KEY"
Default limits vary by endpoint:
  • Sandboxes: 20 per page
  • Templates: 50 per page
Maximum limit: 100 per page

Paginating Through Results

Example: Fetch All Sandboxes

import requests

def get_all_sandboxes(api_key):
    url = "https://api.hopx.dev/v1/sandboxes"
    headers = {"Authorization": f"Bearer {api_key}"}
    all_sandboxes = []
    cursor = None
    
    while True:
        params = {"limit": 100}
        if cursor:
            params["cursor"] = cursor
        
        response = requests.get(url, headers=headers, params=params)
        data = response.json()
        
        all_sandboxes.extend(data["data"])
        
        if not data["has_more"]:
            break
        
        cursor = data["next_cursor"]
    
    return all_sandboxes

sandboxes = get_all_sandboxes("$HOPX_API_KEY")
print(f"Total sandboxes: {len(sandboxes)}")

Example: Fetch with Progress

def get_all_sandboxes_with_progress(api_key):
    url = "https://api.hopx.dev/v1/sandboxes"
    headers = {"Authorization": f"Bearer {api_key}"}
    all_sandboxes = []
    cursor = None
    page = 1
    
    while True:
        params = {"limit": 50}
        if cursor:
            params["cursor"] = cursor
        
        response = requests.get(url, headers=headers, params=params)
        data = response.json()
        
        page_sandboxes = data["data"]
        all_sandboxes.extend(page_sandboxes)
        
        print(f"Page {page}: Fetched {len(page_sandboxes)} sandboxes (total: {len(all_sandboxes)})")
        
        if not data["has_more"]:
            print("No more results")
            break
        
        cursor = data["next_cursor"]
        page += 1
    
    return all_sandboxes

Cursor-Based Pagination Benefits

Consistent Results

Cursor-based pagination provides consistent results even when data changes:
# Offset-based (bad) - can miss or duplicate items if data changes
response1 = get("/sandboxes?offset=0&limit=10")
# New sandbox created here
response2 = get("/sandboxes?offset=10&limit=10")  # Might miss items!

# Cursor-based (good) - consistent results
response1 = get("/sandboxes?limit=10")
cursor = response1["next_cursor"]
# New sandbox created here
response2 = get(f"/sandboxes?cursor={cursor}&limit=10")  # No duplicates or misses

Performance

Cursor-based pagination is more efficient for large datasets:
  • O(1) lookups using the cursor
  • No need to count or skip rows
  • Works well with databases

Filtering with Pagination

Combine filters with pagination:
# List running sandboxes with pagination
curl "https://api.hopx.dev/v1/sandboxes?status=running&limit=50" \
  -H "Authorization: Bearer $HOPX_API_KEY"

# Next page
curl "https://api.hopx.dev/v1/sandboxes?status=running&limit=50&cursor=cursor_abc123" \
  -H "Authorization: Bearer $HOPX_API_KEY"
Example with filters:
def get_running_sandboxes(api_key):
    url = "https://api.hopx.dev/v1/sandboxes"
    headers = {"Authorization": f"Bearer {api_key}"}
    running_sandboxes = []
    cursor = None
    
    while True:
        params = {
            "status": "running",
            "limit": 50
        }
        if cursor:
            params["cursor"] = cursor
        
        response = requests.get(url, headers=headers, params=params)
        data = response.json()
        
        running_sandboxes.extend(data["data"])
        
        if not data["has_more"]:
            break
        
        cursor = data["next_cursor"]
    
    return running_sandboxes

Endpoints with Pagination

All list endpoints support pagination:
EndpointDefault LimitMax Limit
GET /v1/sandboxes20100
GET /v1/templates50100

Best Practices

1. Use Reasonable Page Sizes

# Good: Fetch manageable chunks
response = get("/v1/sandboxes?limit=50")

# Bad: Fetching too many at once
response = get("/v1/sandboxes?limit=1000")  # Over max limit (100)

2. Store and Reuse Cursors

# Save cursor for resuming later
last_cursor = None

for page in range(5):
    params = {"limit": 20}
    if last_cursor:
        params["cursor"] = last_cursor
    
    response = get("/v1/sandboxes", params=params)
    data = response.json()
    
    process_sandboxes(data["data"])
    
    if not data["has_more"]:
        break
    
    last_cursor = data["next_cursor"]

# Resume later with last_cursor

3. Handle Empty Results

response = requests.get(url, headers=headers)
data = response.json()

if not data["data"]:
    print("No results found")
elif not data["has_more"]:
    print("This is the last page")

Shell Script Example

#!/bin/bash

API_KEY="$HOPX_API_KEY"
URL="https://api.hopx.dev/v1/sandboxes"
CURSOR=""
PAGE=1

while true; do
  # Build URL with cursor if available
  if [ -z "$CURSOR" ]; then
    REQUEST_URL="$URL?limit=50"
  else
    REQUEST_URL="$URL?limit=50&cursor=$CURSOR"
  fi
  
  # Fetch page
  RESPONSE=$(curl -s "$REQUEST_URL" -H "Authorization: Bearer $API_KEY")
  
  # Extract data
  COUNT=$(echo "$RESPONSE" | jq '.data | length')
  HAS_MORE=$(echo "$RESPONSE" | jq -r '.has_more')
  
  echo "Page $PAGE: $COUNT sandboxes"
  
  # Check if more pages exist
  if [ "$HAS_MORE" != "true" ]; then
    echo "No more results"
    break
  fi
  
  # Get next cursor
  CURSOR=$(echo "$RESPONSE" | jq -r '.next_cursor')
  PAGE=$((PAGE + 1))
done

Next Steps