agentsclimarketplace

Whatsapp send

Skill InitechSoftware/openclaw-whatsapp-skills/skills/whatsapp-send

Ready-made OpenClaw skills for operating WhatsApp via the TimelinesAI public API

Install
npx -y skills add InitechSoftware/openclaw-whatsapp-skills --skill whatsapp-send

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 3 stars3 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Send a transactional or event-triggered WhatsApp message via the TimelinesAI public API. Two modes: by phone number (creates a new chat if needed) or into an existing chat by chat_id. Writes JSON payloads to a file to avoid UTF-8 encoding traps. Returns the message_uid so downstream skills can poll delivery status.

SKILL.md

6.1 KB, as published. Nobody here has run it

WhatsApp send

Send one WhatsApp message. Two paths:

PathUse whenEndpoint
By phone numberNew recipient, or you don't know the chat idPOST /messages with {"phone":"+...", "text":"..."}
By chat idExisting conversation, you have the chat id (e.g. from a webhook or an earlier send)POST /chats/{chat_id}/messages with {"text":"..."}

The sender is determined differently in each mode:

  • In phone-number mode, TimelinesAI picks the sender from your connected numbers. In a single-number workspace this is unambiguous. In a multi-number workspace it uses the workspace default — if you need deterministic sender control, use chat-id mode with a chat you know the ownership of.
  • In chat-id mode, the sender is always the JID stored in the chat's whatsapp_account_id field. You don't pick it, the chat record does. That's why this skill verifies chat ownership when ALLOWED_SENDER_JID is set.

⚠️ Compliance — read before sending

Personal WhatsApp numbers connected to TimelinesAI are for transactional messages and replies to conversations the customer started. WhatsApp bans personal numbers for cold outreach quickly and aggressively. This skill will let you send anything — it's your responsibility to know the send is safe.

Safe sends with this skill (personal-number workflow):

  • Order confirmation, shipping update, delivery notification, payment receipt.
  • Appointment reminder or booking confirmation.
  • Reply to a customer who opened the thread within WhatsApp's 24-hour session window.
  • Event-triggered notification the customer explicitly opted into (HubSpot "demo scheduled" → meeting link, Stripe failed payment → recovery note).
  • Sending a file (quote, invoice, contract) the customer just asked for.

Not safe — don't use this skill for:

  • Cold outreach to purchased lists.
  • Marketing broadcasts to customers who didn't opt in.
  • Any unsolicited promotional message.

Those use cases need the WhatsApp Business API, which TimelinesAI supports today through the dashboard — public API automation is coming in Q2 2026. See ../../docs/compliance.md for the full explanation.

Invocation payload

{
  "mode": "phone" | "chat",
  "phone": "+15550200",              // mode=phone only
  "chat_id": 12345678,               // mode=chat only
  "text": "Your order shipped. Tracking: ABC123."
}

Step 1 — Chat ownership check (chat mode only)

If you're sending into an existing chat and ALLOWED_SENDER_JID is set, verify the chat is owned by the allowed number before sending. This prevents accidentally sending your sales outbound from the support number in a multi-number workspace.

if [ "$MODE" = "chat" ] && [ -n "$ALLOWED_SENDER_JID" ]; then
    CHAT_JID=$(curl -sS -H "Authorization: Bearer $TIMELINES_AI_API_KEY" \
      "https://app.timelines.ai/integrations/api/chats/$CHAT_ID" \
      | jq -r '.data.whatsapp_account_id')
    if [ "$CHAT_JID" != "$ALLOWED_SENDER_JID" ]; then
        echo "chat $CHAT_ID owned by $CHAT_JID, not $ALLOWED_SENDER_JID — refusing to send"
        exit 1
    fi
fi

Step 2 — Write payload to a file (UTF-8 safe)

NEVER use curl -d "..." with arbitrary content. Shell encoding will corrupt non-ASCII characters — em-dashes, smart quotes, emoji — and the TimelinesAI JSON parser will reject the whole request with 'utf-8' codec can't decode byte 0x97.... Always write to a file with explicit UTF-8, always read with --data-binary @file.

if [ "$MODE" = "phone" ]; then
    python3 -c "
import json, sys
json.dump({'phone': sys.argv[1], 'text': sys.argv[2]}, open('/tmp/wa_send.json','w'), ensure_ascii=False)
" "$PHONE" "$TEXT"
else
    python3 -c "
import json, sys
json.dump({'text': sys.argv[1]}, open('/tmp/wa_send.json','w'), ensure_ascii=False)
" "$TEXT"
fi

Step 3 — Send

if [ "$MODE" = "phone" ]; then
    ENDPOINT="https://app.timelines.ai/integrations/api/messages"
else
    ENDPOINT="https://app.timelines.ai/integrations/api/chats/$CHAT_ID/messages"
fi

RESPONSE=$(curl -sS -X POST \
  -H "Authorization: Bearer $TIMELINES_AI_API_KEY" \
  -H "Content-Type: application/json" \
  --data-binary @/tmp/wa_send.json \
  "$ENDPOINT")

echo "$RESPONSE"

Success:

{"status":"ok","data":{"message_uid":"a8f9b2c1-..."}}

Capture the message_uid from the response and return it. Downstream skills can use whatsapp-delivery-check to poll Sent / Delivered / Read status for this uid.

Failure modes

ResponseMeaningWhat to do
{"status":"error","message":"Bad JSON format: 'utf-8'..."}Your payload isn't valid UTF-8Rewrite using step 2's file pattern; don't use inline -d
{"status":"error","message":"Not authenticated"}Wrong or missing tokenCheck $TIMELINES_AI_API_KEY
{"status":"error","message":"Whatsapp chat_id ... not found"}Chat doesn't exist in your workspaceDon't retry; check the id
Branded HTML 404 pageTrailing slash on the URLRemove it (/messages, not /messages/)
{"status":"error","message":"Phone number invalid"}Bad E.164 formatFormat as +<country><number> with no spaces or dashes

What this skill deliberately does NOT do

  • Does not retry on network failure — return the error to the caller, let them decide.
  • Does not batch multiple sends — call the skill once per recipient.
  • Does not throttle — TimelinesAI enforces its own WhatsApp-compliance throttle server-side.
  • Does not warn you about cold outreach — you're expected to know. Read ../../docs/compliance.md before wiring this into an agent that can initiate conversations.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.