Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.dualship.run/llms.txt

Use this file to discover all available pages before exploring further.

The http node makes HTTP requests to external APIs. It supports all standard HTTP methods, custom headers, query parameters, and request bodies.

Configuration

{
  "id": "fetch_user",
  "type": "http",
  "config": {
    "method": "GET",
    "url": "https://api.example.com/users/{{user_id}}",
    "headers": {
      "Authorization": "Bearer {{env.API_KEY}}"
    },
    "timeout": 10000
  }
}

Config Fields

FieldTypeRequiredDefaultDescription
urlstringYes-Request URL (supports templates)
methodstringNo"GET"HTTP method
headersobjectNo-Request headers
queryobjectNo-Query string parameters
bodyanyNo-Request body
body_typestringNo"json"Body format: "json", "form", or "multipart"
filesarrayNo-Files to upload (auto-sets body_type to multipart)
timeoutnumberNo30000Timeout in milliseconds (max 60000)
content_typestringNoautoContent-Type header
on_errorstringNo"abort"Error handling: "abort" or "continue"

HTTP Methods

Supported methods: GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS
{ "method": "GET" }
{ "method": "POST" }
{ "method": "PUT" }
{ "method": "DELETE" }
{ "method": "PATCH" }

Output

{
  "status_code": 200,
  "headers": {
    "content-type": "application/json",
    "x-request-id": "abc123"
  },
  "body": {
    "id": 1,
    "name": "John Doe"
  },
  "latency_ms": 150,
  "success": true,
  "error": null
}
FieldTypeDescription
status_codenumberHTTP status code
headersobjectResponse headers
bodyanyResponse body (auto-parsed if JSON)
latency_msnumberRequest duration in milliseconds
successbooleantrue if status is 2xx
errorstringError message (only with on_error: "continue")

Examples

GET Request

{
  "id": "get_user",
  "type": "http",
  "config": {
    "method": "GET",
    "url": "https://api.example.com/users/{{request.query.user_id}}"
  }
}

GET with Query Parameters

{
  "id": "search_users",
  "type": "http",
  "config": {
    "method": "GET",
    "url": "https://api.example.com/users",
    "query": {
      "search": "{{request.query.q}}",
      "limit": "10",
      "offset": "{{request.query.page | multiply:10}}"
    }
  }
}

POST with JSON Body

{
  "id": "create_user",
  "type": "http",
  "config": {
    "method": "POST",
    "url": "https://api.example.com/users",
    "headers": {
      "Authorization": "Bearer {{env.API_KEY}}",
      "Content-Type": "application/json"
    },
    "body": {
      "name": "{{request.body.name}}",
      "email": "{{request.body.email}}",
      "role": "user"
    }
  }
}

PUT Request

{
  "id": "update_user",
  "type": "http",
  "config": {
    "method": "PUT",
    "url": "https://api.example.com/users/{{user_id}}",
    "body": {
      "name": "{{request.body.name}}",
      "updated_at": "{{now}}"
    }
  }
}

DELETE Request

{
  "id": "delete_user",
  "type": "http",
  "config": {
    "method": "DELETE",
    "url": "https://api.example.com/users/{{request.body.user_id}}"
  }
}

With Custom Headers

{
  "id": "api_call",
  "type": "http",
  "config": {
    "method": "POST",
    "url": "https://api.example.com/webhook",
    "headers": {
      "Authorization": "Bearer {{env.API_TOKEN}}",
      "X-Request-ID": "{{request_id}}",
      "X-Timestamp": "{{now}}",
      "Accept": "application/json"
    },
    "body": "{{payload}}"
  }
}

With Timeout

{
  "id": "slow_api",
  "type": "http",
  "config": {
    "url": "https://slow-api.example.com/process",
    "timeout": 60000
  }
}

Error Handling

on_error: "abort" (default)

If the request fails (network error, timeout, non-2xx status), the flow stops immediately.
{
  "id": "critical_api",
  "type": "http",
  "config": {
    "url": "https://api.example.com/critical",
    "on_error": "abort"
  }
}

on_error: "continue"

Errors are captured in the output instead of failing the flow:
{
  "id": "optional_api",
  "type": "http",
  "config": {
    "url": "https://api.example.com/optional",
    "on_error": "continue"
  }
}
Then check the result:
{
  "id": "check_result",
  "type": "condition",
  "config": {
    "conditions": [
      {
        "if": "{{optional_api.output.success}} == true",
        "then": ["process_data"]
      }
    ],
    "else": ["use_fallback"]
  }
}

