Pipelines
Automate your workflows with event-driven pipelines — get notified, trigger actions, and save time.
What Is a Pipeline?
A Pipeline is an automation rule that listens for specific events (triggers) and executes actions in response. For example, you can set up a pipeline that sends a Telegram message every time a new payment is received or a new application is submitted. Pipelines are managed in CRM → Pipeline.
How Pipelines Work
- Trigger — the event that starts the pipeline (e.g., "payment created").
- Conditions — optional filters that must all match for the pipeline to continue.
- Payload mapping — maps data from the trigger event to the action input fields.
- Actions — what happens when the trigger fires (e.g., send a Telegram message, email, or webhook).
Available Triggers
Triggers are events that start a pipeline. Currently available:
- Payment Created — fires when a new payment is submitted (status: pending).
- Payment Accepted — fires when a payment is verified and accepted.
- Payment Rejected — fires when a payment is rejected.
- Application Created — fires when a user submits a rental application.
- User Created — fires when a new user registers (admin only).
- Media Published — fires when a media file is published for the first time.
- Incoming Webhook Received — fires when an incoming webhook endpoint receives a request from an external service.
- Review Submitted — fires when a user submits a new review for a unit.
- Review Verified — fires when a moderator verifies and approves a review.
- Review Rejected — fires when a moderator rejects a review.
Trigger Payload Fields
When a trigger fires, it produces a payload with data you can use in your actions. Each trigger type provides a different set of fields.
Payment Trigger Payload
Triggers: Payment Created, Payment Accepted, Payment Rejected
| Field Path | Description |
|---|---|
| [payment][id] | Payment ID |
| [payment][status] | Current status (pending, accepted, rejected) |
| [payment][value] | Amount (raw number) |
| [payment][valueFormatted] | Formatted amount (e.g., "IDR 500,000.00") |
| [payment][currency] | Currency code (IDR) |
| [user][id] | User ID |
| [user][email] | User email |
| [user][firstName] | First name |
| [user][lastName] | Last name |
| [user][fullName] | Full name |
| [user][active] | Whether the account is active |
| [user][telegramChatId] | User's Telegram chat ID |
| [user][telegramUsername] | User's Telegram username |
Application Trigger Payload
Trigger: Application Created
| Field Path | Description |
|---|---|
| [application][id] | Application ID |
| [application][status] | Application status (pending) |
| [application][nights] | Number of nights requested |
| [application][budget] | Budget amount |
| [application][displayName] | Applicant full name |
| [user][id] | User ID |
| [user][email] | User email |
| [user][firstName] | First name |
| [user][lastName] | Last name |
| [user][fullName] | Full name |
| [user][telegramChatId] | User's Telegram chat ID |
| [user][telegramUsername] | User's Telegram username |
| [unit][id] | Unit ID |
| [unit][title] | Unit name |
| [complex][id] | Complex ID |
| [complex][title] | Complex name |
User Trigger Payload
Trigger: User Created
| Field Path | Description |
|---|---|
| [user][id] | User ID |
| [user][email] | User email |
| [user][firstName] | First name |
| [user][lastName] | Last name |
| [user][fullName] | Full name |
| [user][active] | Whether the account is active |
| [user][telegramChatId] | User's Telegram chat ID |
| [user][telegramUsername] | User's Telegram username |
Media Trigger Payload
Trigger: Media Published
| Field Path | Description |
|---|---|
| [media][id] | Media ID |
| [media][type] | Media type (image, video) |
| [media][displayName] | Display name or filename |
| [media][entityType] | Parent entity type (vendor-media, unit-media, etc.) |
| [media][filename] | Stored filename (for building URLs) |
| [entity][id] | Parent entity ID |
| [entity][title] | Parent entity name |
Incoming Webhook Trigger Payload
Trigger: Incoming Webhook Received
| Field Path | Description |
|---|---|
| [webhook][id] | Incoming webhook ID |
| [webhook][name] | Webhook name |
| [webhook][token] | Webhook token |
| [payload] | Full JSON payload sent by the external service |
| [meta][sourceIp] | IP address of the sender |
| [meta][receivedAt] | Timestamp when the request was received |
Review Trigger Payload
Triggers: Review Submitted, Review Verified, Review Rejected
| Field Path | Description |
|---|---|
| [review][id] | Review ID |
| [review][rating] | Star rating (1-5) |
| [review][title] | Review title |
| [review][body] | Review text body |
| [review][status] | Review status (pending, verified, rejected) |
| [unit][id] | Unit ID |
| [unit][name] | Unit name |
| [user][id] | User ID |
| [user][email] | User email |
| [user][firstName] | First name |
| [user][lastName] | Last name |
| [user][fullName] | Full name |
| [user][telegramChatId] | User's Telegram chat ID |
| [user][telegramUsername] | User's Telegram username |
Message Templates
Message templates use Twig syntax for dynamic variables. Pre-built templates are loaded automatically when you select a trigger type. You can customize them or write your own from scratch.
Payment Created
1<b>💳 Payment created</b>
2
3<b>👤 Customer:</b> {{ customer_name }}
4<b>📧 Email:</b> {{ customer_email }}
5
6<b>🆔 Payment ID:</b> {{ payment_id }}
7<b>💰 Amount:</b>
8{{ payment_amount|number_format(2, '.', ' ') }} {{ payment_currency }}
9<b>📌 Status:</b> {{ payment_status }}
10
11<i>Hunico · Payments</i>
Application Created
1<b>📝 New application submitted</b>
2
3<b>👤 Applicant:</b> {{ user_name }}
4<b>📧 Email:</b> {{ user_email }}
5
6<b>🏠 Unit:</b> {{ unit_title }}
7<b>🏢 Complex:</b> {{ complex_title }}
8
9<b>🆔 Application ID:</b> {{ application_id }}
10<b>📌 Status:</b> {{ application_status }}
11
12<i>Hunico · Applications</i>
Media Published
1<b>🖼 New media published</b>
2
3<b>📂 Type:</b> {{ media_type }}
4<b>🏷 Title:</b> {{ entity_title }}
5
6<b>🆔 Media ID:</b> {{ media_id }}
7
8<i>Hunico · Media</i>
Payload Mapping
Mapping connects trigger payload fields to action input fields. When you configure an action (e.g., Telegram message), the system:
- Extracts template variables from your message template. Message templates use Twig syntax. For example, if your message contains
{{ payment.valueFormatted }}, the system creates a mapping field for[message][valueFormatted]. - Shows a dropdown for each extracted variable. The dropdown label shows the action path (e.g.,
[message][payment]) and lists all available trigger fields as options. - You select which trigger field should fill each template variable. For example, map
[message][valueFormatted]to[payment][valueFormatted].
When the pipeline runs, the system replaces each template variable with the actual value from the trigger payload.
Creating a Pipeline
Navigate to CRM → Pipeline and click the create button.
- Configure the subscription — select which event triggers this pipeline.
- Add one or more actions (up to 20) — choose the action type and configure its parameters.
- Write your message template using Twig variables (e.g.,
{{ payment.valueFormatted }}). - Map each template variable to a trigger payload field using the dropdown selectors.
- Save and activate the pipeline.
Action Types
Each pipeline action defines what happens when the trigger fires. All three action types are available to any user who has access to at least one trigger:
| Action Type | Description |
|---|---|
| Telegram Message | Send a message to a Telegram chat or group |
| Send an email notification with customizable subject and body | |
| Webhook | Send an HTTP request to an external service |
| WhatsApp Message | Send a WhatsApp message via Meta Cloud API (admin only) |
| Invoice PDF | Generate and attach a branded invoice PDF |
| Facebook Post | Publish a post with photos to a Facebook Page (admin only) |
Trigger Access by Role
Each trigger type is available to specific roles. You can only create pipelines with triggers you have access to:
| Trigger | Available For |
|---|---|
| Payment Created / Accepted / Rejected | Admin, Accountant |
| Application Created | Admin, Vendor |
| User Created | Admin |
| Media Published | Admin, Vendor |
| Incoming Webhook Received | Admin, Vendor |
| Review Submitted / Verified | Admin, Vendor |
| Review Rejected | Admin |
Telegram Message Action
Sends a message to a specified Telegram chat. Configuration fields:
- Message template — the message text with Twig variables for dynamic data.
- Telegram Chat ID — the numeric ID of the chat where messages will be sent.
- Mapping fields — one dropdown per template variable, connecting it to trigger data.
Email Action
Sends an email notification when the pipeline triggers. Configuration fields:
- Email body template — HTML content with Twig variables. A default template is loaded automatically.
- Email subject — the subject line. Supports Twig variables, e.g.
Payment {{ payment_id }} received - Recipient email — the email address that receives the notification.
- Mapping fields — one dropdown per template variable, connecting it to trigger data.
Tip: The email body uses HTML formatting. You can use Twig filters like {{ amount|number_format(2, '.', ' ') }} to format numbers in your email templates.
Webhook Action
Sends an HTTP request to an external URL when the pipeline triggers. Useful for integrating with third-party services, CRMs, or custom APIs. Configuration fields:
- Request body template — JSON payload with Twig variables. Must produce valid JSON.
- Webhook URL — the HTTPS endpoint that receives the request (e.g.,
https://example.com/webhook). - HTTP Method — POST or PUT.
- Request headers (optional) — custom HTTP headers as a JSON object (e.g.,
{"Authorization": "Bearer token"}). - Mapping fields — one dropdown per template variable, connecting it to trigger data.
Important: External services must respond within 10 seconds, otherwise the request will time out.
How to Find Your Telegram Chat ID
The Telegram Chat ID is a numeric identifier for your chat, group, or channel. Here is how to get it:
- Open Telegram and start a conversation with @hunico_bot.
- Send the command
/chatid— the bot will reply with your personal chat ID. - For group chats: add @hunico_bot to the group, then send
/chatidin the group — the bot will reply with the group's chat ID. - Copy the numeric ID and paste it into the Telegram Chat ID field in your pipeline action.
Important: The bot @hunico_bot must remain a member of the chat for messages to be delivered. If the bot is removed from the group, pipeline messages to that chat will fail.
Setting Up Facebook Page Posting
The Facebook Post action allows you to publish property listings with photos directly to your Facebook Page. This requires a Facebook Page and a long-lived Page Access Token.
Step 1: Get Your Facebook Page ID
- Open your Facebook Page.
- Go to Page Settings → Page Transparency.
- Your Page ID is a numeric value displayed in the transparency section (e.g., 123456789).
- Copy this ID and paste it into the Facebook Page ID field in your pipeline action.
Step 2: Generate a Page Access Token
- Go to Facebook Graph API Explorer.
- Select your App (or create one at developers.facebook.com/apps).
- Click Generate Access Token and grant these permissions:
pages_manage_posts,pages_read_engagement. - Select your Page from the dropdown to get a Page Access Token (not a User token).
- To make the token long-lived (60 days), use the Access Token Debugger and click Extend Access Token.
- Copy the token and paste it into the Facebook Access Token field in your pipeline action.
Step 3: Configure the Pipeline Action
- In your pipeline, add a new action and select Facebook post.
- Fill in the Page ID and Access Token.
- Write a message template using Twig syntax for dynamic variables (e.g.,
{{ unit.title }}). - Optionally, add media slots to attach property photos. Drag and drop to reorder.
- Map the payload fields from the trigger to your template variables.
- Activate the pipeline subscription.
Rate Limits
To prevent spam, publishing is rate-limited per property per vendor:
- Pro vendors — 1 post per property per week
- Free vendors — 1 post per property per month
- Admins — no limits
Important: Page Access Tokens expire after 60 days. Set a reminder to regenerate the token before it expires, or your pipeline posts will fail.
Editing Active Pipelines
When a pipeline is active, its configuration fields are locked to prevent accidental changes while the pipeline is processing events. You can still view all settings, but to make changes:
- Open the pipeline and toggle the Active switch to off.
- Edit the trigger, actions, message template, or mappings as needed.
- When ready, toggle Active back on to resume processing.
Tip: While the pipeline is disabled, no events will be processed. Re-activate as soon as your changes are complete to avoid missing events.
Conditional Execution
Conditions let you filter when a pipeline runs. You can add one or more conditions that must all be true (AND logic) for the pipeline actions to execute. If conditions don't match, the trigger is skipped and a log entry is created with "Skipped" status.
Each condition has three parts:
- Field — the trigger payload field to check (e.g.,
[payment][status]). - Operator — the comparison type.
- Value — the expected value to compare against.
Available Operators
| Operator | Description |
|---|---|
| equals | Field value matches exactly |
| not_equals | Field value does not match |
| contains | Field value contains the specified text |
| greater_than | Field value is greater than (numeric comparison) |
| less_than | Field value is less than (numeric comparison) |
Example: To only trigger on accepted payments, add a condition with field [payment][status], operator equals, and value accepted.
Automatic Retries
If a pipeline action fails (e.g., Telegram API error, webhook timeout), the system can automatically retry it. You can configure the maximum number of retry attempts (0 to 5) per pipeline.
- Retry count — set the Max Retries field on the pipeline (default: 0, meaning no retries).
- Increasing delays — each retry waits longer than the previous one to avoid overloading external services. The delay doubles with each attempt (approximately 10s, 20s, 40s, 80s, 160s).
- Attempt tracking — each retry attempt is logged in the execution history with its attempt number, status, and any error details.
Tip: Set retries to 2-3 for actions that depend on external services (Telegram, webhooks). This handles temporary outages without manual intervention.
Testing Pipelines
Each pipeline has a test trigger feature that lets you fire the pipeline with a sample payload to verify it works correctly before going live. The test input area shows a JSON payload that simulates the real event data. If an action fails, the error payload is captured and displayed on the pipeline detail page for easy debugging.
Execution Logs
Every pipeline execution is tracked in the Execution Logs section at the bottom of the pipeline view page. Each log entry shows:
- Status — Completed, Error, or Skipped (when conditions didn't match).
- Attempt number — which retry attempt this was (1 for the first run).
- Error payload — if the action failed, a read-only code viewer shows the full error details.
- Test input — the payload data that was sent to the action, shown as read-only code.
Template fields and payload data are displayed using a syntax-highlighted code viewer for easier reading. Editable template fields (message body, request body) use a code editor with Twig syntax support.
Deleting Pipelines
You can delete a pipeline from the pipeline view page using the delete action. Deletion follows the standard 14-day grace period — the pipeline is scheduled for removal and can be restored within that period. All associated actions, subscriptions, and execution logs are removed together with the pipeline.