n8n HTTP Request Node: Connect to Any REST API 2026

The HTTP Request node is arguably the most powerful node in n8n. It lets you connect to any REST API in existence — not just the services with dedicated nodes. If the service has an HTTP API (and they all do), you can integrate it with n8n using this node.

In this guide we go deep on every aspect: methods, headers, authentication strategies, pagination handling, error management, and real-world examples with OpenAI, Stripe, and GitHub APIs.

⚡ Skip the setup

Describe your API integration in plain English at Scriflow and get a complete n8n workflow JSON with the HTTP Request node pre-configured.

HTTP Request Node Overview

The HTTP Request node lives in the Core section of n8n's node library. It handles all standard HTTP verbs and supports virtually every authentication scheme used by modern APIs.

GET
method
Retrieve data. Safe and idempotent. Use for reads, searches, and listing resources.
POST
method
Create resources or trigger actions. Use for creating records, sending messages, AI completions.
PUT / PATCH
method
Update existing resources. PUT replaces the full object; PATCH updates specific fields.
DELETE
method
Remove a resource by ID. Typically returns 204 No Content on success.

Basic Node Configuration

Every HTTP Request node needs at minimum a Method and a URL. Here's how to configure a basic GET request:

Method: GET URL: https://api.github.com/repos/n8n-io/n8n // Dynamic URL using expressions URL: https://api.github.com/repos/{{ $json.owner }}/{{ $json.repo }}

Setting Headers

Most APIs require specific headers. You can add them in the Headers section of the node. Common headers include:

// Common headers Content-Type: application/json Accept: application/json X-API-Version: 2026-01-01 // Dynamic header using expression X-Request-ID: {{ $execution.id }}-{{ $itemIndex }}

Sending a Request Body

For POST/PUT/PATCH requests, configure the body in the Body section. Set Content Type to JSON and provide the payload:

Method: POST URL: https://api.example.com/users Body Content Type: JSON Body: { "name": "{{ $json.fullName }}", "email": "{{ $json.email }}", "role": "user", "metadata": { "source": "n8n-automation", "created_at": "{{ $now.toISO() }}" } }

Authentication Methods

This is where most workflows live or die. The HTTP Request node supports all major authentication patterns:

Auth MethodHeader SentBest For
API Key (Header)X-API-Key: your_keyInternal tools, many SaaS APIs
API Key (Query Param)?api_key=your_keyLegacy APIs, maps APIs
Bearer TokenAuthorization: Bearer tokenJWTs, most modern REST APIs
Basic AuthAuthorization: Basic base64(u:p)GitHub PAT, Jira, older services
OAuth2Authorization: Bearer access_tokenGoogle, Salesforce, HubSpot
Digest AuthWWW-Authenticate handshakeLegacy enterprise systems

API Key Authentication

The simplest option. Select Predefined Credential TypeHTTP Header Auth or use Generic Auth to inject the key manually:

// Using Generic Credential approach Authentication: Generic Credential Type Credential Type: HTTP Header Auth Name: X-API-Key Value: sk-your-api-key-here

Bearer Token Authentication

Authentication: Generic Credential Type Credential Type: HTTP Header Auth Name: Authorization Value: Bearer {{ $credentials.myApiToken }}

OAuth2 Authentication

For OAuth2, create a dedicated credential in n8n's Credentials section first. The node will automatically refresh tokens before they expire — a major advantage over manual token management.

💡 Credential tip

Always store API keys as n8n credentials, never hardcode them in node parameters. Credentials are encrypted at rest and can be shared across workflows without exposing the raw value.

Handling JSON Responses

By default, n8n parses JSON responses automatically. The response data is available on the next node as $json. For nested objects, use dot notation in expressions:

// API response example { "user": { "id": "usr_123", "profile": { "name": "Alice", "plan": "pro" } } } // Access in next node: {{ $json.user.id }} // "usr_123" {{ $json.user.profile.name }} // "Alice" {{ $json.user.profile.plan }} // "pro"

Working with Arrays in Responses

When an API returns an array of items, enable Split Into Items in the node's output settings. This converts the array into individual n8n items, allowing downstream nodes to process each one independently:

// API returns array: { "items": [{ "id": 1 }, { "id": 2 }] } // In node settings: Split Into Items: Enabled Field Containing Array: items // Result: 2 separate items flowing to next node

Pagination with Split In Batches

APIs often return paginated results. n8n handles this elegantly using a loop pattern with Split In Batches:

