Skip to content
Splashify Pro
Docs

Messages

The message, conversation, conversations, rcs, instagram, calling, call and contact commands together mirror the /messages page. From the terminal you can:

  • Send WhatsApp text (with reply context), media (with voice-note flag), templates, location pins, reaction emojis, contact cards, and typing indicators.
  • Send free-form RCS messages and RCS templates.
  • Send Instagram DMs (text + image / video / audio media), and check the 24h / 7d reply window.
  • Ask a contact for call permission (interactive text or template), then initiate the call from the backend.
  • Drive conversation lifecycle: list with channel/search filters, show, resolve, reopen, assign / unassign.
  • Edit contact notes, opt-out flag, tags, and the rest of the contact sidebar surface.

Everything below maps 1:1 to a button or composer action on the /messages page. Backed by /api/v1/app/messages/*, /api/v1/app/rcs/messages/*, /api/v1/app/instagram/*, /api/v1/app/calling/* and /api/v1/app/contacts/*.

Quick start

bash
# WhatsApp — send a text, then react and reply.
splashify message send --to "+919876543210" --text "Order shipped!"
splashify message reaction --to "+919876543210" --message-id <wa_id> --emoji "👍"
splashify message send --to "+919876543210" --text "Tracking link incoming" \
  --context-message-id <wa_id>

# RCS — free-form send
splashify rcs send --to "+919876543210" --text "Hi from the CLI 👋"

# Instagram DM
splashify instagram dm --conversation <conv_id> --message "Thanks for the comment!"

# Ask for call permission, then dial
splashify calling permission-status --phone "+919876543210"
splashify calling send permission --to "+919876543210" \
  --body-text "Can we call you about your order?"
splashify call initiate --to "+919876543210"

# Lifecycle
splashify conversations --channel whatsapp --search "Acme" --limit 50
splashify conversation <conv_id> assign --to <member_id>
splashify conversation <conv_id> resolve

WhatsApp messages

splashify message send — text (with optional reply)

bash
splashify message send --to "+919876543210" --text "Hello!"

# Reply-quote an existing message
splashify message send --to "+919876543210" --text "Same here." \
  --context-message-id wamid.ABC123

--context-message-id accepts the recipient's wa_message_id and renders as the quoted bubble above your reply — same as tapping Reply on the page.

splashify message media — image / video / audio / document

bash
splashify message media --to "+919876543210" \
  --type image --url https://cdn.example.com/poster.jpg \
  --caption "Doors open at 7"

# Audio as a voice note (single-tap play, no scrubber)
splashify message media --to "+919876543210" \
  --type audio --url https://cdn.example.com/note.ogg \
  --voice true

# Document with a filename hint
splashify message media --to "+919876543210" \
  --type document --url https://cdn.example.com/inv.pdf \
  --filename "INV-1024.pdf"

splashify message template — approved template

bash
splashify message template --to "+919876543210" \
  --name order_shipped \
  --lang en \
  --vars '["Jane","ORD-1024","2026-05-25"]'

For full Meta-shape control (header components, buttons), pass the already-assembled template with --template '{…}'.

splashify message location — drop a pin

bash
splashify message location --to "+919876543210" \
  --lat 12.9716 --lng 77.5946 \
  --name "Acme HQ" \
  --address "5th Cross, Bengaluru 560001"

splashify message reaction — emoji react

bash
splashify message reaction --to "+919876543210" \
  --message-id wamid.ABC123 --emoji "👍"

# Clear a reaction (pass an empty string)
splashify message reaction --to "+919876543210" \
  --message-id wamid.ABC123 --emoji ""

splashify message contact — contact card

bash
splashify message contact --to "+919876543210" \
  --contacts '[{
    "name":   {"formatted_name":"Acme Support","first_name":"Acme"},
    "phones": [{"phone":"+918000000000","type":"WORK","wa_id":"918000000000"}],
    "emails": [{"email":"[email protected]","type":"WORK"}]
  }]'

# Or load from a file
splashify message contact --to "+919876543210" --file ./contact.json

Accepts Meta's canonical contacts[] shape verbatim. The CLI also accepts a single contact object (without the array wrapper) and wraps it for you.

splashify message typing — typing-indicator bubble

bash
splashify message typing --message-id "wamid.HBgM..."

Tied to the inbound message you're replying to, not a raw recipient phone number — Meta's typing-indicator API requires the id of that message. Get one from splashify message list/show on the conversation. Free to send; the bubble auto-expires server-side after ~25s. Debounce on the caller's side if you're driving it from a script.

RCS messages

splashify rcs send — free-form RCS text

bash
splashify rcs send --to "+919876543210" --text "Hi 👋"

Runs the standard subscription + wallet preflight (skip with --yes). RCS pricing is separate from WhatsApp — see splashify expenses for the per-message billing log.

splashify rcs send-template — RCS template

bash
splashify rcs send-template --to "+919876543210" \
  --template-id 7a32bce6-…

The template must be APPROVED — use splashify rcs templates to list approved templates and splashify rcs template <id> check-status to refresh the approval state.

Instagram DMs

The full surface lives in splashify instagram. The two commands that map directly to the /messages page's Instagram tab:

bash
# Text + optional media in the same call (renders as two bubbles)
splashify instagram dm --conversation <conv_id> --message "Thanks!" \
  --media-url https://cdn.example.com/photo.jpg --media-type image

# Check the 24h / 7d reply window
splashify instagram window --conversation <conv_id>

The window response carries state: "open" | "human_agent_only" | "expired" and seconds_remaining so you can gate further sends the same way the page does.

Call permission + initiate

The composer's call icon mirrors the same three-state flow as /messages:

  1. Check the customer's existing call permission.
  2. If absent and the 24h WhatsApp window is open, send a free-form interactive request.
  3. Otherwise, send a permission template (which works at any time).

splashify calling permission-status — check permission

bash
splashify calling permission-status --phone "+919876543210"

Returns {success, is_window_open, permission_status:{status:…}}. Status values: granted, temporary, approved, active, permanent all mean "OK to call". Anything else means you must ask first.

splashify calling send permission — ask for permission

bash
# Interactive (24h window must be open)
splashify calling send permission --to "+919876543210" \
  --body-text "May we call you about your order ETA?"

# Template (works any time, costs a template charge)
splashify calling send permission --to "+919876543210" \
  --type template \
  --template '{"name":"call_perm_v1","language":{"code":"en"}}'

Or use the dedicated template-only path:

bash
splashify calling send permission-template --to "+919876543210" \
  --name call_perm_v1 --language en

splashify call initiate — backend-side dial

bash
splashify call initiate --to "+919876543210"

The CLI does not drive WebRTC peer audio — that flow needs SDP/ICE exchange a shell can't provide. call initiate triggers the backend's WhatsApp Calling pipeline (the same one the WebRTCCallDialog ends up routing to), and the call shows up in splashify calling calls once Meta confirms.

Conversation lifecycle

splashify conversations — list

bash
splashify conversations                                  # default (open WA)
splashify conversations --status resolved                # closed inbox
splashify conversations --channel rcs                    # RCS tab
splashify conversations --channel instagram --search "Acme"
splashify conversations --page 2 --limit 50

--channel mirrors the inbox switcher on the page (whatsapp / rcs / instagram). --page-size is kept as an alias of --limit for backward compatibility with older scripts.

splashify conversation <id> — show one

bash
splashify conversation 7a32bce6-…

Returns the conversation row plus the message thread.

Lifecycle actions

bash
splashify conversation <id> resolve                      # close the conversation
splashify conversation <id> reopen                       # flip back to open
splashify conversation <id> assign --to <member_id>      # assign to a teammate
splashify conversation <id> assign --to ""               # unassign
splashify conversation <id> assign --team <team_id>      # wait in a team's queue
splashify conversation <id> assign --to <member_id> --team <team_id> --note "Bulk order"
splashify conversation <id> assign --to "" --team none   # out of its team, unassigned
splashify teams                                          # list teams and their people

Contact mutations

splashify contact update — sparse PUT

bash
# Save a note (page: handleSaveNotes)
splashify contact update <id> --notes "VIP. Prefers WhatsApp over email."

# Marketing opt-out toggle (page: handleOptToggle)
splashify contact update <id> --opted-out true

# Update name + email + website (page: contact sidebar)
splashify contact update <id> \
  --name "Jane Doe" --email [email protected] --website https://acme.example

# Replace the tag set in one call
splashify contact update <id> --tags vip,lead,trial

# Bonus: raw JSON for fields not covered by named flags
splashify contact update <id> --data '{"column_data":"{\"company\":\"Acme\"}"}'

Sparse — only the flags you explicitly pass are included in the body. --data JSON overlays last and wins over the named flags when they conflict.

splashify contact tag / untag — add and remove tags

bash
splashify contact tag   <id> --tags vip,lead
splashify contact untag <id> --tags lead

splashify contact block / unblock

bash
splashify contact block   <id>
splashify contact unblock <id>

Blocking stops every outbound channel for that contact and refuses inbound messages too — same behaviour as the /messages block confirm dialog.

Common workflows

Reply to the latest inbound on every open WhatsApp conversation

bash
splashify conversations --channel whatsapp --status open --limit 50 | \
  jq -r '.conversations[] | "\(.conversation_id) \(.phone_number)"' | \
while read CID PHONE; do
  splashify message send --to "$PHONE" --text "Thanks for reaching out — we'll be right with you."
done

Resolve every conversation older than 7 days

bash
CUTOFF=$(date -u -v-7d '+%Y-%m-%dT%H:%M:%SZ')          # macOS
# CUTOFF=$(date -u -d '7 days ago' '+%Y-%m-%dT%H:%M:%SZ')   # linux

splashify conversations --status open --limit 200 | \
  jq -r --arg c "$CUTOFF" '.conversations[] | select(.last_message_at < $c) | .conversation_id' | \
  xargs -I{} splashify conversation {} resolve

Triage unassigned conversations to the on-call agent

bash
AGENT_ID=$(splashify team | jq -r '.members[] | select(.role=="oncall") | .member_id')

splashify conversations --status open --limit 200 | \
  jq -r '.conversations[] | select(.assigned_to == null or .assigned_to == "") | .conversation_id' | \
  xargs -I{} splashify conversation {} assign --to "$AGENT_ID"

Run a "request call permission → dial" loop

bash
PHONE="+919876543210"
STATUS=$(splashify calling permission-status --phone "$PHONE" | jq -r '.permission_status.status // "none"')

case "$STATUS" in
  granted|temporary|approved|active|permanent)
    splashify call initiate --to "$PHONE"
    ;;
  *)
    splashify calling send permission --to "$PHONE" \
      --body-text "May we call you about your recent order?"
    echo "Permission requested — try again once the customer approves."
    ;;
esac

Troubleshooting

message reaction returns "message not found" — --message-id must be the recipient's wa_message_id (a wamid.… string), not the internal message_id UUID. List recent messages with splashify conversation <id> and grab the wa_message_id from the thread.

message contact errors with "invalid contacts" — the array must match Meta's exact shape. name.formatted_name is required; phones[] needs at least one entry with phone (and ideally wa_id so it links to a WhatsApp profile on the recipient's side).

rcs send returns insufficient_balance — RCS pricing is separate from WhatsApp. Run splashify wallet and recharge from the app. The preflight uses a coarse balance threshold; the actual per-message cost is debited after delivery.

instagram dm returns "outside 7d window" — Meta blocks outbound DMs after the customer hasn't messaged in 7 days. Use splashify instagram window --conversation <id> to see exactly when the window expires.

call initiate succeeds but no call rings — backend-side dial uses the WhatsApp Calling pipeline; the customer must have granted call permission first (calling permission-status should show granted/temporary/approved/active/permanent). If not, calling send permission and try again after approval.

See also