Skip to content

feat(pagination): update pagination for remaining integrations that support it#3233

Merged
waleedlatif1 merged 3 commits intostagingfrom
feat/pagination
Feb 17, 2026
Merged

feat(pagination): update pagination for remaining integrations that support it#3233
waleedlatif1 merged 3 commits intostagingfrom
feat/pagination

Conversation

@waleedlatif1
Copy link
Collaborator

Summary

  • update pagination for remaining integrations that support it

Type of Change

  • New feature

Testing

Tested manually

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

@vercel
Copy link

vercel bot commented Feb 17, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped Feb 17, 2026 9:10pm

Request Review

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 17, 2026

Greptile Summary

This PR adds pagination support to several integrations that previously lacked it: Zendesk, Pipedrive, Supabase, Typeform, and Incident.io. The changes are broadly correct and well-structured — shared helpers (appendCursorPaginationParams, extractCursorPagingInfo) are introduced in zendesk/types.ts to eliminate duplication, and each integration uses the appropriate pagination model for its API (cursor-based for v2/export endpoints, offset-based for legacy v1 endpoints).

Key observations:

  • Typeform before/after mutual exclusivity not enforced: Both cursor params can be sent simultaneously in a single request, which the Typeform API rejects. A runtime guard should be added.
  • Silent breaking removals in Pipedrive: deal_id/person_id/org_id filters were removed from get_files and get_activities, and status was removed from get_pipeline_deals. These are valid API params that could coexist with the new pagination — removing them is a silent breaking change for existing users.
  • Supabase plain FTS operator silently changed: ftsplfts for the plain search type. If this fixes a bug it should be documented; if inadvertent it could change query results for existing users.
  • Zendesk /users and /organizations cursor pagination needs verification: These endpoints traditionally use offset pagination. The PR assumes they support the cursor bracket notation (page[size]/page[after]) — if not, pageAfter will be silently ignored.

Confidence Score: 3/5

  • Mostly safe to merge, but several breaking changes (removed filter params, FTS operator change) and an unvalidated mutual-exclusion constraint in Typeform need attention first.
  • The core pagination logic is sound and well-structured. The Zendesk cursor helpers are correct (using page[after] properly), Pipedrive v1/v2 pagination models are handled appropriately, and Supabase/Incident.io additions are clean. However, four issues lower confidence: (1) Typeform before/after mutual exclusivity is not enforced, causing API errors when both are provided; (2) Pipedrive silently removes deal_id/person_id/org_id from get_files and get_activities, and status from get_pipeline_deals — all valid API params that didn't need to be removed; (3) Supabase plain FTS operator changed from 'fts' to 'plfts' without explanation, potentially breaking existing queries; (4) Whether Zendesk /users and /organizations support cursor bracket notation needs verification.
  • apps/sim/tools/typeform/responses.ts (mutual exclusion bug), apps/sim/tools/pipedrive/get_activities.ts and get_files.ts and get_pipeline_deals.ts (breaking param removals), apps/sim/tools/supabase/text_search.ts (FTS operator change), apps/sim/tools/zendesk/get_users.ts and get_organizations.ts (cursor pagination compatibility needs verification)

Important Files Changed

Filename Overview
apps/sim/tools/zendesk/types.ts Adds cursor pagination helpers (appendCursorPaginationParams, extractCursorPagingInfo) and updates shared output constants. Well-structured and correct for cursor-based endpoints.
apps/sim/tools/zendesk/get_users.ts Migrates /users to cursor-based pagination using page[size] and page[after] params. Implementation is correct and consistent with other cursor-based tools.
apps/sim/tools/pipedrive/get_all_deals.ts Adds cursor-based pagination support for the v2 deals endpoint. next_cursor is correctly extracted from additional_data. Implementation looks correct.
apps/sim/tools/pipedrive/get_activities.ts Refactors filter params (deal_id, person_id, org_id removed; user_id added) and adds start-based offset pagination. Pagination info correctly pulled from additional_data.pagination.next_start.
apps/sim/tools/pipedrive/get_pipeline_deals.ts Removes status filter and adds start-based offset pagination for pipeline deals. Correctly reads pagination from additional_data.pagination. The removal of status filter is a breaking change for existing users.
apps/sim/tools/supabase/text_search.ts Adds offset pagination and changes 'plain' FTS operator from 'fts' to 'plfts'. The operator change fixes a PostgREST compatibility issue. Null-safe check used for offset. Minor: 'plfts' is a breaking change for existing 'plain' search users.
apps/sim/tools/typeform/responses.ts Adds before/after cursor pagination params for Typeform responses. Both before and after can be sent simultaneously which Typeform does not allow. No validation prevents this conflicting combination.
apps/sim/tools/zendesk/get_organizations.ts Migrates /organizations to cursor-based pagination (page[size]/page[after]). Needs verification that this endpoint supports cursor bracket notation — it traditionally uses offset pagination.

Flowchart

