Skip to content
Splashify Pro
Docs

Canned Messages

The canned command (aliases: cm, cms, canned-messages) mirrors the Settings → Canned Messages page in the app. Use it to save commonly-sent WhatsApp replies — plain text, images, videos, documents, audio, or any advanced Meta Cloud API payload — and recall them from chat handlers or scripts later.

Backed by /api/v1/app/canned-messages[/:id]. Every call uses your stored oc_live_ token and is scoped to your account.

Quick start

bash
# Save a text snippet
splashify canned create \
  --name "Welcome message" \
  --shortcut "/welcome" \
  --description "First-touch greeting" \
  --type TEXT \
  --text "Hi! Thanks for reaching out — how can we help?"

# Save an image with a caption
splashify canned create \
  --name "Receipt template" \
  --type IMAGE \
  --url https://cdn.example.com/receipt.png \
  --caption "Your receipt is attached"

# See what you've got
splashify canned

Message types

The backend stores any of these message_type values. The CLI provides convenience flags for the first five (the ones the app dialog exposes interactively); the rest are reachable via --payload '<json>'.

Why these shapes? They match the app dialog's buildPayload() exactly, so payloads written from the CLI render identically in the app's preview pane and on WhatsApp itself.

--payload is validated against --type at create/update time. A shape that no sender can render — say --type INTERACTIVE_LIST with a {"text":…} body — is rejected up front instead of storing a record that fails when you send it.

How each type is delivered

WhatsApp offers no free-form interactive send: tappable buttons and native list pickers are only available through an approved template. So the four types below are delivered as a numbered text list the recipient replies to by number — this is the interaction floor by design, not a fallback.

For real tappable buttons, use an approved template: splashify message template. Run canned send --dry-run to see the exact text a payload will produce before sending it.

Command reference

splashify canned — list

bash
splashify canned                                 # default: every canned message
splashify canned list                            # alias
splashify canned list --search receipt           # name/shortcut/description match
splashify canned list --type IMAGE               # filter by message_type
splashify canned list --search hi --type TEXT    # combined

--search and --type are applied client-side (the backend returns the full list — same as the app does).

Response shape:

json
{
  "success": true,
  "messages": [
    {
      "id":             "uuid",
      "name":           "Welcome message",
      "shortcut":       "/welcome",
      "description":    "First-touch greeting",
      "message_type":   "TEXT",
      "message_payload": {"text": {"body": "Hi! Thanks for reaching out…"}},
      "is_active":      true,
      "created_at":     "...",
      "updated_at":     "..."
    }
  ]
}

splashify canned <id> — show one

bash
splashify canned <message_id>

No dedicated backend endpoint — the CLI fetches the list and filters client-side, same pattern as splashify attribute <id> and splashify member <id>.

splashify canned create — save a new message

bash
splashify canned create \
  --name <string> \
  --type <TEXT|IMAGE|VIDEO|AUDIO|DOCUMENT|…> \
  [--shortcut <string>] [--description <string>] \
  [convenience flags OR --payload '<json>']

splashify canned update — change an existing message

bash
splashify canned update <message_id> [--name …] [--shortcut …] \
                                     [--description …] [--type …] \
                                     [--text … | --url … --caption … --filename …] \
                                     [--payload '{…}']

Read-modify-write. The backend's PUT replaces every column, so the CLI loads the current record first, overlays only the flags you passed, then sends the full body. Fields you don't mention stay intact.

bash
# Just rename it
splashify canned update <id> --name "New welcome message"

# Switch the body of a TEXT canned message
splashify canned update <id> --text "Hi there 👋 — what can I do for you?"

# Add a caption to an existing IMAGE canned message
splashify canned update <id> --caption "Updated caption"

# Change a TEXT canned message to a VIDEO (must also pass --url)
splashify canned update <id> --type VIDEO --url https://cdn.example.com/intro.mp4

# Replace the whole payload (advanced types)
splashify canned update <id> --type INTERACTIVE_LIST \
  --payload '{"interactive":{"type":"list","body":{"text":"Choose one"}, …}}'

splashify canned send — send a stored message

bash
splashify canned send <message_id> --to +919876543210
splashify canned send /welcome     --to +919876543210   # by shortcut
splashify canned send /menu        --to +919876543210 --dry-run

Resolves the message by message_id or shortcut (with or without the leading /), picks the endpoint that can carry its type, and sends it. The routing table is in How each type is delivered.

--dry-run prints the resolved endpoint and request body — including the flattened text for interactive types — without sending anything:

bash
splashify canned send /menu --dry-run
json
{
  "endpoint": "/app/messages/send-text",
  "body": {
    "to": "",
    "text": "*Support*\n\nHow can we help you today?\n\n1. Invoices — Download past invoices\n2. Make a payment\n\nReply with the number of your choice."
  }
}

If a stored payload can't be rendered, the command names the offending record and sends nothing rather than putting a malformed message in front of a customer:

text
error: canned message "List menu" (INTERACTIVE_LIST) can't be sent: this
interactive canned message has no text, options, or link to send

