Splashify RCS

Docs

Open panel
Panel

Keyword auto-reply

Every bot on the RCS Panel can carry a small rule table that reacts to inbound free-form messages. When a recipient replies to your bot with text (not a suggestion tap), the panel walks the rules in order, and the first match wins.

Common patterns:

  • STOP → add the phone to your account-wide opt-out list.
  • SALES → reply with a canned message + forward the reply to [email protected].
  • Regex like ^i want (a )?refund → fire a webhook so your CRM ticks a support ticket open.
  • One optional fallback rule per bot (empty keyword) catches everything nothing else matched.

Access

Bot scope from the caller's JWT bots claim applies: a rule under a bot the member can't act on returns 403 bot_not_assigned.

Endpoints

http
GET    /api/v1/rcs/auto-replies/{bot_id}
POST   /api/v1/rcs/auto-replies/{bot_id}
PATCH  /api/v1/rcs/auto-replies/{bot_id}/{rule_id}
DELETE /api/v1/rcs/auto-replies/{bot_id}/{rule_id}
POST   /api/v1/rcs/auto-replies/{bot_id}/reorder
GET    /api/v1/rcs/auto-replies/{bot_id}/fires?limit=100

Rule schema

json
{
  "keyword":       "STOP",
  "match_mode":    "exact",
  "order_index":   0,
  "actions":       ["reply", "add_to_opt_out"],
  "reply_message": "You've been unsubscribed. Reply START to resubscribe.",
  "forward_email": "",
  "webhook_url":   "",
  "add_to_list_id": "",
  "enabled":       true
}

match_mode

Actions

Every rule can declare one or more of these primitives, order inside the array is cosmetic; the engine always fires them in a fixed order (reply first, then opt-out mutation, then external side-effects):

Fallback rule

Set keyword to "" to build the fallback. Only one fallback per bot is allowed, a second POST returns 409 fallback_exists. The fallback fires only when nothing else in the table matched.

Ordering & reorder

Rules render in order_index ascending (ties broken by creation time). To move a rule, send its full list of rule_ids in the desired order:

http
POST /api/v1/rcs/auto-replies/{bot_id}/reorder
{ "rule_ids": ["<id_1>", "<id_2>", "<id_3>"] }

Unknown IDs are silently skipped. The endpoint writes order_index = index for every element in the array.

Fires log

Every match is recorded in the rule's fires log with the matched keyword, inbound message id, reply message id (when the reply action fired), and the ordered list of actions that actually ran. Read it via:

http
GET /api/v1/rcs/auto-replies/{bot_id}/fires?limit=100

Sorted newest first. A match is recorded as the inbound message is handled, so it is usually visible within a fraction of a second.

Defaults on bot activation

When an admin activates a fresh bot, the router seeds two rules:

text
STOP  → add_to_opt_out + reply "You've been unsubscribed. Reply START to resubscribe."
START → remove_from_opt_out + reply "You're back, welcome!"

Idempotent per (user, bot), re-activating an existing bot doesn't blow away edits the operator made.

Regex tips

  • Anchor to the start with ^ unless you want contains semantics.
  • Group the parts you want to keep out of the match with non-capturing groups: (?:foo|bar).
  • Wrap variable text in .* sparingly, a runaway .* can inflate the fire log on chatty inbounds.
  • Compile fails at write-time; the panel modal shows the compiler error inline so you don't waste a fire.

Webhook payload

json
{
  "event":              "auto_reply.fired",
  "user_id":            "9f…",
  "bot_id":             "3c…",
  "rule_id":            "de…",
  "keyword":            "SALES",
  "match_mode":         "starts_with",
  "recipient_phone":    "+919876543210",
  "recipient_name":     "Priya",
  "inbound_text":       "SALES please quote for 500 units",
  "inbound_message_id": "msg_a1b2c3",
  "fired_at":           "2026-07-16T09:12:03Z"
}

Webhook targets go through the standard SSRF guard: only public HTTPS hosts, no follow-redirects to internal IPs. Non-2xx responses are logged but the fire row still lands.