HTTP Integrations
An integration is a saved connection on the project (URL and credentials). A rule’s integration action points at it with integrationId and supplies the per-rule payload. The call runs during event processing, and its outcome is recorded in the workflow’s actions[].
Choose a type
Section titled “Choose a type”type | Config | Action fields used | Important distinction |
|---|---|---|---|
http | url, method (GET/POST/PUT/PATCH/DELETE), headers?, authentication?, bodyTemplate?, timeout? (ms, default 30000), retryConfig? | payloadTemplate | A generic webhook. The JSON body is built only from templates. |
slack | webhookUrl, messageTemplate, channel?, username?, iconEmoji? | none (message comes from the integration) | One message format per integration. |
telegram | botToken, chatId, messageTemplate, parseMode? (HTML/Markdown/MarkdownV2) | none | Same as Slack. |
postgres | connectionString, ssl? (default true) | sql | Runs the resolved SQL string as is. |
aws-ses | region, accessKeyId, secretAccessKey, fromEmail, fromName? | to, subject, body (HTML), all required | Sends one email. |
HTTP webhook example
Section titled “HTTP webhook example”POST /projects/{projectId}/integrations{ "name": "CRM points webhook", "type": "http", "config": { "url": "https://crm.example.com/hooks/storelayer", "method": "POST", "authentication": { "type": "bearer", "token": "crm_secret_…" }, "headers": { "X-Source": "storelayer" }, "bodyTemplate": { "source": "storelayer" }, "timeout": 10000 }}Rule action:
{ "type": "integration", "config": { "integrationId": "<integration id>", "payloadTemplate": { "customerId": "{{ $('event').userId }}", "orderId": "{{ $('event').payload.orderId }}", "amountCents": "{{ $('event').payload.amount }}", "kind": "purchase_reward" } }}The request sent is POST with Content-Type: application/json and Authorization: Bearer crm_secret_…, and its body is bodyTemplate merged with payloadTemplate (action keys win):
{"source":"storelayer","customerId":"cust_8421","orderId":"ord_1001","amountCents":7450,"kind":"purchase_reward"}.
Authentication options: { "type": "bearer", "token" }, { "type": "basic", "username", "password" }, { "type": "api-key", "key", "value", "in": "header" | "query" }, or none.
Templating rules
Section titled “Templating rules”- Body templates (
bodyTemplate,payloadTemplate) and action fields (sql,to,subject,body): a value that is exactly one{{ … }}expression is evaluated and keeps its type.7450stays a number. A value like"Order {{ $('event').payload.orderId }}"is sent literally. Build strings inside the expression instead:"{{ 'Order ' + $('event').payload.orderId }}". url,messageTemplate(Slack/Telegram): every{{ … }}occurrence is interpolated into the string, for examplehttps://crm.example.com/customers/{{ $('event').userId }}/points.- Expressions can read
$('event')and any resource the rule declares. See Conditions and resources. - With no template at all, a non-
GETrequest sends{}. Event data is not included automatically.GETsends no body.
Outcome and failure
Section titled “Outcome and failure”- A
2xxresponse gives actionstatus: "completed"withresult: { status, body }. Any other status givesfailedwitherror: "HTTP <status>". A network error or timeout givesfailedwithIntegration call failed: …. An integration failure does not fail the workflow or stop the rule’s other actions. - A missing or inactive integration gives a failed action:
Integration '<id>' not found/… is inactive. - Do not rely on
retryConfig. In current behavior the first response or error is final. Make your receiver tolerant, and repair missed calls from the workflow records (GET /projects/{projectId}/workflows?status=…). - Storelayer does not add a signature header. Authenticate requests with the
authenticationconfig or a secret header, and have the receiver check it. - Receivers should deduplicate on a business key you template in (such as
orderId). The same business event can reach you twice if it was ingested twice.
Security
Section titled “Security”- Integration configs, including tokens, passwords and connection strings, are returned in full by
GET /projects/{projectId}/integrations. Anyone with project API access can read them, so use narrowly scoped credentials. postgresruns whatever SQL the template produces, and values are inserted as raw text. Never template untrusted payload strings into SQL. Prefer a dedicated, least-privilege database user.- Keep secrets in the integration config, never in event payloads.
Verify
Section titled “Verify”- Point the integration at a request inspector you control.
- Ingest a test event and read
GET /projects/{projectId}/workflows/{eventId}. Checkactions[].payload(resolved template) andactions[].result.status. - Compare with what the receiver logged.
See also
Section titled “See also”Workflows · Debugging rules · Loyalty program action reference · Integrations and Rules in the API reference