HTTP Transitions – The Complete Guide to External API Integration in Agentic Nets
The HTTP transition is the integration powerhouse in Agentic Nets. While Pass and Map transitions handle internal token routing and transformation, HTTP transitions enable your agentic processes to communicate with the outside world – calling REST APIs, webhooks, microservices, and any HTTP endpoint.
In this comprehensive guide, we’ll explore every capability of HTTP transitions:
- HTTP methods – GET, POST, PUT, DELETE, PATCH
- Template interpolation – dynamic URLs, headers, and request bodies
- Authentication – Basic, Bearer, API Key
- Retry logic – configurable retries with exponential backoff
- Timeout handling – per-request timeout configuration
- Response routing – success/error paths with conditional emit
- Multi-emit patterns – routing responses to multiple destinations
- Token metadata – including source token info in requests
Anatomy of an HTTP Transition Inscription
Every HTTP transition inscription follows this structure:
{
"id": "t-my-api-call",
"kind": "task",
"mode": "SINGLE",
"presets": {
"input": {
"placeId": "requests-queue",
"host": "myModel@localhost:8080",
"arcql": "FROM $ LIMIT 1",
"take": "FIRST",
"consume": true
}
},
"postsets": {
"success": { "placeId": "success-queue", "host": "myModel@localhost:8080" },
"error": { "placeId": "error-queue", "host": "myModel@localhost:8080" }
},
"action": {
"type": "http",
"method": "POST",
"url": "https://api.example.com/orders/${input.data.orderId}",
"headers": {
"Content-Type": "application/json",
"X-Request-Id": "${requestId}"
},
"body": {
"orderId": "${input.data.orderId}",
"amount": "${input.data.amount}"
},
"timeoutMs": 30000
},
"emit": [
{ "to": "success", "from": "@response.json", "when": "success" },
{ "to": "error", "from": "@input.data", "when": "error" }
]
}
Key elements:
kind: "task"– identifies this as an HTTP action transitionaction.type: "http"– specifies the HTTP action handleraction.method– HTTP method (GET, POST, PUT, DELETE, PATCH)action.url– target URL with template interpolationemit.from– what to emit:@response.json,@response.meta, or@input.data
HTTP Methods
HTTP transitions support all standard HTTP methods:
GET – Retrieve Data
{
"action": {
"type": "http",
"method": "GET",
"url": "https://api.example.com/orders/${input.data.orderId}"
}
}
POST – Create Resources
{
"action": {
"type": "http",
"method": "POST",
"url": "https://api.example.com/orders",
"headers": { "Content-Type": "application/json" },
"body": {
"customerId": "${input.data.customerId}",
"items": "${input.data.items}",
"total": "${input.data.total}"
}
}
}
PUT – Update Resources
{
"action": {
"type": "http",
"method": "PUT",
"url": "https://api.example.com/orders/${input.data.orderId}",
"headers": { "Content-Type": "application/json" },
"body": {
"status": "shipped",
"trackingNumber": "${input.data.trackingNumber}"
}
}
}
DELETE – Remove Resources
{
"action": {
"type": "http",
"method": "DELETE",
"url": "https://api.example.com/orders/${input.data.orderId}"
}
}
Template Interpolation
HTTP transitions use the same ${...} template syntax as Map transitions, enabling dynamic request construction from token data.
URL Path Interpolation
Embed token data directly in URL paths:
// Input token
{ "resourceId": "resource-xyz", "action": "status" }
// URL template
"url": "https://api.example.com/resources/${input.data.resourceId}/${input.data.action}"
// Result
"https://api.example.com/resources/resource-xyz/status"
Query Parameter Interpolation
Build dynamic query strings:
// Input token
{ "orderId": "ORD-12345", "customerId": "CUST-999" }
// URL template with query params
"url": "https://api.example.com/search?orderId=${input.data.orderId}&customerId=${input.data.customerId}"
// Result
"https://api.example.com/search?orderId=ORD-12345&customerId=CUST-999"
Header Interpolation
Include token data in request headers:
// Input token
{ "traceId": "trace-abc-123", "clientVersion": "2.5.0" }
// Headers with interpolation
"headers": {
"Content-Type": "application/json",
"X-Trace-Id": "${input.data.traceId}",
"X-Client-Version": "${input.data.clientVersion}"
}
Request Body Interpolation
Build complex JSON request bodies from token data:
// Input token
{ "customerId": "CUST-001", "total": "599.99", "priority": "high" }
// Body template with nested structure
"body": {
"order": {
"customerId": "${input.data.customerId}",
"total": "${input.data.total}"
},
"shipping": {
"method": "express",
"priority": "${input.data.priority}"
},
"metadata": {
"timestamp": "${now}",
"requestId": "${requestId}"
}
}
Token Metadata in Requests
Include source token metadata for traceability:
// Headers with token metadata
"headers": {
"X-Token-Id": "${input._meta.id}",
"X-Token-Name": "${input._meta.name}"
},
// Body with source tracking
"body": {
"payload": "${input.data.payload}",
"sourceTokenId": "${input._meta.id}",
"sourceTokenName": "${input._meta.name}"
}
Available metadata:
${input._meta.id}– Token UUID${input._meta.name}– Token name${input._meta.parentId}– Parent place UUID
Authentication
HTTP transitions support multiple authentication methods:
Basic Authentication
Username and password encoded as Base64:
{
"action": {
"type": "http",
"method": "GET",
"url": "https://api.example.com/protected",
"auth": {
"type": "basic",
"username": "testuser",
"password": "testpass"
}
}
}
This automatically adds the Authorization: Basic dGVzdHVzZXI6dGVzdHBhc3M= header.
Bearer Token Authentication
For OAuth2 or JWT-based authentication:
{
"action": {
"type": "http",
"method": "POST",
"url": "https://api.example.com/data",
"auth": {
"type": "bearer",
"token": "eyJhbGciOiJIUzI1NiIs..."
}
}
}
This adds the Authorization: Bearer eyJhbGciOiJIUzI1NiIs... header.
API Key Authentication
For services that use API keys in headers:
{
"action": {
"type": "http",
"method": "GET",
"url": "https://api.example.com/data",
"auth": {
"type": "api_key",
"headerName": "X-Api-Key",
"apiKey": "secret-api-key-xyz"
}
}
}
This adds the custom header X-Api-Key: secret-api-key-xyz.
Retry Logic and Error Handling
HTTP transitions include robust retry capabilities for handling transient failures:
{
"action": {
"type": "http",
"method": "POST",
"url": "https://api.example.com/orders",
"retry": {
"maxAttempts": 3,
"backoffMs": 1000,
"backoffMultiplier": 2.0,
"retryOn": ["5xx", "429", "io"]
}
}
}
Retry configuration options:
| Option | Description | Default |
|---|---|---|
maxAttempts |
Maximum number of retry attempts | 3 |
backoffMs |
Initial backoff delay in milliseconds | 1000 |
backoffMultiplier |
Multiplier for exponential backoff | 2.0 |
retryOn |
Conditions that trigger retry | [“5xx”, “429”] |
Retry conditions:
"5xx"– Retry on server errors (500-599)"429"– Retry on rate limiting"io"– Retry on network I/O errors
Error Handling Behavior
Important: When an HTTP call fails (4xx, 5xx, timeout, or exhausted retries), the input token is preserved – it is NOT consumed. This enables:
- Manual retry by re-firing the transition
- Dead letter queue patterns (move failed tokens to error place)
- Automatic retry when the transition fires again
// After HTTP error:
// - Input token remains in input place (not consumed)
// - Error emit rules are NOT processed
// - Token available for re-processing
Timeout Configuration
Configure per-request timeouts to handle slow endpoints:
{
"action": {
"type": "http",
"method": "GET",
"url": "https://api.example.com/slow-endpoint",
"timeoutMs": 30000 // 30 seconds
}
}
If the request exceeds the timeout, it’s treated as an error and the input token is preserved for retry.
Response Routing
Route HTTP responses to different postsets based on success or failure:
Success/Error Routing
{
"postsets": {
"success": { "placeId": "success-queue", "host": "myModel@localhost:8080" },
"error": { "placeId": "error-queue", "host": "myModel@localhost:8080" }
},
"emit": [
{ "to": "success", "from": "@response.json", "when": "success" },
{ "to": "error", "from": "@input.data", "when": "error" }
]
}
Emit conditions:
"when": "success"– Emit on HTTP 2xx responses"when": "error"– Emit on HTTP errors (see note below)
Note: In the current implementation, error emit rules are only processed for responses that reach the response processing stage. HTTP errors (4xx, 5xx, timeouts) that throw exceptions preserve the input token without processing emit rules.
Multi-Emit on Success
Send successful responses to multiple destinations:
{
"postsets": {
"processed": { "placeId": "processed-queue", "host": "myModel@localhost:8080" },
"audit": { "placeId": "audit-log", "host": "myModel@localhost:8080" }
},
"emit": [
{ "to": "processed", "from": "@response.json", "when": "success" },
{ "to": "audit", "from": "@response.meta", "when": "success" }
]
}
Emit Payloads
HTTP transitions offer multiple payload options for emit rules:
@response.json – Full Response Body
Emit the entire JSON response from the HTTP call:
// HTTP response
{
"orderId": "ORD-123",
"status": "created",
"createdAt": "2024-01-15T10:30:00Z"
}
// Emit rule
{ "to": "output", "from": "@response.json", "when": "success" }
// Token created in output place
{
"orderId": "ORD-123",
"status": "created",
"createdAt": "2024-01-15T10:30:00Z",
"_transitionId": "t-my-api",
"_status": "success",
"_emittedAt": "2024-01-15T10:30:01Z"
}
@response.meta – Response Metadata
Emit HTTP metadata instead of the body:
// Emit rule
{ "to": "metrics", "from": "@response.meta", "when": "success" }
// Token created with HTTP metadata
{
"status": "200",
"url": "https://api.example.com/orders",
"durationMs": "245",
"_transitionId": "t-my-api",
"_status": "success",
"_emittedAt": "2024-01-15T10:30:01Z"
}
Use case: Performance monitoring, SLA tracking, audit logging.
@input.data – Original Token Data
Emit the original input token (useful for error paths):
// Input token
{ "orderId": "ORD-123", "customerId": "CUST-456" }
// Emit rule for error path
{ "to": "retry-queue", "from": "@input.data", "when": "error" }
// Original token preserved in retry queue
{ "orderId": "ORD-123", "customerId": "CUST-456" }
Automatic Features
Correlation ID Injection
Every HTTP request automatically includes an X-Correlation-Id header for distributed tracing:
// Automatic header added to every request
"X-Correlation-Id": "8a769e7d-ea8f-4286-9a82-bc9aeba4dabe"
This correlation ID can be used to trace requests across your entire system, from AgenticOS through downstream services.
Built-in Variables
In addition to token data, these built-in variables are available:
${requestId}– Unique request UUID (same as correlation ID)${now}– Current timestamp in ISO 8601 format
Pattern 1: Simple API Call with Response Routing
Basic pattern for calling an API and routing the response:
{
"id": "t-fetch-order",
"kind": "task",
"mode": "SINGLE",
"presets": {
"input": {
"placeId": "order-requests",
"host": "orders@localhost:8080",
"arcql": "FROM $ LIMIT 1",
"take": "FIRST",
"consume": true
}
},
"postsets": {
"output": { "placeId": "order-data", "host": "orders@localhost:8080" }
},
"action": {
"type": "http",
"method": "GET",
"url": "https://api.example.com/orders/${input.data.orderId}",
"timeoutMs": 30000
},
"emit": [
{ "to": "output", "from": "@response.json", "when": "success" }
]
}
Pattern 2: Authenticated POST with Retry
Create resources with authentication and retry logic:
{
"id": "t-create-order",
"kind": "task",
"mode": "SINGLE",
"presets": {
"input": {
"placeId": "new-orders",
"host": "orders@localhost:8080",
"arcql": "FROM $ LIMIT 1",
"take": "FIRST",
"consume": true
}
},
"postsets": {
"created": { "placeId": "created-orders", "host": "orders@localhost:8080" },
"failed": { "placeId": "failed-orders", "host": "orders@localhost:8080" }
},
"action": {
"type": "http",
"method": "POST",
"url": "https://api.example.com/orders",
"headers": { "Content-Type": "application/json" },
"body": {
"customerId": "${input.data.customerId}",
"items": "${input.data.items}",
"total": "${input.data.total}"
},
"auth": {
"type": "bearer",
"token": "your-api-token"
},
"timeoutMs": 30000,
"retry": {
"maxAttempts": 3,
"backoffMs": 1000,
"backoffMultiplier": 2.0,
"retryOn": ["5xx", "429"]
}
},
"emit": [
{ "to": "created", "from": "@response.json", "when": "success" }
]
}
Pattern 3: Multi-Emit for Audit Logging
Send response to processing queue AND audit log:
{
"id": "t-audited-api-call",
"kind": "task",
"mode": "SINGLE",
"presets": {
"input": {
"placeId": "requests",
"host": "myModel@localhost:8080",
"arcql": "FROM $ LIMIT 1",
"take": "FIRST",
"consume": true
}
},
"postsets": {
"json-output": { "placeId": "responses", "host": "myModel@localhost:8080" },
"meta-output": { "placeId": "metrics", "host": "myModel@localhost:8080" }
},
"action": {
"type": "http",
"method": "GET",
"url": "https://api.example.com/data?id=${input.data.id}",
"timeoutMs": 30000
},
"emit": [
{ "to": "json-output", "from": "@response.json", "when": "success" },
{ "to": "meta-output", "from": "@response.meta", "when": "success" }
]
}
This creates two tokens on success:
responses– Contains the full JSON response bodymetrics– Contains HTTP metadata (status, duration, URL)
Pattern 4: Webhook Integration
Post events to external webhooks:
{
"id": "t-webhook-notify",
"kind": "task",
"mode": "SINGLE",
"presets": {
"input": {
"placeId": "events",
"host": "notifications@localhost:8080",
"arcql": "FROM $ LIMIT 1",
"take": "FIRST",
"consume": true
}
},
"postsets": {
"delivered": { "placeId": "delivered", "host": "notifications@localhost:8080" }
},
"action": {
"type": "http",
"method": "POST",
"url": "https://webhook.example.com/events",
"headers": {
"Content-Type": "application/json",
"X-Webhook-Secret": "shared-secret-key"
},
"body": {
"event": "${input.data.eventType}",
"payload": "${input.data.payload}",
"timestamp": "${now}",
"correlationId": "${requestId}"
},
"timeoutMs": 10000
},
"emit": [
{ "to": "delivered", "from": "@response.meta", "when": "success" }
]
}
Best Practices
1. Always Set Timeouts
Never rely on default timeouts. Set explicit timeoutMs values appropriate for each endpoint:
"timeoutMs": 30000 // 30 seconds for most APIs
"timeoutMs": 60000 // 60 seconds for slow operations
"timeoutMs": 5000 // 5 seconds for health checks
2. Configure Appropriate Retry Strategies
Match retry configuration to the API characteristics:
// For idempotent operations (GET, PUT, DELETE)
"retry": { "maxAttempts": 3, "retryOn": ["5xx", "429", "io"] }
// For non-idempotent operations (POST) - be cautious
"retry": { "maxAttempts": 1 } // Or use idempotency keys
3. Include Traceability Headers
Add token metadata to requests for debugging:
"headers": {
"X-Token-Id": "${input._meta.id}",
"X-Token-Name": "${input._meta.name}",
"X-Source-Transition": "t-my-transition"
}
4. Use @response.meta for Monitoring
Emit response metadata to a metrics place for SLA monitoring:
"emit": [
{ "to": "response-data", "from": "@response.json", "when": "success" },
{ "to": "api-metrics", "from": "@response.meta", "when": "success" }
]
5. Secure Credential Management
Never hardcode credentials in inscriptions. Use environment variables or secret management:
// Token-based credentials (recommended)
{ "apiKey": "${input.data.apiKey}" }
// Or use service-level configuration
// Configure credentials in agentic-net-master application.properties
HTTP vs Map vs Pass: When to Use Each
| Use Case | Pass | Map | HTTP |
|---|---|---|---|
| Simple token routing | Yes | ||
| Filter/gate based on data | Yes | ||
| Transform token structure | Yes | ||
| Add computed fields | Yes | ||
| Call external REST API | Yes | ||
| Send webhooks | Yes | ||
| Integrate microservices | Yes | ||
| Fetch external data | Yes |
Complete Working Example
Here’s a complete HTTP transition that fetches order details, adds authentication, handles errors, and routes responses:
{
"id": "t-order-enrichment",
"kind": "task",
"mode": "SINGLE",
"presets": {
"input": {
"placeId": "pending-orders",
"host": "orders@localhost:8080",
"arcql": "FROM $ WHERE $.status==\"pending\" LIMIT 1",
"take": "FIRST",
"consume": true
}
},
"postsets": {
"enriched": { "placeId": "enriched-orders", "host": "orders@localhost:8080" },
"metrics": { "placeId": "api-metrics", "host": "orders@localhost:8080" }
},
"action": {
"type": "http",
"method": "GET",
"url": "https://api.example.com/orders/${input.data.orderId}/details",
"headers": {
"Accept": "application/json",
"X-Request-Id": "${requestId}",
"X-Source-Token": "${input._meta.id}"
},
"auth": {
"type": "api_key",
"headerName": "X-Api-Key",
"apiKey": "your-api-key"
},
"timeoutMs": 30000,
"retry": {
"maxAttempts": 3,
"backoffMs": 1000,
"backoffMultiplier": 2.0,
"retryOn": ["5xx", "429"]
}
},
"emit": [
{ "to": "enriched", "from": "@response.json", "when": "success" },
{ "to": "metrics", "from": "@response.meta", "when": "success" }
]
}
This transition:
- Reads pending orders from
pending-ordersplace - Calls external API with order ID from token
- Includes API key authentication
- Adds correlation and source tracking headers
- Retries up to 3 times on server errors
- On success: sends response body to
enriched-orders - On success: sends metadata to
api-metricsfor monitoring - On error: preserves input token for retry
Summary
HTTP transitions are the integration backbone of Agentic Nets, enabling your agentic processes to communicate with any HTTP endpoint. With template interpolation, multiple authentication methods, retry logic, and flexible response routing, you can build robust integrations entirely through declarative JSON inscriptions.
Key takeaways:
- Template interpolation everywhere – URLs, headers, and bodies all support
${...}expressions - Multiple auth methods – Basic, Bearer, and API Key authentication built-in
- Robust error handling – Configurable retries with exponential backoff
- Token preservation on error – Failed requests don’t consume input tokens
- Flexible emit payloads – Choose between
@response.json,@response.meta, or@input.data - Automatic correlation – Every request includes
X-Correlation-Idfor tracing - Token metadata access – Include source token info in requests for traceability
Combined with Pass transitions for routing, Map transitions for transformation, and HTTP transitions for external integration, you have a complete toolkit for building sophisticated, maintainable agent orchestration in Agentic Nets.