Cursor-Based Pagination Pattern

  1. Set an initial page or cursor value using a Set node.
  2. Make the HTTP Request with the current page parameter.
  3. Use an IF node to check if next_cursor exists in the response.
  4. If yes — update the cursor with a Set node and loop back to step 2.
  5. If no — continue to downstream processing.
// Query parameter for pagination URL: https://api.example.com/contacts Query Params: limit: 100 cursor: {{ $('Set Cursor').item.json.cursor ?? '' }} // IF node checks for next page {{ $json.next_cursor }} is not empty
📌 Note on rate limits

When paginating through large datasets, add a Wait node (e.g. 500ms) between requests to avoid hitting rate limits. Most APIs limit to 100–1000 requests/minute.

Error Handling

By default, if an API returns a 4xx or 5xx status code, n8n throws an error and stops the workflow. You have two strategies for handling this gracefully:

Strategy 1: Continue on Error

In the node's settings, enable Continue on Error. The node outputs the error details as a regular item, allowing you to route errors differently:

// When Continue on Error is enabled, access error data: {{ $json.error }} // error message {{ $json.statusCode }} // HTTP status code (e.g. 404, 429) {{ $json.cause }} // detailed error cause // Use IF node to check for errors: {{ $json.error }} is not empty

Strategy 2: Retry on Fail

Enable Retry on Fail to automatically retry failed requests. Configure max retries (2–3) and wait between retries (1000ms+). This is ideal for handling transient 429 (Rate Limited) or 503 (Service Unavailable) errors.

Using Expressions in URL and Body

Expressions make the HTTP Request node dynamic. Here are the most useful patterns:

// Build URL from previous node data URL: https://api.stripe.com/v1/customers/{{ $json.customerId }}/invoices // Conditional body field Body: { "amount": {{ $json.amount * 100 }}, "currency": "{{ $json.currency?.toLowerCase() ?? 'usd' }}", "description": "{{ $json.description || 'n8n automated charge' }}" } // Use environment variables (set in n8n settings) URL: {{ $env.API_BASE_URL }}/v2/users

Real-World API Examples

Example 1: OpenAI Chat Completions

Method: POST URL: https://api.openai.com/v1/chat/completions Authentication: Bearer Token (your OpenAI API key) Body: { "model": "gpt-4o", "messages": [ { "role": "user", "content": "{{ $json.userMessage }}" } ], "max_tokens": 500 } // Access the response: {{ $json.choices[0].message.content }}

Example 2: Stripe Create Customer

Method: POST URL: https://api.stripe.com/v1/customers Authentication: Basic Auth (API key as username, empty password) Body Content Type: Form-Urlencoded Body: email={{ $json.email }} name={{ $json.name }} metadata[source]=n8n // Stripe returns the customer object: {{ $json.id }} // "cus_XXXXXXXXX"

Example 3: GitHub Create Issue

Method: POST URL: https://api.github.com/repos/{{ $json.owner }}/{{ $json.repo }}/issues Authentication: Bearer Token (GitHub Personal Access Token) Headers: Accept: application/vnd.github+json X-GitHub-Api-Version: 2022-11-28 Body: { "title": "{{ $json.issueTitle }}", "body": "{{ $json.issueBody }}", "labels": ["bug", "automated"] }

Debugging Tips

  • Use the test execution button: Run the node individually to inspect the raw request and response without triggering the whole workflow.
  • Check the input panel: Verify that expressions resolve to the correct values before the request fires.
  • Enable "Full Response": In node settings, enable this option to access status codes, headers, and full body — crucial for debugging 4xx errors.
  • Log to a Code node: Temporarily add a Code node after the HTTP Request to console.log($input.all()) and inspect the raw output.
  • Test with a Mock API: Use services like httpbin.org to test your request format before hitting the real API.

Frequently Asked Questions

What's the difference between the HTTP Request node and dedicated integration nodes?
Dedicated nodes (e.g. Slack, HubSpot) are pre-built with authentication and common operations. The HTTP Request node is universal — it works with any API but requires manual configuration. Use dedicated nodes when they exist; fall back to HTTP Request for custom or newer APIs.
How do I handle APIs that require mTLS or client certificates?
The HTTP Request node supports SSL certificate configuration under Advanced Settings → TLS. You can provide a client certificate and private key for mutual TLS authentication.
Can I send file uploads (multipart/form-data)?
Yes. Set Body Content Type to Multipart Form Data. You can attach binary data from previous nodes (e.g. after downloading a file) using the {{ $binary.data }} expression.
How do I auto-generate an HTTP Request workflow for any API?
Go to Scriflow, describe the API integration you need (e.g. "Call the OpenAI API to summarize incoming emails and save results to Airtable"), and get a complete n8n JSON ready to import.