Skip to content

10 Questions to ask your unified API provider

Ask your unified API provider these 10 key questions, plus see how pagination works across offset, page-number, cursor, Link header, and GraphQL APIs with code examples.

Roopendra Talekar Roopendra Talekar · · 8 min read
10 Questions to ask your unified API provider

Integrations will form a core part of your product offering and its customer-facing. It's paramount that it just works 100% of the time. Once you have decided to use a unified API provider and shortlisted some, use the questions below to ensure you don't end up firefighting one day.

Questions to ask your Unified API provider

  1. What is your plan for the next 1,2 and 3 years?

Look for stability and clarity in thinking.

2. What is your product roadmap?

Look for features that will add value as time goes by. You don't want to use many SaaS products to get integrations done.

3. What's your plan for adding to your integrations catalogue?

Look for steady building activity on integrations. Make sure they will continue to support newer integrations. Better yet, ask them for custom integrations.

4. Who are your current customers?

Look for big well-known names here.

5. How do you plan to scale the tech?

Identify any gaps and make sure the tech stack is built for scale.

6. What happens if you choose to shut down the company?

Look for open-source solutions or solutions which have open-source elements in them. There are other solutions to alleviate this fear as well such as sharing the code base and self-hosted solutions.

7. Is a price increase on the horizon?

Since will be a fundamental part of your product offering, you want to make sure it doesn't become a burden later on. Make sure you have a long-term contract or a commitment to pricing caps.

8. Do you do multi-year contracts?

Any vendor will appreciate it when you ask them this question. The benefit you want to look for here for your team is a good price and/or services geared for you.

9. Will there be any issues when we scale?

This will bring out any gaps in the tech stack that may have been missed earlier.

10. How can we switch to another vendor?

If you are speaking with the right vendor, they will love this question and happily suggest how best to prepare for this event. Solutions you want to look for - help with migration, architecture design, and switching timelines.

How unified APIs handle pagination differences across REST APIs

When you ask Questions 5 and 9 above, pagination is one of the most revealing areas to dig into. Every SaaS API paginates differently - offset/limit, page numbers, cursor tokens, RFC 5988 Link headers, GraphQL relay connections - and a unified API must normalize all of them behind a single interface.

A well-designed unified API exposes just two pagination parameters to the caller:

  • limit - how many records per page
  • next_cursor - an opaque token representing the next page

You never need to know the provider's native pagination scheme. Here's how each common pattern works under the hood, with concrete request/response examples.

Example: Translating limit/next_cursor to offset/limit

Many APIs use classic offset pagination - offset=20&limit=10 means "skip 20 records, return 10." NetSuite's SuiteQL API is a good example: it takes offset and limit query parameters and returns totalResults in the response body, with a max of 1,000 records per page.

Your request to the unified API:

GET /unified/accounting/journal-entries?integrated_account_id=acct_abc&limit=10

What the unified API sends to the provider:

GET /query/v1/suiteql?offset=0&limit=10

Unified API response to you:

{
  "result": [
    { "id": "je_001", "memo": "Monthly depreciation", "amount": 1500.00, "date": "2024-06-01" },
    { "id": "je_010", "memo": "Payroll accrual", "amount": 4200.00, "date": "2024-06-15" }
  ],
  "next_cursor": "eyJvZmZzZXQiOjEwfQ==",
  "result_count": 10
}

The next_cursor is an opaque token that encodes the next offset. Pass it back to get the next page:

GET /unified/accounting/journal-entries?integrated_account_id=acct_abc&limit=10&next_cursor=eyJvZmZzZXQiOjEwfQ==

The unified API decodes the cursor and sends offset=10&limit=10 to the provider. When no more results exist, next_cursor comes back as null.

The offset pagination config specifies which query parameters the provider expects (offset_param, limit_param) and what offset to start at (start_offset). Some providers enforce hard ceilings - NetSuite caps at 1,000 per page, and certain resource types may use lower limits (like 50 per page when each record requires extra enrichment calls). The unified API respects those automatically.

Example: Translating to page-number pagination

Some APIs paginate with page numbers - page=2&per_page=25. The unified API abstracts this identically.

Your request:

GET /unified/hris/employees?integrated_account_id=acct_xyz&limit=25