Body Handling

JSON Body (default)

Objects are automatically serialized as JSON:
{
  "body": {
    "name": "John",
    "age": 30
  }
}

Form URL Encoded

Use body_type: "form" to send application/x-www-form-urlencoded data. Common for OAuth token requests:
{
  "id": "oauth_token",
  "type": "http",
  "config": {
    "method": "POST",
    "url": "https://oauth.example.com/token",
    "body_type": "form",
    "body": {
      "grant_type": "client_credentials",
      "client_id": "{{env.CLIENT_ID}}",
      "client_secret": "{{env.CLIENT_SECRET}}"
    }
  }
}
The body is encoded as: grant_type=client_credentials&client_id=xxx&client_secret=yyy

Multipart File Upload

Use body_type: "multipart" or add a files array to upload files:
{
  "id": "upload_file",
  "type": "http",
  "config": {
    "method": "POST",
    "url": "https://api.example.com/upload",
    "body": {
      "description": "Monthly report",
      "category": "reports"
    },
    "files": [
      {
        "field": "document",
        "filename": "report.pdf",
        "content": "base64:JVBERi0xLjQK..."
      }
    ]
  }
}
File Config:
FieldTypeRequiredDescription
fieldstringYesForm field name for the file
filenamestringYesFilename to send
contentstringYesFile content (prefix with base64: for binary)
Multiple Files:
{
  "files": [
    {
      "field": "document",
      "filename": "report.pdf",
      "content": "base64:JVBERi0xLjQK..."
    },
    {
      "field": "thumbnail",
      "filename": "preview.png",
      "content": "base64:iVBORw0KGgo..."
    }
  ]
}

String Body

Strings are sent as-is:
{
  "body": "raw string content",
  "content_type": "text/plain"
}

Template Body

Use templates for dynamic content:
{
  "body": "{{prepared_payload}}"
}

Response Parsing

  • JSON responses are automatically parsed into objects
  • Other responses are returned as strings
  • Check Content-Type header to determine response format

URL Templates

The URL supports template expressions:
"url": "https://api.example.com/users/{{user_id}}/posts/{{post_id}}"  # Path parameters
"url": "https://{{env.API_HOST}}/v1/users"                            # Dynamic host
"url": "https://api.example.com/{{api_version}}/users"                # Conditional path

Common Patterns

Authenticated Request

{
  "id": "authenticated_call",
  "type": "http",
  "config": {
    "url": "https://api.example.com/protected",
    "headers": {
      "Authorization": "Bearer {{auth_token}}"
    }
  }
}

OAuth Token Exchange

{
  "id": "get_token",
  "type": "http",
  "config": {
    "method": "POST",
    "url": "https://oauth.example.com/token",
    "body_type": "form",
    "body": {
      "grant_type": "client_credentials",
      "client_id": "{{env.CLIENT_ID}}",
      "client_secret": "{{env.CLIENT_SECRET}}",
      "scope": "read write"
    }
  }
}
Then use the token in subsequent requests:
{
  "id": "api_call",
  "type": "http",
  "config": {
    "url": "https://api.example.com/data",
    "headers": {
      "Authorization": "Bearer {{get_token.output.body.access_token}}"
    }
  }
}

Pagination

{
  "id": "fetch_page",
  "type": "http",
  "config": {
    "url": "https://api.example.com/items",
    "query": {
      "page": "{{current_page}}",
      "per_page": "50"
    }
  }
}

Webhook Call

{
  "id": "send_webhook",
  "type": "http",
  "config": {
    "method": "POST",
    "url": "{{webhook_url}}",
    "headers": {
      "X-Webhook-Secret": "{{env.WEBHOOK_SECRET}}"
    },
    "body": {
      "event": "order.created",
      "data": "{{order}}"
    }
  }
}

File Upload

{
  "id": "upload_document",
  "type": "http",
  "config": {
    "method": "POST",
    "url": "https://api.example.com/documents",
    "headers": {
      "Authorization": "Bearer {{env.API_KEY}}"
    },
    "body": {
      "title": "{{request.body.title}}",
      "folder_id": "{{request.body.folder_id}}"
    },
    "files": [
      {
        "field": "file",
        "filename": "{{request.body.filename}}",
        "content": "{{request.body.file_content}}"
      }
    ]
  }
}