ronnycoding/.claude

penwa

Drive the OpenWA WhatsApp HTTP API from the terminal with curl.

First seen Jun 18, 2026

Installation

$ npx skills add ronnycoding/.claude --skill penwa

Summary

  • Drive the OpenWA WhatsApp HTTP API from the terminal with curl.
  • Use when sending WhatsApp messages (text/image/video/audio/document/location/contact/bulk), managing sessions and QR login, listing contacts/groups/chats, registering webhooks, or managing scoped API keys against an OpenWA server.
  • Triggers on "OpenWA", "penwa", "send WhatsApp via API", "WhatsApp session", or mentions of base URL http://0.0.0.0:2785.

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from ronnycoding/.claude · top by installs.

npx skills add ronnycoding/.claude

Browse all from ronnycoding/.claude

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Repository health

Stars 20
Default branch main
Open issues 0
Status Active

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 7,576 B
  • docs SUMMARY.md 428 B

History

  1. First seen on skills.sh
  2. First recorded snapshot · 1 installs

SKILL.md

penwa — OpenWA API via curl

Talk to an OpenWA WhatsApp server over its REST API using curl. Spec: docs/06-api-specification.md.

Connection

Setting Flag Env var Default
Base URL --base-url OPENWABASEURL http://0.0.0.0:2785
API key --api-key OPENWAAPIKEY dev-admin-key
  • All API paths are prefixed with /api → e.g. http://0.0.0.0:2785/api/sessions.
  • Auth header is X-API-Key (not Authorization). Send it on every call except GET /health.
  • Set up the shell once, then every snippet below works as-is:
export OPENWA_BASE_URL="${OPENWA_BASE_URL:-http://0.0.0.0:2785}"
export OPENWA_API_KEY="${OPENWA_API_KEY:-dev-admin-key}"
BASE="$OPENWA_BASE_URL/api"
AUTH=(-H "X-API-Key: $OPENWA_API_KEY" -H "Content-Type: application/json")

chatId format: individuals <countrycode><number>@c.us (e.g. [email protected]); groups <id>@g.us. No +, spaces, or dashes.

Quick start: verify, log in, send

# 1. Is the server up? (public, no key)
curl -s "$BASE/health"

# 2. Is my key valid?
curl -s -X POST "$BASE/auth/validate" "${AUTH[@]}"

# 3. Create a session
curl -s -X POST "$BASE/sessions" "${AUTH[@]}" -d '{"name":"main"}'
# -> note the returned sessionId, e.g. sess_abc123

# 4. Get the QR (scan in WhatsApp > Linked devices). Returns an image.
SID=sess_abc123
curl -s "$BASE/sessions/$SID/qr" -H "X-API-Key: $OPENWA_API_KEY" -o qr.png && open qr.png

# 5. Poll until connected
curl -s "$BASE/sessions/$SID" "${AUTH[@]}"   # watch for status: connected

# 6. Send your first message
curl -s -X POST "$BASE/sessions/$SID/messages/send-text" "${AUTH[@]}" \
  -d '{"chatId":"[email protected]","text":"Hello from OpenWA!"}'

Add -H "X-Request-ID: req_$(date +%s)" to any write call for traceable logs. Pipe responses through | jq to read them.

Sessions

# List (optional ?status= ?page= ?limit=)
curl -s "$BASE/sessions?status=connected&limit=20" "${AUTH[@]}"

# Create with a webhook attached
curl -s -X POST "$BASE/sessions" "${AUTH[@]}" \
  -d '{"name":"sales-bot","webhook":"https://example.com/hook"}'

# Details / QR / logout / delete
curl -s     "$BASE/sessions/$SID"        "${AUTH[@]}"
curl -s     "$BASE/sessions/$SID/qr"     -H "X-API-Key: $OPENWA_API_KEY" -o qr.png
curl -s -X POST   "$BASE/sessions/$SID/logout" "${AUTH[@]}"
curl -s -X DELETE "$BASE/sessions/$SID"        "${AUTH[@]}"

Sending messages

All send endpoints are POST /sessions/:sessionId/messages/send-<type>. Media accepts either {"url":"..."} or a base64 {"data":"...","mimetype":"..."} object — {"url":...} shown.

SEND="$BASE/sessions/$SID/messages"

# Text
curl -s -X POST "$SEND/send-text" "${AUTH[@]}" \
  -d '{"chatId":"[email protected]","text":"Hello *world*"}'

# Image (with caption)
curl -s -X POST "$SEND/send-image" "${AUTH[@]}" \
  -d '{"chatId":"[email protected]","image":{"url":"https://example.com/pic.jpg"},"caption":"Check this out!"}'

# Video
curl -s -X POST "$SEND/send-video" "${AUTH[@]}" \
  -d '{"chatId":"[email protected]","video":{"url":"https://example.com/clip.mp4"},"caption":"demo"}'