What the unified API sends to the provider:

GET /api/v1/employees?page=1&per_page=25

Unified API response:

{
  "result": [
    { "id": "emp_001", "first_name": "Jane", "last_name": "Smith", "department": "Engineering" },
    { "id": "emp_025", "first_name": "Carlos", "last_name": "Rivera", "department": "Sales" }
  ],
  "next_cursor": "eyJwYWdlIjoyfQ==",
  "result_count": 25
}

Behind the scenes, the config specifies page_param, page_size_param, start_page (usually 1), and page_increment. Your code doesn't change - you still just pass next_cursor.

APIs like GitHub follow RFC 5988 and return pagination URLs in the HTTP Link header:

HTTP/1.1 200 OK
Link: <https://api.github.com/repos/acme/app/issues?page=3&per_page=10>; rel="next",
      <https://api.github.com/repos/acme/app/issues?page=12&per_page=10>; rel="last"
Content-Type: application/json
 
[
  { "id": 301, "title": "Fix login timeout", "state": "open" },
  { "id": 310, "title": "Update dependencies", "state": "closed" }
]

The unified API parses the Link header, extracts the next URL, and encodes it into next_cursor:

{
  "result": [
    { "id": "301", "title": "Fix login timeout", "status": "open" },
    { "id": "310", "title": "Update dependencies", "status": "closed" }
  ],
  "next_cursor": "eyJ1cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2FjbWUvYXBwL2lzc3Vlcz9wYWdlPTMmcGVyX3BhZ2U9MTAifQ==",
  "result_count": 10
}

When you pass that next_cursor back, the unified API follows the extracted URL directly. You never parse Link headers yourself.

Example: GraphQL relay-style pagination

GraphQL APIs commonly use relay-style cursor pagination. A typical provider query looks like this:

query($cursor: String, $first: Int) {
  issues(first: $first, after: $cursor) {
    nodes {
      id
      title
      state { name }
    }
    pageInfo {
      hasNextPage
      endCursor
    }
  }
}

With variables { "first": 10, "cursor": null } on the first request.

The unified API abstracts this behind the same interface:

Your request:

GET /unified/ticketing/tickets?integrated_account_id=acct_linear&limit=10

Unified API response:

{
  "result": [
    { "id": "LIN-401", "title": "Refactor auth module", "status": "in_progress" },
    { "id": "LIN-410", "title": "Add rate limit docs", "status": "todo" }
  ],
  "next_cursor": "WyIyMDI0LTA2LTIwVDE0OjE1OjAwWiJd",
  "result_count": 10
}

Under the hood, the unified API extracted pageInfo.endCursor from the GraphQL response and packaged it as next_cursor. On your next request, it injects that value as the after variable in the GraphQL query. A dynamic pagination config uses expressions to locate the cursor in the response, check whether hasNextPage is true, and apply the cursor to the outgoing request.

Note that on the first request (no cursor provided), the cursor variable resolves to null - which is the correct "start from the beginning" value for most GraphQL pagination schemes.

Provider-native cursor tokens

Some REST APIs already use opaque cursors natively - HubSpot returns paging.next.after, Salesforce returns a nextRecordsUrl, Slack uses response_metadata.next_cursor. These are the simplest case: the unified API extracts the provider's cursor from whatever response field it lives in and returns it as next_cursor.

The cursor pagination config specifies cursor_field (where to find the cursor in the response) and cursor_query_param (which parameter to send it back in). Some providers expect the cursor in the request body or a header rather than a query parameter - the config handles that too, using cursor_in_body or cursor_in_header flags.

How all six strategies map to one interface

Provider pattern Example providers Under the hood What you see
Offset/limit NetSuite SuiteQL, Zendesk offset=N&limit=M next_cursor + limit
Page number BambooHR, Personio page=N&per_page=M next_cursor + limit
Cursor HubSpot, Slack, Salesforce after=xyz or cursor=xyz next_cursor + limit
Link header GitHub, GitLab RFC 5988 Link: <url>; rel="next" next_cursor + limit
Range APIs using HTTP Range headers Range: items=0-9 next_cursor + limit
Dynamic (expression-based) GraphQL relay, custom APIs JSONata expressions compute next cursor next_cursor + limit

