# Component-HTTP Flow Integration
Instructions and knowledge for integrating `component-http` into greentic flows (`.ygtc`). This document teaches how to combine Adaptive Card nodes with HTTP API call nodes in a single flow, enabling cards to send/receive data from external APIs.
---
## What is component-http?
A WASM component that makes HTTP requests from within a greentic flow. It runs inside the greentic-runner sandbox — the component calls the host's HTTP client (reqwest) via the `greentic:http@1.0.0` WIT interface. Components cannot open sockets directly; all network access goes through the host.
- **Component ID**: `ai.greentic.component-http`
- **OCI source**: `oci://ghcr.io/greenticai/components/component-http:latest`
- **Operations**: `request` (blocking HTTP), `stream` (SSE/NDJSON)
- **Host requirement**: `greentic:http/client@1.0.0` (enabled automatically for `messaging` flow type)
---
## Schemas
### Config (per-node, set once)
| `base_url` | string (uri) | no | — | Base URL for all requests (e.g., `https://api.example.com/v1`) |
| `auth_type` | string | no | `"none"` | Authentication type: `none`, `bearer`, `api_key`, `basic` |
| `auth_token` | string | no | — | Token/key. Prefix with `secret:` to use secret store (e.g., `secret:API_TOKEN`) |
| `timeout_ms` | number | no | `30000` | Request timeout in milliseconds |
| `api_key_header` | string | no | `"X-API-Key"` | Header name for `api_key` auth type |
| `default_headers` | object | no | — | Default headers added to every request (e.g., `{"Accept": "application/json"}`) |
### Input (per-invocation, from flow data)
| `url` | string | yes | — | Request URL. Can be relative if `base_url` is configured (e.g., `/tickets`) |
| `method` | string | no | `"POST"` | HTTP method: `GET`, `POST`, `PUT`, `DELETE`, `PATCH` |
| `body` | any | no | — | Request body (JSON object or string) |
| `headers` | object | no | — | Additional request headers for this call |
### Output (returned to flow)
| `status` | number | HTTP status code (200, 404, 500, etc.) |
| `body` | any | Response body (parsed as JSON if possible, raw string otherwise) |
---
## Flow Node Syntax
### Schema v2 format (recommended, used by cards2pack)
```yaml
nodes:
my_http_node:
routing:
- to: next_node
run:
component: repo://local/component-http
config:
base_url: https://api.example.com
auth_type: bearer
auth_token: secret:MY_TOKEN
timeout_ms: 15000
default_headers:
Accept: application/json
```
### component.exec format (used in hand-written flows like weather demo)
```yaml
nodes:
my_http_node:
component.exec:
component: ai.greentic.component-http
operation: request
input:
url: "/api/tickets"
method: POST
body:
category: "{{node.form_card.result.category}}"
description: "{{node.form_card.result.description}}"
routing:
- to: next_node
```
Both formats work in greentic-runner. Use schema v2 (`run:`) for consistency with cards2pack-generated flows.
---
## Data Flow Between Nodes
Data passes between nodes using Handlebars-style template references:
| `{{in.input.metadata.KEY}}` | Flow-level input (from ingress payload) |
| `{{node.NODE_ID.result.FIELD}}` | Output from a previously executed node |
| `{{parameters.KEY}}` | Flow-level parameters |
| `{{state.KEY}}` | Flow session state |
### Example: Card form data → HTTP POST → Confirmation card
```
[create_ticket_form] user fills category, priority, description
│
▼ node output includes form field values
[api_create_ticket] POST /api/tickets with form data
│
▼ node output: { status: 201, body: { ticket_id: "IT-123", ... } }
[ticket_confirmation] card displays ticket_id from API response
```
In the flow:
```yaml
api_create_ticket:
component.exec:
component: ai.greentic.component-http
operation: request
input:
url: "/api/tickets"
method: POST
body:
category: "{{node.create_ticket_form.result.category}}"
priority: "{{node.create_ticket_form.result.priority}}"
description: "{{node.create_ticket_form.result.description}}"
routing:
- to: ticket_confirmation
ticket_confirmation:
component.exec:
component: ai.greentic.component-adaptive-card
operation: card
input:
card_source: asset
card_spec:
asset_path: assets/cards/ticket_confirmation.json
payload:
ticket: "{{node.api_create_ticket.result.body}}"
routing:
- out: true
```
---
## Routing Patterns
### Simple: Linear
```yaml
card_a:
routing:
- to: http_call
http_call:
routing:
- to: card_b
card_b:
routing: out
```
### Conditional: Branch based on HTTP response
```yaml
api_check_status:
routing:
- to: success_card
- to: error_card
```
### Card action routing (via routeToCardId)
Card nodes use `routeToCardId` in action data to determine which node to go to next. When inserting an HTTP node between two cards, change the card's `routeToCardId` to point to the HTTP node instead of the next card.
**Before (card → card):**
```
welcome → create_ticket_step1 → create_ticket_step2 → ticket_confirmation
```
**After (card → HTTP → card):**
```
welcome → create_ticket_step1 → create_ticket_step2 → api_create_ticket → ticket_confirmation
```
---
## Complete Example: IT Helpdesk with API Integration
This example extends a static IT helpdesk card flow with real API calls.
### Flow file: `flows/it_helpdesk_portal.ygtc`
```yaml
id: it_helpdesk_portal
type: messaging
start: welcome
parameters: {}
tags: []
schema_version: 2
entrypoints:
default: welcome
nodes:
# ─── WELCOME MENU ───
welcome:
routing:
- to: create_ticket_step1
- to: api_fetch_tickets
- to: call_center
card:
card_source: asset
card_spec:
asset_path: assets/cards/welcome.json
mode: renderAndValidate
node_id: welcome
payload: {}
session: {}
state: {}
validation_mode: warn
# ─── CREATE TICKET: Step 1 (category, priority, description) ───
create_ticket_step1:
routing:
- to: create_ticket_step2
card:
card_source: asset
card_spec:
asset_path: assets/cards/create_ticket_step1.json
mode: renderAndValidate
node_id: create_ticket_step1
payload: {}
session: {}
state: {}
validation_mode: warn
# ─── CREATE TICKET: Step 2 (contact info) ───
create_ticket_step2:
routing:
- to: api_create_ticket
card:
card_source: asset
card_spec:
asset_path: assets/cards/create_ticket_step2.json
mode: renderAndValidate
node_id: create_ticket_step2
payload: {}
session: {}
state: {}
validation_mode: warn
# ─── HTTP: Create ticket via API ───
api_create_ticket:
routing:
- to: ticket_confirmation
component.exec:
component: ai.greentic.component-http
operation: request
input:
url: "/api/tickets"
method: POST
body:
category: "{{node.create_ticket_step1.result.category}}"
priority: "{{node.create_ticket_step1.result.priority}}"
description: "{{node.create_ticket_step1.result.description}}"
fullname: "{{node.create_ticket_step2.result.fullname}}"
email: "{{node.create_ticket_step2.result.email}}"
phone: "{{node.create_ticket_step2.result.phone}}"
# ─── CONFIRMATION: Show created ticket (data from API) ───
ticket_confirmation:
routing:
- to: api_fetch_tickets
- to: welcome
component.exec:
component: ai.greentic.component-adaptive-card
operation: card
input:
card_source: asset
card_spec:
asset_path: assets/cards/ticket_confirmation.json
payload:
ticket: "{{node.api_create_ticket.result.body}}"
# ─── HTTP: Fetch user's tickets ───
api_fetch_tickets:
routing:
- to: view_tickets
component.exec:
component: ai.greentic.component-http
operation: request
input:
url: "/api/tickets"
method: GET
# ─── VIEW TICKETS: List tickets (data from API) ───
view_tickets:
routing:
- to: api_ticket_detail
- to: welcome
component.exec:
component: ai.greentic.component-adaptive-card
operation: card
input:
card_source: asset
card_spec:
asset_path: assets/cards/view_tickets.json
payload:
tickets: "{{node.api_fetch_tickets.result.body}}"
# ─── HTTP: Fetch single ticket detail ───
api_ticket_detail:
routing:
- to: ticket_status
component.exec:
component: ai.greentic.component-http
operation: request
input:
url: "/api/tickets/{{node.view_tickets.result.ticket_select}}"
method: GET
# ─── TICKET STATUS: Show timeline (data from API) ───
ticket_status:
routing:
- to: api_fetch_tickets
- to: welcome
component.exec:
component: ai.greentic.component-adaptive-card
operation: card
input:
card_source: asset
card_spec:
asset_path: assets/cards/ticket_status.json
payload:
ticket: "{{node.api_ticket_detail.result.body}}"
# ─── CALL CENTER (static card, no API needed) ───
call_center:
routing:
- to: request_callback
- to: welcome
card:
card_source: asset
card_spec:
asset_path: assets/cards/call_center.json
mode: renderAndValidate
node_id: call_center
payload: {}
session: {}
state: {}
validation_mode: warn
# ─── REQUEST CALLBACK (static card) ───
request_callback:
routing:
- to: callback_confirmation
card:
card_source: asset
card_spec:
asset_path: assets/cards/request_callback.json
mode: renderAndValidate
node_id: request_callback
payload: {}
session: {}
state: {}
validation_mode: warn
# ─── CALLBACK CONFIRMATION (static card) ───
callback_confirmation:
routing:
- to: welcome
card:
card_source: asset
card_spec:
asset_path: assets/cards/callback_confirmation.json
mode: renderAndValidate
node_id: callback_confirmation
payload: {}
session: {}
state: {}
validation_mode: warn
```
### Component sources in pack manifest
The pack must declare both components:
```yaml
component_sources:
- component_id: ai.greentic.component-adaptive-card
source: oci://ghcr.io/greenticai/components/component-adaptive-card:latest
- component_id: ai.greentic.component-http
source: oci://ghcr.io/greenticai/components/component-http:latest
```
### HTTP node config (set via pack wizard or setup answers)
```json
{
"base_url": "https://helpdesk-api.example.com",
"auth_type": "bearer",
"auth_token": "secret:HELPDESK_API_TOKEN",
"timeout_ms": 15000,
"default_headers": {
"Accept": "application/json",
"Content-Type": "application/json"
}
}
```
---
## When to Use component-http in a Flow
Insert an HTTP node when a card transition needs to:
| Submit form data to backend | POST | Between form card and confirmation card |
| Fetch list data to display | GET | Before a list/table card |
| Fetch detail for a selected item | GET | Between list card and detail card |
| Update a record | PUT/PATCH | Between edit form and result card |
| Delete a record | DELETE | Between confirm-delete card and success card |
Do NOT use component-http for:
- Card-to-card navigation that doesn't need backend data (keep static routing)
- API calls that should happen outside the flow (e.g., webhooks, scheduled jobs)
---
## Pack Requirements
To include component-http in a `.gtpack`:
1. **Component binary**: Must be bundled inline or referenced via OCI
2. **Secrets**: API tokens must be set up via wizard/setup (`secret:TOKEN_NAME` format)
3. **Two components minimum**: `component-adaptive-card` (for cards) + `component-http` (for API calls)
4. **Flow type**: Must be `messaging` (enables HTTP client in runner host)
---
## Common Patterns
### Pattern 1: Form → API → Confirmation
```
[form_card] → [api_submit] → [confirmation_card]
```
User fills form → HTTP POST sends data → confirmation shows API response.
### Pattern 2: Menu → API Fetch → List Display
```
[menu_card] → [api_fetch_list] → [list_card]
```
User clicks "View Items" → HTTP GET fetches list → card renders list from API data.
### Pattern 3: List → Select → API Detail → Detail Card
```
[list_card] → [api_fetch_detail] → [detail_card]
```
User selects item → HTTP GET fetches detail by ID → card renders full detail.
### Pattern 4: CRUD Cycle
```
[list] → [api_fetch] → [display] → [edit_form] → [api_update] → [success] → [api_fetch] → [list]
```
Full create-read-update-delete loop with API calls at each mutation point.
---
## Reference: Working Flows in Codebase
| Weather API + Card | `weather-demo-scratch/weatherapi-pack/flows/flow_get_weather.ygtc` | component.exec → adaptive-card with `{{node.X.result.Y}}` |
| component-http gtest | `components-public/artifacts/readme-gtests/07_component-http_add_to_flow/artifacts/main.ygtc` | Two HTTP nodes chained, schema v2 `run:` format |
| Cisco Live RFQ | `cisco-live-bundle/flows/main.ygtc` | cards2pack-generated multi-card flow (card-only, no HTTP) |