flowchart TD
    subgraph Zendesk
        ZT["get_tickets"] -->|"has filters (status/priority/type/assignee/org)"| ZSE["/search/export\ncursor: page[after]"]
        ZT -->|"no filters"| ZTE["/tickets\ncursor: page[after]"]
        ZS["search"] --> ZSE2["/search/export\nfilter[type]=ticket|user|org|group\ncursor: page[after]"]
        ZU["get_users"] --> ZUE["/users\ncursor: page[after]"]
        ZO["get_organizations"] --> ZOE["/organizations\ncursor: page[after]"]
        ZSU["search_users"] --> ZSUE["/users/search\noffset: page param\nafter_cursor always null"]
        ZAO["autocomplete_organizations"] --> ZAOE["/organizations/autocomplete\noffset: page param\nafter_cursor always null"]
    end

    subgraph Pipedrive
        PD["get_all_deals\nget_projects"] -->|"cursor"| PDC["v2/deals or v1/projects\ncursor-based\nnext_cursor"]
        PA["get_activities\nget_pipeline_deals\nget_pipelines\nget_leads\nget_mail_messages\nget_files"] -->|"start offset"| PAS["v1 endpoints\nnext_start from additional_data.pagination"]
    end

    subgraph Supabase
        SQ["query\ntext_search"] -->|"offset param"| SQE["PostgREST REST API\n?offset=N&limit=M"]
    end

    subgraph Typeform
        TF["responses"] -->|"before OR after\ncursor"| TFE["api.typeform.com\n/responses?before=X or ?after=Y"]
    end

    subgraph "Incident.io"
        IU["users_list"] -->|"after cursor"| IUE["api.incident.io/v2/users\n?after=cursor&page_size=N"]
    end
Loading

Last reviewed commit: d002c73

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

37 files reviewed, 8 comments

Edit Code Review Agent Settings | Greptile

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 17, 2026

Additional Comments (4)

apps/sim/tools/pipedrive/get_activities.ts
has_more and next_start missing from outputs definition

has_more and next_start are returned in the transformResponse output, but they are not declared in the outputs object. This means downstream consumers (block UI, type inference) won't be aware these fields exist.

Add the missing declarations:

  outputs: {
    activities: {
      type: 'array',
      description: 'Array of activity objects from Pipedrive',
      items: {
        type: 'object',
        properties: PIPEDRIVE_ACTIVITY_OUTPUT_PROPERTIES,
      },
    },
    total_items: { type: 'number', description: 'Total number of activities returned' },
    has_more: { type: 'boolean', description: 'Whether more activities are available', optional: true },
    next_start: { type: 'number', description: 'Offset for fetching the next page', optional: true },
    success: { type: 'boolean', description: 'Operation success status' },
  },

apps/sim/tools/pipedrive/get_mail_messages.ts
has_more and next_start missing from outputs definition

has_more and next_start are returned in transformResponse but are not declared in the outputs object. This pattern is consistent with other Pipedrive tools in this PR (get_activities, get_pipelines, get_pipeline_deals, get_projects) — all have the same gap.

The outputs section should include:

  outputs: {
    messages: { type: 'array', description: 'Array of mail thread objects from Pipedrive mailbox' },
    total_items: { type: 'number', description: 'Total number of mail threads returned' },
    has_more: { type: 'boolean', description: 'Whether more messages are available', optional: true },
    next_start: { type: 'number', description: 'Offset for fetching the next page', optional: true },
    success: { type: 'boolean', description: 'Operation success status' },
  },

apps/sim/tools/pipedrive/get_pipelines.ts
has_more and next_start missing from outputs definition

has_more and next_start are returned in transformResponse but not declared in the outputs object. The same gap exists across several other Pipedrive tools in this PR.

  outputs: {
    pipelines: {
      type: 'array',
      description: 'Array of pipeline objects from Pipedrive',
      items: {
        type: 'object',
        properties: PIPEDRIVE_PIPELINE_OUTPUT_PROPERTIES,
      },
    },
    total_items: { type: 'number', description: 'Total number of pipelines returned' },
    has_more: { type: 'boolean', description: 'Whether more pipelines are available', optional: true },
    next_start: { type: 'number', description: 'Offset for fetching the next page', optional: true },
    success: { type: 'boolean', description: 'Operation success status' },
  },

apps/sim/tools/pipedrive/get_projects.ts
has_more and next_cursor missing from outputs definition

has_more and next_cursor are returned in transformResponse for the list path but are not declared in the outputs object, unlike get_all_deals which correctly includes them via PIPEDRIVE_METADATA_OUTPUT_PROPERTIES.

  outputs: {
    projects: {
      type: 'array',
      description: 'Array of project objects (when listing all)',
      optional: true,
    },
    project: {
      type: 'object',
      description: 'Single project object (when project_id is provided)',
      optional: true,
    },
    total_items: {
      type: 'number',
      description: 'Total number of projects returned',
      optional: true,
    },
    has_more: { type: 'boolean', description: 'Whether more projects are available', optional: true },
    next_cursor: { type: 'string', description: 'Cursor for fetching the next page', optional: true },
    success: { type: 'boolean', description: 'Operation success status' },
  },

@waleedlatif1
Copy link
Collaborator Author

@cursor review

@waleedlatif1
Copy link
Collaborator Author

