Skip to content

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[].

typeConfigAction fields usedImportant distinction
httpurl, method (GET/POST/PUT/PATCH/DELETE), headers?, authentication?, bodyTemplate?, timeout? (ms, default 30000), retryConfig?payloadTemplateA generic webhook. The JSON body is built only from templates.
slackwebhookUrl, messageTemplate, channel?, username?, iconEmoji?none (message comes from the integration)One message format per integration.
telegrambotToken, chatId, messageTemplate, parseMode? (HTML/Markdown/MarkdownV2)noneSame as Slack.
postgresconnectionString, ssl? (default true)sqlRuns the resolved SQL string as is.
aws-sesregion, accessKeyId, secretAccessKey, fromEmail, fromName?to, subject, body (HTML), all requiredSends one email.
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.

  • Body templates (bodyTemplate, payloadTemplate) and action fields (sql, to, subject, body): a value that is exactly one {{ … }} expression is evaluated and keeps its type. 7450 stays 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 example https://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-GET request sends {}. Event data is not included automatically. GET sends no body.
  • A 2xx response gives action status: "completed" with result: { status, body }. Any other status gives failed with error: "HTTP <status>". A network error or timeout gives failed with Integration 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 authentication config 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.
  • 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.
  • postgres runs 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.
  1. Point the integration at a request inspector you control.
  2. Ingest a test event and read GET /projects/{projectId}/workflows/{eventId}. Check actions[].payload (resolved template) and actions[].result.status.
  3. Compare with what the receiver logged.

Workflows · Debugging rules · Loyalty program action reference · Integrations and Rules in the API reference