Skip to main content

Overview

The DNSRadar API uses cursor-based pagination for all list endpoints. This approach provides consistent results even when data is being modified, making it ideal for reliable data synchronization and iteration.
Cursor-based pagination ensures you never miss items or see duplicates, even if data changes between requests.

Pagination Parameters

All paginated endpoints accept the following query parameters:
limit
integer
default:20
Number of items to return per pageRange: 1-100 itemsDefault: 20 items
after
string
Cursor for fetching the next page of resultsUse the after value from the previous response to get the next page
before
string
Cursor for fetching the previous page of resultsUse the before value from the previous response to get the previous page
order_by
string
Field to order results byAvailable fields depend on the endpoint (e.g., created, domain, name)
order_way
string
default:"asc"
Sort directionValues: asc (ascending) or desc (descending)Default: asc

Response Structure

All paginated responses follow this structure:
{
  "limit": 20,
  "after": "eyJpZCI6MTIzNDU2fQ==",
  "before": "eyJpZCI6MTIzNDAwfQ==",
  "has_more": true,
  "data": [
    // Array of items
  ]
}

Response Fields

limit
integer
The number of items per page requested
after
string | null
Cursor to fetch the next page of resultsnull if there are no more pages
before
string | null
Cursor to fetch the previous page of resultsnull if this is the first page
has_more
boolean
Indicates whether there are more items after the current pageUse this to determine if you should fetch the next page
data
array
Array of items for the current page

Paginated Endpoints

The following endpoints support pagination:
  • GET /agents - List team members
  • GET /monitors - List DNS monitors
  • GET /monitors/{monitor_uuid}/events - List events for a monitor
  • GET /groups - List monitor groups
  • GET /groups/{slug}/monitors - List monitors in a group
  • GET /webhooks - List webhooks
  • GET /webhooks/{uuid}/requests - List webhook execution requests

Basic Pagination

Fetching the First Page

To get the first page of results, simply call the endpoint without any cursor parameters:
curl "https://api.dnsradar.dev/monitors?limit=20" \
  -H "X-Api-Key: sk_your_api_key_here"

Fetching the Next Page

Use the after cursor from the response to fetch the next page:
curl "https://api.dnsradar.dev/monitors?limit=20&after=eyJpZCI6MTIzNDU2fQ==" \
  -H "X-Api-Key: sk_your_api_key_here"

Sorting Results

You can control the sort order of results using order_by and order_way parameters:
curl "https://api.dnsradar.dev/monitors?order_by=created&order_way=desc&limit=20" \
  -H "X-Api-Key: sk_your_api_key_here"
Use the before cursor to navigate to the previous page:
// After navigating forward several pages
const response = await fetch(
  `https://api.dnsradar.dev/monitors?limit=20&before=${beforeCursor}`,
  {
    headers: {
      'X-Api-Key': 'sk_your_api_key_here'
    }
  }
);
The before cursor is useful for implementing “Previous” buttons in pagination UI or for backward navigation in your application.

Best Practices

Choose page sizes based on your use case:
  • Small pages (10-20): Good for UI display, faster response times
  • Medium pages (50): Balanced for most applications
  • Large pages (100): Efficient for bulk processing, fewer API calls
// For UI display
const uiResponse = await fetch(
  'https://api.dnsradar.dev/monitors?limit=10'
);

// For bulk processing
const bulkResponse = await fetch(
  'https://api.dnsradar.dev/monitors?limit=100'
);
Always check the has_more field to avoid unnecessary requests:
const data = await fetchPage();

if (data.has_more) {
  // Fetch next page
  const nextPage = await fetchPage(data.after);
} else {
  console.log('Reached the end of results');
}
Empty result sets are valid and should be handled gracefully:
data = response.json()

if len(data['data']) == 0:
    print("No items found")
else:
    for item in data['data']:
        process_item(item)
Save the after cursor to resume pagination later:
// Save progress
localStorage.setItem('lastCursor', data.after);

// Resume later
const lastCursor = localStorage.getItem('lastCursor');
if (lastCursor) {
  const response = await fetch(
    `https://api.dnsradar.dev/monitors?after=${lastCursor}`
  );
}
The actual number of items returned may be less than the requested limit, even if more pages exist:
// Don't do this
if (data.data.length < limit) {
  // Wrong assumption: might not be the last page
}

// Do this instead
if (data.has_more) {
  // Correctly check for more pages
}
When iterating through all pages, respect rate limits by adding delays:
import time

after = None
while True:
    data = fetch_page(after)
    process_data(data['data'])

    after = data.get('after')
    if not after:
        break

    # Add delay to respect rate limits
    time.sleep(0.5)

Complete Example: Paginated Export

Here’s a complete example of exporting all monitors to a CSV file:
import fs from 'fs';

async function exportMonitorsToCSV(apiKey) {
  const monitors = [];
  let after = null;
  let pageCount = 0;

  console.log('Fetching monitors...');

  do {
    const url = new URL('https://api.dnsradar.dev/monitors');
    url.searchParams.set('limit', '100');
    if (after) {
      url.searchParams.set('after', after);
    }

    const response = await fetch(url, {
      headers: { 'X-Api-Key': apiKey }
    });

    if (!response.ok) {
      throw new Error(`HTTP ${response.status}: ${response.statusText}`);
    }

    const data = await response.json();
    monitors.push(...data.data);
    pageCount++;

    console.log(`Fetched page ${pageCount} (${data.data.length} items)`);

    after = data.after;

    // Respect rate limits
    if (after) {
      await new Promise(resolve => setTimeout(resolve, 500));
    }
  } while (after !== null);

  console.log(`\nTotal monitors fetched: ${monitors.length}`);

  // Convert to CSV
  const csv = [
    'UUID,Domain,Subdomain,Type,State,Active',
    ...monitors.map(m =>
      `${m.uuid},${m.domain},${m.subdomain},${m.record_type},${m.state},${m.is_active}`
    )
  ].join('\n');

  fs.writeFileSync('monitors.csv', csv);
  console.log('Exported to monitors.csv');
}

// Usage
exportMonitorsToCSV('sk_your_api_key_here')
  .catch(console.error);

Common Pitfalls

Don’t Manipulate Cursors: Cursors are opaque tokens. Never try to decode, modify, or construct them manually. Always use the values provided by the API.
Don’t Use Offset-Based Logic: Unlike offset-based pagination, you cannot jump to arbitrary pages (e.g., “page 5”). You must iterate sequentially using cursors.
Cursors Can Expire: Cursors may become invalid after extended periods. If you receive an error, restart pagination from the beginning.

See Also