splashify canned toggle — activate / deactivate

bash
splashify canned toggle <message_id>

Flips is_active. The endpoint always returns the new state — is_active: true means the message is now usable by chat handlers, false hides it.

splashify canned delete — remove

bash
splashify canned delete <message_id>
splashify canned rm     <message_id>      # alias
splashify canned remove <message_id>      # alias

Permanent. There is no soft-delete and no recovery — back up first if you need to keep a copy.

Advanced — interactive payloads

For the message types the app dialog does not expose (interactive buttons, lists, CTA URLs, location, contact, address) use --payload:

bash
splashify canned create \
  --name "Quick reply buttons" \
  --type INTERACTIVE_BUTTON \
  --payload '{
    "interactive": {
      "type": "button",
      "body": {"text": "How can we help?"},
      "action": {
        "buttons": [
          {"type": "reply", "reply": {"id": "billing",  "title": "Billing"}},
          {"type": "reply", "reply": {"id": "support",  "title": "Support"}},
          {"type": "reply", "reply": {"id": "sales",    "title": "Sales"}}
        ]
      }
    }
  }'

splashify canned create \
  --name "Open store CTA" \
  --type INTERACTIVE_CTA_URL \
  --payload '{
    "interactive": {
      "type": "cta_url",
      "body": {"text": "Open our online store"},
      "action": {
        "name": "cta_url",
        "parameters": {"display_text": "Open store", "url": "https://shop.example.com"}
      }
    }
  }'

splashify canned create \
  --name "Office location" \
  --type LOCATION \
  --payload '{
    "location": {
      "latitude":  12.9716,
      "longitude": 77.5946,
      "name":      "HQ",
      "address":   "Bangalore, India"
    }
  }'

message_payload is stored in the shape the WhatsApp Cloud API uses, but it is not forwarded to Meta verbatim on send — there is no canned "send this payload as-is" endpoint. canned send maps each type onto the matching /app/messages/send-* endpoint, and the interactive types are flattened to a numbered text list (see How each type is delivered). Storing a richer interactive payload than WhatsApp can deliver free-form is fine — it just arrives as the numbered list. Use --dry-run to see exactly what will go out.

Common workflows

Bulk-create from a JSON file

text
// canned.json
[
  {"name": "Hi",        "type": "TEXT",  "text": "Hi! How can we help?"},
  {"name": "Hours",     "type": "TEXT",  "text": "We're open 9-6, Mon-Sat."},
  {"name": "Brochure",  "type": "DOCUMENT", "url": "https://…/brochure.pdf", "filename": "brochure.pdf"}
]
bash
jq -c '.[]' canned.json | while read -r row; do
  splashify canned create \
    --name "$(echo "$row" | jq -r '.name')" \
    --type "$(echo "$row" | jq -r '.type')" \
    $(echo "$row" | jq -r 'select(.text)     | "--text \"\(.text)\""') \
    $(echo "$row" | jq -r 'select(.url)      | "--url \(.url)"') \
    $(echo "$row" | jq -r 'select(.filename) | "--filename \(.filename)"')
done

Deactivate every TEXT canned message you used last quarter

bash
splashify canned list --type TEXT | \
  jq -r '.messages[] | select(.updated_at < "2026-04-01") | .id' | \
  xargs -I{} splashify canned toggle {}

Find the message backing a /welcome shortcut

bash
splashify canned list --search /welcome | \
  jq '.messages[] | select(.shortcut == "/welcome") | {id, name, message_type}'

Round-trip an existing payload — copy with a new name

bash
SRC_ID="<existing message_id>"
PAYLOAD=$(splashify canned $SRC_ID | jq -c '.message_payload')
TYPE=$(splashify canned $SRC_ID    | jq -r '.message_type')
splashify canned create --name "Welcome — variant B" --type "$TYPE" --payload "$PAYLOAD"
bash
NEW_URL=$(splashify media upload ./receipt-v2.png | jq -r '.file_url')
splashify canned update <id> --url "$NEW_URL" --caption "Updated receipt"

Troubleshooting

"A canned message with this name already exists" — names are unique case-insensitively across your account. Use splashify canned list --search <name> to find the duplicate, then either rename or delete the old row.

"Name must be 200 characters or less" — trim the --name argument.

"Invalid message payload" — your --payload JSON didn't parse on the backend. Validate locally with jq first: echo "$PAYLOAD" | jq .

Update didn't change the type — make sure you passed --type and the matching media flag. Switching from TEXT → IMAGE without --url would fail validation; the CLI catches this before the round-trip and prints a usage error.

--text ignored on an IMAGE — --text only builds the payload for --type TEXT. For IMAGE/VIDEO/DOCUMENT captions, use --caption instead.

See also

  • splashify media — upload files first to get the CDN URLs you pass to --url.
  • splashify templates — approved WhatsApp templates, which are different from canned messages (templates need Meta approval, canned messages don't).
  • splashify message — the send-side commands that can include the payloads you stored here.