# Audio / voice note (ptt:true = push-to-talk bubble)
curl -s -X POST "$SEND/send-audio" "${AUTH[@]}" \
  -d '{"chatId":"[email protected]","audio":{"url":"https://example.com/vn.ogg"},"ptt":true}'

# Document
curl -s -X POST "$SEND/send-document" "${AUTH[@]}" \
  -d '{"chatId":"[email protected]","document":{"url":"https://example.com/invoice.pdf"},"filename":"invoice.pdf","caption":"Your invoice"}'

# Location
curl -s -X POST "$SEND/send-location" "${AUTH[@]}" \
  -d '{"chatId":"[email protected]","latitude":-6.2088,"longitude":106.8456,"description":"Jakarta HQ"}'

# Contact card
curl -s -X POST "$SEND/send-contact" "${AUTH[@]}" \
  -d '{"chatId":"[email protected]","contact":{"name":"Jane","phone":"628987654321"}}'

Bulk send

# Queue a batch
curl -s -X POST "$SEND/send-bulk" "${AUTH[@]}" -d '{
  "messages":[
    {"chatId":"[email protected]","text":"Hi A"},
    {"chatId":"[email protected]","text":"Hi B"}
  ]
}'
# -> returns a batchId

BID=batch_xyz
curl -s     "$SEND/batch/$BID"        "${AUTH[@]}"   # status/progress
curl -s -X POST "$SEND/batch/$BID/cancel" "${AUTH[@]}"   # cancel

Message history

curl -s "$BASE/sessions/$SID/chats/[email protected]/messages?limit=50" "${AUTH[@]}"
# ?before=<messageId> to paginate older

Contacts

curl -s "$BASE/sessions/$SID/contacts" "${AUTH[@]}"
# Does this number have WhatsApp?
curl -s "$BASE/sessions/$SID/contacts/check/628123456789" "${AUTH[@]}"
# Avatar
curl -s "$BASE/sessions/$SID/contacts/[email protected]/profile-picture" "${AUTH[@]}"

Groups

curl -s "$BASE/sessions/$SID/groups" "${AUTH[@]}"                 # list
curl -s "$BASE/sessions/$SID/groups/[email protected]" "${AUTH[@]}"   # info + participants
# Create
curl -s -X POST "$BASE/sessions/$SID/groups" "${AUTH[@]}" \
  -d '{"name":"Project Team","participants":["[email protected]","[email protected]"]}'

Webhooks

# Register
curl -s -X POST "$BASE/sessions/$SID/webhooks" "${AUTH[@]}" -d '{
  "url":"https://example.com/wa-hook",
  "events":["message.received","message.ack","session.status"],
  "secret":"shhh"
}'
curl -s     "$BASE/sessions/$SID/webhooks"            "${AUTH[@]}"   # list
curl -s -X DELETE "$BASE/sessions/$SID/webhooks/wh_123"  "${AUTH[@]}"   # delete

API key management (admin role)

# Create a scoped key
curl -s -X POST "$BASE/auth/api-keys" "${AUTH[@]}" \
  -d '{"name":"n8n Integration","role":"operator"}'
# Optional fields: allowedIps[], allowedSessions[], expiresAt (ISO)

curl -s     "$BASE/auth/api-keys"            "${AUTH[@]}"   # list
curl -s     "$BASE/auth/api-keys/key_123"    "${AUTH[@]}"   # details
curl -s -X PUT    "$BASE/auth/api-keys/key_123" "${AUTH[@]}" -d '{"role":"viewer"}'
curl -s -X POST   "$BASE/auth/api-keys/key_123/revoke" "${AUTH[@]}"
curl -s -X DELETE "$BASE/auth/api-keys/key_123" "${AUTH[@]}"

Health

curl -s "$BASE/health"            # public, no key
curl -s "$BASE/health/detailed" "${AUTH[@]}"   # auth required

Tips & gotchas

  • /api prefix — endpoints in the spec tables omit it; always prepend it (already baked into $BASE).
  • QR is binary — write to a file with -o qr.png; don't dump it to the terminal.
  • X-API-Key, not Bearer — a 401 almost always means wrong header name or key.
  • chatId hygiene — strip +/spaces; suffix @c.us (person) or @g.us (group). Use contacts/check before sending to unknown numbers.
  • Debug a call — add -i to see status + headers, or -w '\n%{http_code}\n' for just the code.
  • WebSocket for realtime: wss://<host>/ws?apiKey=$OPENWAAPIKEY, then send {"type":"subscribe","payload":{"sessionId":"...","events":[...]}}.
  • Reach for jq to extract fields, e.g. ... | jq -r '.sessionId' to capture and reuse.