> ## 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.

# HTTP Trigger

> Create REST API endpoints that execute your flows

The `http` trigger is the most common trigger type. It creates a REST endpoint that executes your flow when called.

## Configuration

```json theme={null}
{
  "trigger": {
    "type": "http",
    "config": {
      "method": "POST",
      "path": "/payments"
    }
  }
}
```

## Config Fields

| Field    | Type   | Required | Description                                |
| -------- | ------ | -------- | ------------------------------------------ |
| `method` | string | Yes      | HTTP method: GET, POST, PUT, DELETE, PATCH |
| `path`   | string | Yes      | URL path for the endpoint                  |

## HTTP Methods

| Method   | Typical Use       |
| -------- | ----------------- |
| `GET`    | Retrieve data     |
| `POST`   | Create resources  |
| `PUT`    | Replace resources |
| `PATCH`  | Partial updates   |
| `DELETE` | Remove resources  |

## Path Patterns

Paths must start with `/` and can include path parameters:

```json theme={null}
// Simple path
{ "path": "/users" }

// With parameters
{ "path": "/users/:id" }

// Nested resources
{ "path": "/users/:user_id/orders/:order_id" }
```

### Path Parameters

Path parameters are accessible in the request context:

```json theme={null}
// Path: /users/:id
// Request: GET /users/123

// Access in nodes:
"{{request.params.id}}"  // "123"
```

## Endpoint URL

Your flow's endpoint URL is constructed from your project's subdomain and the path:

```
https://{project-slug}.dualship.run{path}
```

For example:

* Project slug: `acme-api`
* Path: `/payments`
* Full URL: `https://acme-api.dualship.run/payments`

## Content Types

HTTP triggers support these content types:

| Content-Type          | Description                   |
| --------------------- | ----------------------------- |
| `application/json`    | JSON request body (default)   |
| `multipart/form-data` | File uploads with form fields |

## Runtime Context

When an HTTP request triggers your flow, the context includes:

```json theme={null}
{
  "request": {
    "method": "POST",
    "path": "/payments",
    "params": {
      "id": "123"
    },
    "headers": {
      "authorization": "Bearer xxx",
      "content-type": "application/json",
      "user-agent": "Mozilla/5.0..."
    },
    "query": {
      "debug": "true",
      "limit": "10"
    },
    "body": {
      "amount": 1000,
      "currency": "usd"
    }
  },
  "env": {
    "environment": "production"
  }
}
```

### Context References

| Reference                           | Description                     |
| ----------------------------------- | ------------------------------- |
| `{{request.method}}`                | HTTP method (GET, POST, etc.)   |
| `{{request.path}}`                  | Request path                    |
| `{{request.params.id}}`             | Path parameter                  |
| `{{request.headers.authorization}}` | Request header                  |
| `{{request.query.limit}}`           | Query string parameter          |
| `{{request.body}}`                  | Full request body               |
| `{{request.body.amount}}`           | Body field                      |
| `{{request.files}}`                 | Uploaded files (multipart only) |
| `{{request.files.avatar}}`          | Specific uploaded file          |

## Examples

### GET Endpoint

Retrieve a user by ID:

```json theme={null}
{
  "name": "Get User",
  "trigger": {
    "type": "http",
    "config": {
      "method": "GET",
      "path": "/users/:id"
    }
  },
  "nodes": [
    {
      "id": "fetch_user",
      "type": "http",
      "config": {
        "method": "GET",
        "url": "https://api.example.com/users/{{request.params.id}}"
      }
    },
    {
      "id": "respond",
      "type": "response",
      "config": {
        "status": 200,
        "body": "{{fetch_user.output.body}}"
      }
    }
  ]
}
```

### POST Endpoint

Create a new resource:

```json theme={null}
{
  "name": "Create Order",
  "trigger": {
    "type": "http",
    "config": {
      "method": "POST",
      "path": "/orders"
    }
  },
  "nodes": [
    {
      "id": "validate",
      "type": "request",
      "config": {
        "source": "request.body",
        "schema": {
          "customer_id": "required|string",
          "items": "required|array|min:1"
        }
      }
    },
    {
      "id": "create_order",
      "type": "http",
      "config": {
        "method": "POST",
        "url": "https://api.example.com/orders",
        "body": {
          "customer_id": "{{request.body.customer_id}}",
          "items": "{{request.body.items}}",
          "created_at": "{{now}}"
        }
      }
    },
    {
      "id": "respond",
      "type": "response",
      "config": {
        "status": 201,
        "body": {
          "id": "{{create_order.output.body.id}}",
          "status": "created"
        }
      }
    }
  ]
}
```

### PUT Endpoint

Replace a resource:

```json theme={null}
{
  "name": "Update User",
  "trigger": {
    "type": "http",
    "config": {
      "method": "PUT",
      "path": "/users/:id"
    }
  },
  "nodes": [
    {
      "id": "update_user",
      "type": "http",
      "config": {
        "method": "PUT",
        "url": "https://api.example.com/users/{{request.params.id}}",
        "body": "{{request.body}}"
      }
    },
    {
      "id": "respond",
      "type": "response",
      "config": {
        "status": 200,
        "body": "{{update_user.output.body}}"
      }
    }
  ]
}
```

### DELETE Endpoint

Remove a resource:

```json theme={null}
{
  "name": "Delete User",
  "trigger": {
    "type": "http",
    "config": {
      "method": "DELETE",
      "path": "/users/:id"
    }
  },
  "nodes": [
    {
      "id": "delete_user",
      "type": "http",
      "config": {
        "method": "DELETE",
        "url": "https://api.example.com/users/{{request.params.id}}"
      }
    },
    {
      "id": "respond",
      "type": "response",
      "config": {
        "status": 204
      }
    }
  ]
}
```

### With Query Parameters

List resources with filtering:

```json theme={null}
{
  "name": "List Orders",
  "trigger": {
    "type": "http",
    "config": {
      "method": "GET",
      "path": "/orders"
    }
  },
  "nodes": [
    {
      "id": "fetch_orders",
      "type": "http",
      "config": {
        "method": "GET",
        "url": "https://api.example.com/orders",
        "query": {
          "status": "{{request.query.status | default:all}}",
          "limit": "{{request.query.limit | default:20}}",
          "offset": "{{request.query.offset | default:0}}"
        }
      }
    },
    {
      "id": "respond",
      "type": "response",
      "config": {
        "status": 200,
        "body": {
          "data": "{{fetch_orders.output.body.data}}",
          "total": "{{fetch_orders.output.body.total}}"
        }
      }
    }
  ]
}
```

### With Authentication

Validate authorization header:

```json theme={null}
{
  "name": "Protected Endpoint",
  "trigger": {
    "type": "http",
    "config": {
      "method": "GET",
      "path": "/protected"
    }
  },
  "nodes": [
    {
      "id": "check_auth",
      "type": "condition",
      "config": {
        "conditions": [
          {
            "if": "{{request.headers.authorization}} == Bearer {{env.API_KEY}}",
            "then": ["fetch_data"]
          }
        ],
        "else": ["unauthorized"]
      }
    },
    {
      "id": "unauthorized",
      "type": "abort",
      "config": {
        "status": 401,
        "body": { "error": "Unauthorized" }
      }
    },
    {
      "id": "fetch_data",
      "type": "http",
      "config": {
        "url": "https://api.example.com/data"
      }
    },
    {
      "id": "respond",
      "type": "response",
      "config": {
        "status": 200,
        "body": "{{fetch_data.output.body}}"
      }
    }
  ]
}
```

## Request Validation

Use the [request node](/nodes/request) to validate incoming data:

```json theme={null}
{
  "id": "validate",
  "type": "request",
  "config": {
    "source": "request.body",
    "schema": {
      "email": "required|email",
      "amount": "required|integer|min:1",
      "currency": "required|in:usd,eur,gbp"
    },
    "on_error": {
      "action": "abort",
      "status": 400,
      "body": {
        "error": "Validation failed",
        "details": "{{validation_errors}}"
      }
    }
  }
}
```

## File Uploads

Accept file uploads via `multipart/form-data` requests. Uploaded files are available in `request.files`.

### File Object Structure

Each uploaded file contains:

```json theme={null}
{
  "request": {
    "files": {
      "avatar": {
        "name": "profile.jpg",
        "size": 245678,
        "content_type": "image/jpeg",
        "content": "<base64-encoded-content>"
      }
    }
  }
}
```

| Field          | Type   | Description                                       |
| -------------- | ------ | ------------------------------------------------- |
| `name`         | string | Original filename                                 |
| `size`         | number | File size in bytes                                |
| `content_type` | string | MIME type (e.g., `image/jpeg`, `application/pdf`) |
| `content`      | string | Base64-encoded file content                       |

### File References

| Reference                               | Description        |
| --------------------------------------- | ------------------ |
| `{{request.files.avatar}}`              | Full file object   |
| `{{request.files.avatar.name}}`         | Original filename  |
| `{{request.files.avatar.size}}`         | File size in bytes |
| `{{request.files.avatar.content_type}}` | MIME type          |
| `{{request.files.avatar.content}}`      | Base64 content     |

### File Upload Example

Accept and validate a file upload:

```json theme={null}
{
  "name": "Upload Avatar",
  "trigger": {
    "type": "http",
    "config": {
      "method": "POST",
      "path": "/users/:id/avatar"
    }
  },
  "nodes": [
    {
      "id": "validate",
      "type": "request",
      "config": {
        "source": "request.files",
        "schema": {
          "avatar": "required|image|dimensions:min_width=200,min_height=200"
        }
      }
    },
    {
      "id": "upload",
      "type": "http",
      "config": {
        "method": "POST",
        "url": "https://storage.example.com/upload",
        "headers": {
          "Authorization": "Bearer {{env.STORAGE_KEY}}"
        },
        "files": [
          {
            "field": "file",
            "filename": "{{request.files.avatar.name}}",
            "content": "{{request.files.avatar.content}}"
          }
        ],
        "body": {
          "user_id": "{{request.params.id}}"
        }
      }
    },
    {
      "id": "respond",
      "type": "response",
      "config": {
        "status": 200,
        "body": {
          "success": true,
          "url": "{{upload.output.body.url}}"
        }
      }
    }
  ]
}
```

### Multiple Files with Form Data

Handle multiple files along with form fields:

```json theme={null}
{
  "name": "Submit Document",
  "trigger": {
    "type": "http",
    "config": {
      "method": "POST",
      "path": "/documents"
    }
  },
  "nodes": [
    {
      "id": "validate_body",
      "type": "request",
      "config": {
        "source": "request.body",
        "schema": {
          "title": "required|string|max:200",
          "category": "required|in:report,invoice,contract"
        }
      }
    },
    {
      "id": "validate_files",
      "type": "request",
      "config": {
        "source": "request.files",
        "schema": {
          "document": "required|file|extensions:pdf,doc,docx",
          "thumbnail": "sometimes|image|dimensions:max_width=400"
        }
      }
    },
    {
      "id": "process",
      "type": "transform",
      "config": {
        "output": {
          "title": "{{request.body.title}}",
          "category": "{{request.body.category}}",
          "document_name": "{{request.files.document.name}}",
          "document_size": "{{request.files.document.size}}",
          "has_thumbnail": "{{request.files.thumbnail | default:false}}"
        }
      }
    }
  ]
}
```

## CORS

Configure CORS in your [project settings](/project-settings) to allow cross-origin requests:

```json theme={null}
{
  "cors": {
    "enabled": true,
    "allowed_origins": ["https://example.com"],
    "allowed_methods": ["GET", "POST", "PUT", "DELETE"],
    "allow_credentials": true
  }
}
```

## Rate Limiting

Enable rate limiting in [project settings](/project-settings) to protect your endpoints:

```json theme={null}
{
  "rate_limit": {
    "enabled": true,
    "requests_per_min": 100,
    "burst_size": 20
  }
}
```

## Common Patterns

### REST API

Create a full REST API for a resource:

| Endpoint | Method | Path         | Description   |
| -------- | ------ | ------------ | ------------- |
| List     | GET    | `/users`     | Get all users |
| Get      | GET    | `/users/:id` | Get one user  |
| Create   | POST   | `/users`     | Create user   |
| Update   | PUT    | `/users/:id` | Update user   |
| Delete   | DELETE | `/users/:id` | Delete user   |

### Webhook Receiver

Accept webhooks from external services:

```json theme={null}
{
  "name": "Stripe Webhook",
  "trigger": {
    "type": "http",
    "config": {
      "method": "POST",
      "path": "/webhooks/stripe"
    }
  },
  "nodes": [
    {
      "id": "process",
      "type": "switch",
      "config": {
        "expression": "{{request.body.type}}",
        "cases": [
          { "value": "payment_intent.succeeded", "then": ["handle_payment"] },
          { "value": "customer.created", "then": ["handle_customer"] }
        ],
        "default": ["acknowledge"]
      }
    }
  ]
}
```

### API Gateway

Proxy requests to backend services:

```json theme={null}
{
  "id": "proxy",
  "type": "http",
  "config": {
    "method": "{{request.method}}",
    "url": "https://backend.example.com{{request.path}}",
    "headers": {
      "Authorization": "Bearer {{env.BACKEND_TOKEN}}",
      "X-Forwarded-For": "{{request.headers.x-forwarded-for}}"
    },
    "body": "{{request.body}}"
  }
}
```

## Plan Availability

HTTP triggers are available on all plans including **Free**.

## Related

* [Request Node](/nodes/request) - Validate incoming data
* [Validation Rules](/reference/validation-rules) - Complete validation rule reference
* [Response Node](/nodes/response) - Send HTTP responses
* [Abort Node](/nodes/abort) - Return error responses
* [Project Settings](/project-settings) - Configure CORS and rate limiting
