Paginating with a workspace variable
APIs return one page at a time. To get the next page you need a cursor that says where the last page ended. A for loop can't carry that cursor between runs, and looping through everything in one go hits the 300-second timeout.
The fix: do one page per run, save the cursor in a workspace variable, and have the workflow re-trigger itself until there are no pages left.
Setup
Create a workspace variable called cursor (Variables & secrets), type number, value 0. Reference it as {{ WORKSPACE_VARIABLES.cursor }} in the workflows.


The workflow

Trigger - Choose the default trigger available when you open a new workflow. Copy the curl command as we will be using it to re-fire itself for each page.

Input - wire the trigger in.
Read cursor (Code) - get the cursor, fetch one page, output the next cursor and whether more pages exist. Bind
body_cursor→{{ input.body.cursor }}andvar_cursor→{{ WORKSPACE_VARIABLES.cursor }}.
For loop over
{{ read_cursor.page }}— your per-record work. This loops through each index for the page and you can check each run in the child iterations of the execution logs

Update Workspace Variable - set
cursorto{{ read_cursor.next_cursor }}. This advances the saved cursor so the next run reads the new value.

If/Else on
{{ read_cursor.has_more }} == true:true → HTTP Request, POST to the trigger's webhook CURL and parse it

false → Update Workspace Variable set
cursorback to 0, then stop.
Swap in a real source
Replace the stand-in list in step 3. Only the cursor and the "more pages" check change:
GraphQL (Shopify)
endCursor
hasNextPage
Cursor REST (HubSpot)
paging.next.after
paging.next exists
Database
last row's id
full page returned
Watch out for
Use the Update Workspace Variable node, not "Update Workflow Variable." They look identical but write to different stores; mixing them up means your cursor never actually moves and the workflow loops forever on the same page.
Timeout: keep the page size small so each run finishes well under 300 seconds.
Last updated