> ## Documentation Index
> Fetch the complete documentation index at: https://docs.edges.run/llms.txt
> Use this file to discover all available pages before exploring further.

# Edges on n8n

> Integrate the Edges API with n8n.

This guide targets **[n8n](https://n8n.io/cloud)** users. It uses **`linkedin-search-people`** but you can apply the same patterns to other actions by changing the path and JSON body.

**Goals:**

* **How To** — Tips and good practice to implement Edges.
* **Manage Cursor** — paginate with **`X-Pagination-Next`** until done;
* **Fewer webhooks** — use Edges `callback.on: "final"` for async so you get one callback per run, then pull data with [`GET /v1/runs/{run_uid}/outputs`](/v1/api/runs/outputs) ([Callbacks](/v1/runs/callbacks)).

***

## 1. Set the request body to JSON

Use an **HTTP Request** node:

1. **Method** `POST`.
2. Enable **Send Body**.
3. Body Content Type → **JSON**.
4. Paste or build your JSON.

<Frame caption="n8n Cloud: HTTP Request JSON body for Edges API">
  <img src="https://mintcdn.com/edges/Fe6p1R90EepkV3ok/images/guides/n8n-cloud-edges-api-http-request-json-body-configuration.png?fit=max&auto=format&n=Fe6p1R90EepkV3ok&q=85&s=5b7a8125c2fe0b5ab704523939854324" alt="n8n Cloud HTTP Request node showing JSON body configuration for Edges API" width="826" height="588" data-path="images/guides/n8n-cloud-edges-api-http-request-json-body-configuration.png" />
</Frame>

You can also set the `Accept: application/json` header to ensure the response is in JSON format.

***

## 2. Send the `X-API-Key` header

For each request to the Edges API you need to authenticate thanks to your API key.
Edges authenticates with **`X-API-Key`** (not Bearer).

Add a header field

<Frame caption="n8n Cloud: X-API-Key header for Edges API authentication">
  <img src="https://mintcdn.com/edges/Fe6p1R90EepkV3ok/images/guides/n8n-cloud-edges-api-x-api-key-header-authentication.png?fit=max&auto=format&n=Fe6p1R90EepkV3ok&q=85&s=f4730b02a36a0d16d0b09056d76bbcbc" alt="n8n Cloud HTTP Request headers with X-API-Key for Edges API" width="850" height="640" data-path="images/guides/n8n-cloud-edges-api-x-api-key-header-authentication.png" />
</Frame>

Consider creating a **Custom Authentication** using n8n's Generic Credential Type. This allows you to securely **store and reuse your credentials** across all HTTP Request nodes in your workflows, improving both security and convenience.

<Frame caption="n8n Cloud: X-API-Key header for Edges API authentication">
  <img src="https://mintcdn.com/edges/Fe6p1R90EepkV3ok/images/guides/n8n-cloud-edges-api-custom-authentication-method.png?fit=max&auto=format&n=Fe6p1R90EepkV3ok&q=85&s=3bdd38194c1674a09f2107a4f8f80aac" alt="n8n Cloud HTTP Request with Custom Auth for Edges API" width="846" height="488" data-path="images/guides/n8n-cloud-edges-api-custom-authentication-method.png" />
</Frame>

***

## 3. Show headers and body

Enable **Include Response Headers and Status** / **Full response** (wording depends on n8n version).

The item shape is typically like `{ body, headers, statusCode }` so the next step can read `headers['x-pagination-next']`.

<Frame caption="n8n Cloud: full response with headers and JSON body for Edges">
  <img src="https://mintcdn.com/edges/Fe6p1R90EepkV3ok/images/guides/n8n-cloud-edges-api-http-headers-json-body-full-response.png?fit=max&auto=format&n=Fe6p1R90EepkV3ok&q=85&s=4c5835fda37dcc295ee94cb5228735ea" alt="n8n Cloud HTTP Request showing headers, JSON body, and full response option for Edges" width="836" height="252" data-path="images/guides/n8n-cloud-edges-api-http-headers-json-body-full-response.png" />
</Frame>

***

## Live mode: native loop on `X-Pagination-Next`

In **live** mode, Edges returns the next page as a **full URL** in the **`X-Pagination-Next`** header.
Call it **exactly** as returned. stop when the header is missing or empty.

### Simple implementation

1. Edit Field `cursor` to empty string or with the returned cursor header ← `{{ $runIndex === 0 ? '' : $('Extract Pagination Cursor').first().json.pagination_cursor }}`
2. Check if `cursor` is set. If empty then launch the first request. If cursor exist then go to the cursor request.
3. HTTP Request — `POST` to `https://api.edges.run/v1/actions/linkedin-search-people/run/live` and **full response** enabled. Or use the `cursor` as URL.
4. Edit Field — extract `cursor`
5. Check if `cursor` is returned. If cursor exist then go back to the first step of the loop !
6. If no cursor is returned then continue. **You have to process or store the results during the loop**.

<Warning>
  Add a **max iteration** safeguard (n8n workflow settings timeout, or a small counter — see [optional Code](#optional-merge-many-pages-code-only-if-needed)) so a bug cannot run forever.
</Warning>

<Frame caption="n8n Cloud: native IF loop for Edges live X-Pagination-Next pagination">
  <img src="https://mintcdn.com/edges/Fe6p1R90EepkV3ok/images/guides/n8n-cloud-edges-api-live-cursor-pagination-native-loop.png?fit=max&auto=format&n=Fe6p1R90EepkV3ok&q=85&s=0d29414013f905c393ddffcf13b69a74" alt="n8n Cloud workflow: Set, IF, and HTTP Request loop for Edges live pagination" width="2542" height="596" data-path="images/guides/n8n-cloud-edges-api-live-cursor-pagination-native-loop.png" />
</Frame>

### Importable workflow (live loop)

Replace the placeholder key in both HTTP nodes after import. Complete the canvas so **HTTP Next page** connects back to **Extract pagination**.

<Accordion title="JSON — Sales Navigator live pagination">
  Copy Paste this json directly into your n8n workflow editor
  Then edit the API keys and input request URL

  ```json theme={null}
  {
    "nodes": [
      {
        "parameters": {},
        "type": "n8n-nodes-base.manualTrigger",
        "typeVersion": 1,
        "position": [-256, -272],
        "id": "ebf5bc97-b994-4c4f-9784-f04bca7f0bec",
        "name": "When clicking ‘Execute workflow’"
      },
      {
        "parameters": {
          "conditions": {
            "options": {
              "caseSensitive": true,
              "leftValue": "",
              "typeValidation": "strict",
              "version": 3
            },
            "conditions": [
              {
                "id": "1b593099-50d6-4fa7-85b3-bd41ccb0e989",
                "leftValue": "={{ $json.cursor }}",
                "rightValue": "''",
                "operator": {
                  "type": "string",
                  "operation": "empty",
                  "singleValue": true
                }
              }
            ],
            "combinator": "and"
          },
          "options": {}
        },
        "type": "n8n-nodes-base.if",
        "typeVersion": 2.3,
        "position": [224, -272],
        "id": "2dd0338d-de01-4847-9f31-6546b5899597",
        "name": "If"
      },
      {
        "parameters": {
          "method": "POST",
          "url": "https://api.edges.run/v1/actions/salesnavigator-search-people/run/live",
          "sendQuery": true,
          "queryParameters": {
            "parameters": [
              {
                "name": "page_size",
                "value": "25"
              }
            ]
          },
          "sendHeaders": true,
          "headerParameters": {
            "parameters": [
              {
                "name": "X-API-Key",
                "value": "xxxx-MY-EDGES-API-KEY-xxxx"
              }
            ]
          },
          "sendBody": true,
          "specifyBody": "json",
          "jsonBody": "={\n  \"input\": {\n    \"sales_navigator_profile_search_url\": \"https://www.linkedin.com/sales/search/people?[REDACTED_SAVED_SEARCH_OR_QUERY]\",\n    \"custom_data\": {}\n  },\n  \"parameters\": {\n    \"exclude_crm_contacts\": false,\n    \"exclude_viewed_leads\": false\n  },\n  \"identity_mode\": \"managed\"\n}",
          "options": {
            "response": {
              "response": {
                "fullResponse": true
              }
            }
          }
        },
        "type": "n8n-nodes-base.httpRequest",
        "typeVersion": 4.3,
        "position": [512, -384],
        "id": "980d947a-c966-47ab-b4f6-fd9b0c5cfc3f",
        "name": "First Request"
      },
      {
        "parameters": {
          "method": "POST",
          "url": "={{ $('Extract Pagination Cursor').first().json.pagination_cursor }}",
          "sendQuery": true,
          "queryParameters": {
            "parameters": [
              {
                "name": "page_size",
                "value": "25"
              }
            ]
          },
          "sendHeaders": true,
          "headerParameters": {
            "parameters": [
              {
                "name": "X-API-Key",
                "value": "xxxx-MY-EDGES-API-KEY-xxxx"
              }
            ]
          },
          "sendBody": true,
          "specifyBody": "json",
          "jsonBody": "={\n  \"input\": {\n    \"sales_navigator_profile_search_url\": \"https://www.linkedin.com/sales/search/people?[REDACTED_SAVED_SEARCH_OR_QUERY]\",\n    \"custom_data\": {}\n  },\n  \"parameters\": {\n    \"exclude_crm_contacts\": false,\n    \"exclude_viewed_leads\": false\n  },\n  \"identity_mode\": \"managed\"\n}",
          "options": {
            "response": {
              "response": {
                "fullResponse": true
              }
            }
          }
        },
        "type": "n8n-nodes-base.httpRequest",
        "typeVersion": 4.3,
        "position": [512, -208],
        "id": "d2afc651-7e49-4d1d-8e92-50c8ff498e93",
        "name": "Cursor Request"
      },
      {
        "parameters": {
          "assignments": {
            "assignments": [
              {
                "id": "id-1",
                "name": "cursor",
                "value": "={{ $runIndex === 0 ? '' : $('Extract Pagination Cursor').first().json.pagination_cursor }}",
                "type": "string"
              }
            ]
          },
          "includeOtherFields": true,
          "options": {}
        },
        "id": "3c05caa0-ea80-4a3b-b476-db7f29f2be90",
        "name": "Loop Start",
        "type": "n8n-nodes-base.set",
        "typeVersion": 3.4,
        "position": [16, -272]
      },
      {
        "parameters": {
          "assignments": {
            "assignments": [
              {
                "id": "id-1",
                "name": "pagination_cursor",
                "value": "={{ $json.headers['x-pagination-next'] }}",
                "type": "string"
              },
              {
                "id": "id-2",
                "name": "results",
                "value": "={{ $json.body }}",
                "type": "array"
              }
            ]
          },
          "includeOtherFields": true,
          "options": {}
        },
        "id": "f4528818-b1d3-46a9-a657-f5891e5b90ca",
        "name": "Extract Pagination Cursor",
        "type": "n8n-nodes-base.set",
        "typeVersion": 3.4,
        "position": [848, -272]
      },
      {
        "parameters": {
          "conditions": {
            "options": {
              "caseSensitive": true,
              "leftValue": "",
              "typeValidation": "strict",
              "version": 3
            },
            "conditions": [
              {
                "id": "id-1",
                "leftValue": "={{ $('Extract Pagination Cursor').first().json.pagination_cursor }}",
                "operator": {
                  "type": "string",
                  "operation": "notEmpty"
                }
              }
            ],
            "combinator": "and"
          },
          "options": {}
        },
        "id": "2f279d41-385d-4f9b-a8e7-28f26b3d4e9f",
        "name": "More Pages?",
        "type": "n8n-nodes-base.if",
        "typeVersion": 2.3,
        "position": [1072, -224]
      }
    ],
    "connections": {
      "When clicking ‘Execute workflow’": {
        "main": [[{ "node": "Loop Start", "type": "main", "index": 0 }]]
      },
      "If": {
        "main": [
          [{ "node": "First Request", "type": "main", "index": 0 }],
          [{ "node": "Cursor Request", "type": "main", "index": 0 }]
        ]
      },
      "First Request": {
        "main": [[{ "node": "Extract Pagination Cursor", "type": "main", "index": 0 }]]
      },
      "Cursor Request": {
        "main": [[{ "node": "Extract Pagination Cursor", "type": "main", "index": 0 }]]
      },
      "Loop Start": {
        "main": [[{ "node": "If", "type": "main", "index": 0 }]]
      },
      "Extract Pagination Cursor": {
        "main": [[{ "node": "More Pages?", "type": "main", "index": 0 }]]
      },
      "More Pages?": {
        "main": [
          [{ "node": "Loop Start", "type": "main", "index": 0 }],
          []
        ]
      }
    },
    "pinData": {},
    "meta": {
      "templateCredsSetupCompleted": false
    }
  }
  ```
</Accordion>

***

## Async mode: `final` webhook + outputs pagination

### Why `callback.on: "final"`

With `"final"`, Edges sends **one** callback when the run finishes instead of streaming many callbacks. That fits n8n Cloud well: one **Webhook** execution per run, then you pull the full result set with the outputs API ([Streaming vs final callbacks](/v1/runs/callbacks#streaming-vs-final-callbacks)).

### Start the async run

HTTP Request POST on `https://api.edges.run/v1/actions/linkedin-search-people/run/async`

Body example (replace the webhook URL with yours):

```json theme={null}
{
  "parameters": {},
  "identity_mode": "managed",
  "callback": {
    "url": "https://YOUR-SUBDOMAIN.app.n8n.cloud/webhook/edges-async-final",
    "on": "final"
  }
}
```

### When the Webhook fires

The payload includes **`run.run_uid`** (see [Callbacks](/v1/runs/callbacks#final-mode-%22final%22)). Use **Edit Fields (Set)**:

1. **HTTP Request** — method **GET**. In the URL field, use the `runUid` returned to the callback.
   ` https://api.edges.run/v1/runs/{{ $json.runUid }}/outputs` and enable **full response**.
2. Same **Set / IF / HTTP** pattern as live mode:
   * `nextUrl` from `x-pagination-next`
3. Loop until no cursor are returned.

***

## Related Edges documentation

* [Pagination](/v1/runs/pagination)
* [Callbacks](/v1/runs/callbacks) — **`on: "final"`**
* [Get run outputs](/v1/api/runs/outputs)
* [Runs overview](/v1/runs/overview)
* [API introduction](/v1/api/introduction)
