HTTP Client
Business rules can call external APIs using the fetch() function. This enables webhooks, data enrichment, third-party integrations, and more. The HTTP client is opt-in per application and governed by system-wide security limits.
const response = fetch('https://api.example.com/data', { method: 'POST', headers: { 'Authorization': 'Bearer ' + apiKey, 'Content-Type': 'application/json' }, body: JSON.stringify({ customer_id: record.customer_id, event: 'order_created' })});
if (response.ok) { const data = response.json(); update('orders', record.id, { external_id: data.id });}Request options
Section titled “Request options”| Option | Description |
|---|---|
method | HTTP method (defaults to GET) |
headers | Object of request headers |
body | Request body (string or JSON-serializable value) |
timeout | Per-request timeout in milliseconds (clamped to the system maximum) |
credential | Name of a stored credential to inject (keeps secrets out of script code) |
Response object
Section titled “Response object”| Property | Type | Description |
|---|---|---|
status | number | HTTP status code |
statusText | string | HTTP status text |
ok | boolean | True if the status is 200–299 |
headers | object | Response headers (also headers.get(name)) |
json() | function | Parse the response as JSON |
text() | function | Get the response as text |
Methods
Section titled “Methods”// GETfetch('https://api.example.com/users');
// POST with JSON bodyfetch('https://api.example.com/webhooks', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ event: 'created' })});
// PUT, PATCH, DELETEfetch('https://api.example.com/resource/123', { method: 'DELETE' });Using stored credentials
Section titled “Using stored credentials”Inject a named secret without exposing it to the script:
fetch('https://api.stripe.com/v1/charges', { method: 'POST', credential: 'stripe_key'});Security
Section titled “Security”SSRF protection
Section titled “SSRF protection”By default the HTTP client blocks requests that resolve to private or internal addresses, including:
- Private IP ranges (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16)
- Loopback addresses (127.0.0.1, ::1)
- Link-local and cloud metadata addresses (169.254.0.0/16, including 169.254.169.254)
- Carrier-grade NAT and other reserved ranges
An operator can lift this restriction system-wide with allow_private_ips, but it is off by default.
Domain controls
Section titled “Domain controls”Each application controls which domains its rules may reach. Operators can require an allowlist (block everything not explicitly allowed) and maintain per-application and system-wide blocklists.
# System configuration — applies to every applicationhttp_client: enabled: true allow_private_ips: false max_timeout: 60s max_response_size: 5242880 # 5 MB follow_redirects: true max_redirects: 10 system_blocked_domains: - "*.internal.corp"# Per-application configurationenabled: truerequire_allowlist: trueallowed_domains: - "api.stripe.com" - "hooks.slack.com"blocked_domains: - "example.test"Limits
Section titled “Limits”| Setting | Default |
|---|---|
| Default request timeout | 30 seconds (per-app, clamped to the system max) |
| Maximum request timeout | 60 seconds (system) |
| Maximum response size | 5 MB (system; per-app may be lower) |
| Redirect following | Enabled, up to 10 redirects (configurable) |
When request logging is enabled, outbound HTTP requests are recorded for audit purposes, including the URL, method, status code, and response time.