Connecting Integrations — Step‑by‑Step Guides
These guides walk you, end to end, through connecting ACE to the most common external services and hardware. Every ACE command shown here is a real command you can copy into the ACE console (CLI) — see the Webhook Commands and Sensor Commands reference for the full syntax.
Two halves to every integration
Each outbound service needs work in two places:
- On the service — create the app / bot / API key and copy a credential.
- In ACE — run one
webhook integration setup …command with that credential, then send a test message.
The webhook integration setup <service> <name> … presets create a normal
webhook that is already pointed at the correct 2026 endpoint with the right
headers and body template. You can inspect any preset first with
webhook integration info <service>.
Slack
Slack outbound messages use Incoming Webhooks.
On Slack
- Go to https://api.slack.com/apps and click Create New App → From scratch.
- Give it a name, pick your workspace, click Create App.
- In the left sidebar open Incoming Webhooks and toggle Activate Incoming Webhooks on.
- Click Add New Webhook to Workspace, choose the channel to post to, and Allow.
- Copy the generated Webhook URL — it looks like
https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX.
In ACE
webhook integration setup slack mySlack WEBHOOK_URL=https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXX
webhook post mySlack TEXT=Hello from ACE!
That's it — the message appears in the channel you selected. The channel is
baked into the webhook URL, so you only ever send TEXT=….
Telegram
Telegram outbound messages use the Bot API (sendMessage).
On Telegram
- In the Telegram app, open a chat with @BotFather.
- Send
/newbot, then follow the prompts to name your bot. BotFather replies with a bot token like123456789:ABC-DEF1234ghIkl-zyx57W2v1u123ew11. - Find the chat ID you want to message:
- For a private chat: message your new bot once (say "hi"), then open
https://api.telegram.org/bot<YOUR_TOKEN>/getUpdatesin a browser and read the"chat":{"id":…}value, or message @userinfobot to get your numeric ID. - For a group: add the bot to the group, send a message, then use
getUpdatesthe same way (group IDs are negative, e.g.-1001234567890).
- For a private chat: message your new bot once (say "hi"), then open
The bot must be able to reach you
Telegram bots cannot start a conversation. You must message the bot (or add
it to the group) first, otherwise sendMessage returns
"chat not found" / "bot can't initiate conversation".
In ACE
webhook integration setup telegram myTg BOT_TOKEN=123456789:ABC-DEF1234ghIkl-zyx57W2v1u123ew11
webhook post myTg CHAT_ID=123456789 TEXT=Hello from ACE!
Optional: add PARSE_MODE=HTML (or MarkdownV2) to send formatted text.
WhatsApp (Meta Cloud API)
WhatsApp outbound messages use the Meta WhatsApp Cloud API.
On Meta for Developers
- Go to https://developers.facebook.com/ and create an app of type Business.
- In the app dashboard, click Add Product → WhatsApp → Set up.
- On the WhatsApp API Setup page you get, for free, a test phone number.
Note two values:
- Phone number ID (a long number under the "From" phone number).
- A temporary access token (valid ~24 h) shown on the same page.
- Under To, add and verify at least one recipient phone number (you can only message numbers you've added while using the test number).
- For production, generate a permanent access token: create a System User
in Business Settings, assign it to the app with the
whatsapp_business_messagingpermission, and generate a non‑expiring token.
In ACE
webhook integration setup whatsapp myWa ACCESS_TOKEN=EAAxxxxxxxx PHONE_NUMBER_ID=100000000000000
webhook post myWa TO=15551234567 BODY=Hello from ACE!
TOis the recipient in international format, digits only (no+), e.g.15551234567.- The preset targets Graph API v25.0 (current as of mid‑2026; each Graph
version stays callable for about two years). When a newer version is out you
can point the same webhook at it without recreating anything:
webhook target myWa https://graph.facebook.com/v26.0/<PHONE_NUMBER_ID>/messages.
24‑hour session window
Outside a 24‑hour customer‑service window, WhatsApp only allows approved
message templates, not free‑form text. For testing to a verified recipient
inside the window, the plain BODY=… text above works.
Email (SendGrid)
Email uses the Twilio SendGrid v3 Mail Send API.
On SendGrid
- Create an account at https://sendgrid.com/ and log in.
- Verify a sender first (this is the #1 cause of
403errors): Settings → Sender Authentication → either verify a Single Sender email address or authenticate a whole domain. - Create an API key: Settings → API Keys → Create API Key. Give it at least
Mail Send permission and copy the key (
SG.xxxx…) — it is shown only once.
In ACE
webhook integration setup email myEmail API_KEY=SG.xxxxxxxxxxxxxxxxxxxxxxxx
webhook post myEmail [email protected] [email protected] FROM_NAME=ACE Server SUBJECT=Server Alert BODY=The server is up and running
FROMmust be the address (or a domain) you verified in step 2.FROM_NAMEis optional.- A successful send returns
1; SendGrid Mail Send responds202 Acceptedwith an empty body.
Linking an integration to a command or event (optional)
Once a webhook works, you can fire it automatically:
- Inbound → run an ACE command. Create an inbound webhook and link commands to it so an external POST triggers them:
webhook integration setup github-inbound ghEvents SECRET=my-shared-secret
webhook link add ghEvents admin mydb myDeployCommand
- Outbound from a Timer / EventSensor / expression. Put
webhook post …(or theWebhookCallResponsenode in the Node Editor) inside a command, timer job, or sensor event so ACE pushes to Slack/Telegram/etc. on its own.
Use webhook list, webhook info <name>, and webhook integration list at any
time to review what you have configured.
A plain webhook, without an integration
You do not need an integration preset. An integration only pre-fills a URL, headers and a body template for a known service — the underlying object is an ordinary webhook you can create and edit yourself:
In the GUI this is the Plain webhook (no integration) entry, first in the
integration list, or New → New Webhook. Everything stays editable
afterwards: webhook target, webhook method, webhook header,
webhook template, webhook response, webhook enable / webhook disable, and
webhook link add / webhook link remove.
How an inbound webhook is triggered, and how to secure it
webhook info <name> prints the full endpoint, which looks like:
It is served by the HTTPS listener on port 4541 — the same one the web dashboard uses. Port 4542 is the ACE client protocol and does not speak HTTP, so a request sent there cannot work.
No ACE login is involved. The inbound route is deliberately reachable without a session, because the services that call it (GitHub, GitLab, a PLC, a cron job) have no ACE account. What guards it depends on whether you configure a shared secret:
| Configuration | What is required to trigger the linked commands |
|---|---|
| No secret (default) | Nothing but the URL. Any POST to it runs every linked command. The random <token> in the path is the only secret, so treat the whole URL as a password. |
| Secret configured | A matching X-Hub-Signature-256 header (GitHub style: sha256= + HMAC‑SHA256 of the exact request body) or an X-Gitlab-Token header equal to the secret. Anything else is answered 401. |
Set one with:
Other behaviour worth knowing:
- A disabled webhook (
webhook disable) answers404, as does an unknown token — an attacker cannot tell the two apart. - The request body can be stored into a linked Variable before the commands run, optionally extracting one field via a JSON pointer, so a command can read the incoming payload immediately.
- Requests are subject to the server's normal per-source rate limiting, so a caller that retries aggressively can be throttled.
- The body is read in full before dispatch, so large JSON payloads split across packets arrive intact.
Recommendation: configure a secret for anything reachable from the internet, and keep the endpoint URL out of logs, screenshots and tickets.
RFID Reader (MFRC522) wiring & setup
The RFIDReader sensor type drives an MFRC522‑style RFID/NFC reader over SPI. The SS/SDA and RST pins are yours to choose — any free digital pins work. This walkthrough uses SS/SDA on pin 3 and RST on pin 9 purely as a working example (on an Arduino Uno / Nano); if you wire different pins, just pass your pin numbers in the commands below. The SPI bus pins (SCK/MOSI/MISO) are fixed by the board and are not the SS/RST pins you choose.
Example wiring (Arduino Uno / Nano)
| MFRC522 pin | Example (Uno/Nano) | Notes |
|---|---|---|
| SDA (SS) | D3 (your choice) | Chip‑select — the first pin you pass to ACE. |
| RST | D9 (your choice) | Reset — the second pin you pass to ACE. |
| SCK | D13 | SPI clock (fixed). |
| MOSI | D11 | SPI data out (fixed). |
| MISO | D12 | SPI data in (fixed). |
| IRQ | (not connected) | Not used. |
| GND | GND | Common ground. |
| 3.3V | 3.3V | Power the module from 3.3 V, not 5 V. |
Power the MFRC522 from 3.3 V
The MFRC522 is a 3.3 V device. Powering 3.3V/VCC from the Arduino's
5 V pin is the single most common reason a reader "does nothing" or dies.
The digital SPI lines from a 5 V Arduino are tolerated by most modules, but
the power pin must be 3.3 V.
Short, solid wiring
Intermittent reads are almost always wiring: use short jumpers, make sure GND is shared, and re‑seat the SS and RST leads if tags are not detected.
Firmware
Flash the ACE firmware to the board as usual (see the Installer / firmware guide). The firmware reads the SS and RST pins that ACE sends when the reader is attached — you do not hard‑code the SS/RST pin numbers in the sketch.
Register the reader in ACE
- Create the reader sensor:
- Attach it to your controller with the SS and RST pins you wired (the
RFIDReader form of
attach-sensortakes two pins — SS first, RST second; in this example SS = 3, RST = 9):
- Start listening so the reader begins scanning for tags:
Toggling this on/off blinks the Arduino's TX/RX LEDs as ACE talks to the board.
Read tags, authorise them, and trigger commands
- See a scanned tag's UID: scan a card while listening, then check the sensor's info (current value) or its recent values:
- Authorise a specific tag (the label is optional and must be a single word):
- Choose what a scan does —
scan(just report),auth, ordeauth:
- Run a command when a particular tag is scanned:
- Inspect current state at any time:
sensor info admin mydb RFIDReader frontDoor AuthedTags
sensor info admin mydb RFIDReader frontDoor Listening
sensor info admin mydb RFIDReader frontDoor ResponseType
RFID vs. Button / EventSensor
An RFIDReader reports tag UIDs and uses auth-tag / set-tag-command
/ set-response-type. A Button / EventSensor reports digital
high/low/hold edges and uses add-event-sensor-command. Both require
start-listening, and both must be attached to a controller before they can
listen.