Every pattern collapses to the same two fields. Pagination behavior is defined as data (configuration and expressions), not as per-integration code. Adding a new integration with a different pagination scheme means adding config - not writing new pagination logic.

Code sample: Generic pagination loop using unified next_cursor

Because the pagination interface is identical regardless of the underlying provider, your pagination code is a single loop that works everywhere.

Python:

import requests
 
def fetch_all_records(base_url, resource, account_id, api_key, limit=100):
    """
    Paginate through any unified API resource.
    Works the same whether the provider uses offset, page numbers,
    Link headers, cursor tokens, or GraphQL relay pagination.
    """
    url = f"{base_url}/unified/{resource}"
    headers = {"Authorization": f"Bearer {api_key}"}
    params = {
        "integrated_account_id": account_id,
        "limit": limit,
    }
 
    all_records = []
    while True:
        resp = requests.get(url, headers=headers, params=params)
        resp.raise_for_status()
        data = resp.json()
 
        all_records.extend(data["result"])
 
        if not data.get("next_cursor"):
            break
        params["next_cursor"] = data["next_cursor"]
 
    return all_records
 
 
# Same function for every provider - no pagination-specific logic needed
contacts = fetch_all_records(
    "https://api.truto.one",
    "crm/contacts",
    "acct_abc123",
    "your_api_key"
)

Node.js (ES modules):

async function fetchAllRecords(baseUrl, resource, accountId, apiKey, limit = 100) {
  const headers = { Authorization: `Bearer ${apiKey}` };
  const records = [];
  let nextCursor = null;
 
  do {
    const params = new URLSearchParams({
      integrated_account_id: accountId,
      limit: String(limit),
    });
    if (nextCursor) params.set('next_cursor', nextCursor);
 
    const res = await fetch(
      `${baseUrl}/unified/${resource}?${params}`,
      { headers }
    );
    if (!res.ok) throw new Error(`HTTP ${res.status}: ${await res.text()}`);
 
    const data = await res.json();
    records.push(...data.result);
    nextCursor = data.next_cursor ?? null;
  } while (nextCursor);
 
  return records;
}
 
// Works for HubSpot (cursor), NetSuite (offset), GitHub (Link header), Linear (GraphQL relay)
const contacts = await fetchAllRecords(
  'https://api.truto.one',
  'crm/contacts',
  'acct_abc123',
  'your_api_key'
);

This single function handles every provider behind the unified API. You never write provider-specific pagination logic.

What to look for when evaluating providers

When you ask a unified API vendor Question 5 ("How do you plan to scale the tech?") and Question 9 ("Will there be any issues when we scale?"), pagination is a concrete area to probe:

  • How many pagination strategies does the platform support? If it only handles cursor-based pagination, it'll struggle with older APIs that use offsets or page numbers.
  • Is pagination behavior data-driven or hard-coded per integration? A data-driven approach - where pagination is defined in configuration, not per-integration code - means adding new integrations doesn't require new pagination logic.
  • Does the platform respect provider-imposed limits? Some APIs cap page sizes or throttle differently for heavy list operations. Ask whether the unified layer handles those constraints transparently.
  • Is pagination stateless? For APIs that already use cursors, the unified API should pass through the native token rather than inventing server-side state. Stateless pagination scales better and avoids stale-cursor bugs.

If you are looking for a comprehensive guide with parameters to get you started on choosing a unified API provider, read this post - How to choose a unified API provider

FAQ

What should I ask a unified API provider about their roadmap?
Ask about their plans for the next three years and their strategy for adding new integrations to ensure the platform evolves with your needs and supports custom requests.
What happens if a unified API provider company shuts down?
Look for providers with open-source elements, self-hosted options, or code-sharing agreements to ensure you can maintain your integrations even if the vendor ceases operations.
How can I prepare for switching to a different unified API vendor?
Ask prospective vendors how they support migrations, architecture design, and switching timelines to ensure you are not locked into a single service and can transition if needed.

More from our Blog

What if Truto shuts down?
Security

What if Truto shuts down?

Truto ensures business continuity through profitability, on-prem and self-host deployment options, SOC 2 Type II compliance, and source code access for long-term security.

Nachi Raman Nachi Raman · · 4 min read