Skip to content

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:

  1. On the service — create the app / bot / API key and copy a credential.
  2. 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

  1. Go to https://api.slack.com/apps and click Create New App → From scratch.
  2. Give it a name, pick your workspace, click Create App.
  3. In the left sidebar open Incoming Webhooks and toggle Activate Incoming Webhooks on.
  4. Click Add New Webhook to Workspace, choose the channel to post to, and Allow.
  5. 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

  1. In the Telegram app, open a chat with @BotFather.
  2. Send /newbot, then follow the prompts to name your bot. BotFather replies with a bot token like 123456789:ABC-DEF1234ghIkl-zyx57W2v1u123ew11.
  3. 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>/getUpdates in 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 getUpdates the same way (group IDs are negative, e.g. -1001234567890).

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

  1. Go to https://developers.facebook.com/ and create an app of type Business.
  2. In the app dashboard, click Add Product → WhatsApp → Set up.
  3. 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.
  4. Under To, add and verify at least one recipient phone number (you can only message numbers you've added while using the test number).
  5. For production, generate a permanent access token: create a System User in Business Settings, assign it to the app with the whatsapp_business_messaging permission, 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!
  • TO is 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

  1. Create an account at https://sendgrid.com/ and log in.
  2. Verify a sender first (this is the #1 cause of 403 errors): Settings → Sender Authentication → either verify a Single Sender email address or authenticate a whole domain.
  3. 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
  • FROM must be the address (or a domain) you verified in step 2.
  • FROM_NAME is optional.
  • A successful send returns 1; SendGrid Mail Send responds 202 Accepted with 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 the WebhookCallResponse node 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:

webhook create myhook inbound
webhook create myalert outbound

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:

https://<host>:4541/webhook/<token>

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:

webhook secret set myhook my-shared-secret

Other behaviour worth knowing:

  • A disabled webhook (webhook disable) answers 404, 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

  1. Create the reader sensor:
sensor create admin mydb RFIDReader frontDoor
  1. Attach it to your controller with the SS and RST pins you wired (the RFIDReader form of attach-sensor takes two pins — SS first, RST second; in this example SS = 3, RST = 9):
controller attach-sensor admin mydb Arduino myUno admin mydb RFIDReader frontDoor 3 9
  1. Start listening so the reader begins scanning for tags:
sensor start-listening admin mydb RFIDReader frontDoor

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:
sensor info          admin mydb RFIDReader frontDoor
sensor recent-values admin mydb RFIDReader frontDoor
  • Authorise a specific tag (the label is optional and must be a single word):
sensor auth-tag admin mydb RFIDReader frontDoor 04A1B2C3D4 PetersBadge
  • Choose what a scan does — scan (just report), auth, or deauth:
sensor set-response-type admin mydb RFIDReader frontDoor scan
  • Run a command when a particular tag is scanned:
sensor set-tag-command admin mydb RFIDReader frontDoor admin mydb UnlockDoor 04A1B2C3D4
  • 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.