@greptile

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

37 files reviewed, 3 comments

Edit Code Review Agent Settings | Greptile

@waleedlatif1
Copy link
Collaborator Author

@greptile

@waleedlatif1
Copy link
Collaborator Author

@cursor review

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

37 files reviewed, 6 comments

Edit Code Review Agent Settings | Greptile

Comment on lines +71 to +77
if (params.before) {
queryParams.push(`before=${encodeURIComponent(params.before)}`)
}

if (params.after) {
queryParams.push(`after=${encodeURIComponent(params.after)}`)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mutually exclusive before/after params can both be sent

The Typeform Responses API treats before and after as mutually exclusive cursors — sending both in the same request produces an error. Since both params are independently optional with no guard, a caller that populates both will get an API error with no explanation at the tool level.

Add a runtime guard before building the URL:

Suggested change
if (params.before) {
queryParams.push(`before=${encodeURIComponent(params.before)}`)
}
if (params.after) {
queryParams.push(`after=${encodeURIComponent(params.after)}`)
}
if (params.before && params.after) {
throw new Error("Typeform 'before' and 'after' cursor params are mutually exclusive. Provide only one.")
}
if (params.before) {
queryParams.push(`before=${encodeURIComponent(params.before)}`)
}
if (params.after) {
queryParams.push(`after=${encodeURIComponent(params.after)}`)
}

Comment on lines +38 to 49
limit: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter by deal status: open, won, lost',
description: 'Number of results to return (e.g., "50", default: 100, max: 500)',
},
limit: {
start: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Number of results to return (e.g., "50", default: 100, max: 500)',
description: 'Pagination start offset (0-based index of the first item to return)',
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Breaking removal of status filter

The status filter (open, won, lost) that previously existed on this tool has been removed and replaced with start (pagination offset). While adding pagination is the goal of this PR, removing status is a silent breaking change — existing users who relied on filtering pipeline deals by status will silently lose that capability with no migration path or deprecation notice.

The Pipedrive /v1/pipelines/{id}/deals endpoint does support a status query parameter, so adding pagination via start doesn't require removing it. Consider keeping the status param alongside start.

Comment on lines +27 to 32
user_id: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter activities by deal ID (e.g., "123")',
},
person_id: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter activities by person ID (e.g., "456")',
},
org_id: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter activities by organization ID (e.g., "789")',
description: 'Filter activities by user ID (e.g., "123")',
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Breaking removal of deal_id, person_id, org_id filters

The three activity filter params (deal_id, person_id, org_id) have been removed and replaced with user_id. These are all valid filter params on the Pipedrive /v1/activities endpoint and are not mutually exclusive with user_id. Removing them silently breaks existing users who filter activities by deal or person.

The same applies to get_files where deal_id, person_id, and org_id filters were removed entirely (see route.ts and get_files.ts). The Pipedrive /v1/files endpoint does support these filters, so pagination via start doesn't require their removal.

Consider reinstating these filter params alongside the new pagination field.

Comment on lines 83 to +84
const operatorMap: Record<string, string> = {
plain: 'fts',
plain: 'plfts',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Silent breaking change: plain search operator changed from fts to plfts

The PostgREST operator for plain text search has changed from fts to plfts (plainto_tsquery). While plfts is likely the correct operator for plain text search, this is a silent breaking change for anyone using searchType: 'plain'. fts in PostgREST corresponds to to_tsquery (which accepts raw tsquery syntax), while plfts uses plainto_tsquery (which takes plain text). The results can differ significantly for queries with special characters or operators.

If this is intentional (fixing a pre-existing bug), it warrants a comment explaining the correction.

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 17, 2026

Additional Comments (2)

apps/sim/tools/zendesk/get_organizations.ts
Verify /organizations supports cursor-based page[size]/page[after] pagination

The appendCursorPaginationParams helper appends page[size] and page[after], which is the Zendesk cursor-based pagination style. However, the Zendesk /organizations list endpoint traditionally uses offset pagination (page and per_page). The cursor-based list API (using page[size]/page[after]) is only available on certain Zendesk endpoints via the "New Pagination" API.

If /organizations does not support the cursor-based bracket notation, the pageAfter cursor input will be silently ignored and pagination will always start from the first page. Please verify this endpoint supports page[size] and page[after] before shipping.


apps/sim/tools/zendesk/get_users.ts
Verify /users supports cursor-based page[size]/page[after] pagination

Similar to get_organizations, this switches from offset pagination (page/per_page) to cursor-based page[size]/page[after]. The Zendesk /users list endpoint traditionally uses offset pagination. If it does not support the cursor bracket notation, the pageAfter cursor value will be silently ignored and pagination will not advance past the first page.

The companion search_users tool (also in this PR) correctly retains offset pagination for /users/search — worth confirming whether /users (this endpoint) and /users/search truly use different pagination models.

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

@waleedlatif1 waleedlatif1 merged commit 08690b2 into staging Feb 17, 2026
12 checks passed
@waleedlatif1 waleedlatif1 deleted the feat/pagination branch February 17, 2026 21:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant