Stage 4. Push the generated bot to GitHub, deploy on Render.com, register the public webhook URL with Wasender, and verify a real round-trip message works.
How this skill is triggered — by the user, by Claude, or both
Slash command
/whatsapp-agent-builder:wa-deployThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Goal: get the bot onto a public HTTPS URL so Wasender can deliver webhooks to it. Render.com is the default — free tier is enough for a personal bot, and the deploy is a single CLI call.
Goal: get the bot onto a public HTTPS URL so Wasender can deliver webhooks to it. Render.com is the default — free tier is enough for a personal bot, and the deploy is a single CLI call.
Speak Hebrew. Ask before doing anything that costs money or makes the bot reachable.
הבוט שלך מוכן. עכשיו נעלה אותו לאוויר.
נשתמש ב-Render.com — שירות שמריץ את הבוט בענן. יש להם תוכנית חינמית שמספיקה לרוב המקרים. אם הבוט הופך עמוס נשדרג ל-$7 לחודש.
מוכן?
The bot needs to live in a Git repo for Render to deploy it.
Ask:
יש לך חשבון GitHub?
- כן, ואני מחובר ל-
ghCLI כאן- כן, אבל לא מחובר
- אין לי
For 1: skip ahead.
For 2: tell them to run gh auth login and come back.
For 3: walk them through creating one at github.com/signup, then gh auth login.
Then:
cd bot
git init
git add .
git commit -m "initial commit: WhatsApp agent generated by WhatsApp Agent Builder"
gh repo create wa-bot-${BOT_NAME_SLUG} --private --source . --remote origin --push
Capture the repo URL from gh output. Tell the user:
יצרתי לך ריפו פרטי ב-GitHub: {repo_url}. הקוד שלך נשמר שם.
Ask:
יש לך חשבון Render?
- כן
- לא — נירשם עכשיו
For 2:
- גש ל https://render.com/register
- הירשם עם GitHub (הכי קל) או אימייל.
- כשסיימת, תגיד לי "מוכן".
בשביל לפרוס מכאן, אצטריך מפתח API של Render:
- גש ל https://dashboard.render.com/u/settings#api-keys
- צור מפתח חדש בשם "claude-code".
- הדבק כאן.
Save to project-root .env as RENDER_API_KEY. Don't echo back.
Use the Render API (POST /v1/services). The bot is a web_service.
Render API schema notes (verified live, 2026-05):
envVars is top-level in the request body, not inside serviceDetails.buildCommand and startCommand go inside serviceDetails.envSpecificDetails (NOT top-level, NOT serviceDetails directly). Putting them at the top level returns "buildCommand is required for non-static, non-docker services" even though they're set there.pythonVersion also goes inside envSpecificDetails.runtime: "python" (not the older env: "python" — Render accepts both but runtime is the current key).Use Python to build the JSON body so secrets stay in env vars and never appear in shell command output:
set -a; source "$ENV_FILE"; set +a
export OWNER_ID="..." # from GET /v1/owners
python <<'PYEOF' > /tmp/render_create.json
import json, os
body = {
"type": "web_service",
"name": "wa-bot-" + os.environ["BOT_NAME_SLUG"],
"ownerId": os.environ["OWNER_ID"],
"repo": os.environ["GITHUB_REPO_URL"],
"branch": "main",
"autoDeploy": "yes",
"rootDir": "",
"envVars": [
{"key": "WASENDER_API_KEY", "value": os.environ["WASENDER_API_KEY"]},
{"key": "WASENDER_WEBHOOK_SECRET", "value": os.environ["WASENDER_WEBHOOK_SECRET"]},
{"key": "WASENDER_ACCOUNT_PROTECTION", "value": "true"},
{"key": "ANTHROPIC_API_KEY", "value": os.environ["ANTHROPIC_API_KEY"]},
{"key": "LLM_MODEL", "value": "claude-haiku-4-5"},
{"key": "MAX_HISTORY", "value": "20"},
],
"serviceDetails": {
"runtime": "python",
"plan": "free",
"region": "singapore", # frankfurt for Israel, oregon for Americas, singapore for Asia
"envSpecificDetails": {
"pythonVersion": "3.12.7",
"buildCommand": "pip install -r requirements.txt",
"startCommand": "uvicorn main:app --host 0.0.0.0 --port $PORT",
},
"healthCheckPath": "/healthz",
},
}
print(json.dumps(body))
PYEOF
curl -s -X POST "https://api.render.com/v1/services" \
-H "Authorization: Bearer $RENDER_API_KEY" \
-H "Content-Type: application/json" \
-d @/tmp/render_create.json
rm -f /tmp/render_create.json
OWNER_ID comes from GET /v1/owners first:
curl -s "https://api.render.com/v1/owners" \
-H "Authorization: Bearer $RENDER_API_KEY" | jq -r '.[0].owner.id'
Region: pick frankfurt for Israeli users (lowest latency to most Israeli ISPs), oregon for Americas, singapore for Asia/Pacific.
Save the returned service.id and service.serviceDetails.url to .wa-state.json as render_service_id and render_url.
Poll GET /v1/services/{id}/deploys?limit=1 until status becomes live. Show progress in Hebrew:
בונה... (~2 דקות) מתקין תלויות... מפעיל... 🎉 הבוט באוויר ב: {render_url}
Verify:
curl -s "$RENDER_URL/healthz"
Expect {"status":"ok"}. If it fails, fetch the latest deploy logs (GET /v1/services/{id}/deploys/{deployId}/events) and surface the error in Hebrew.
Now the critical bit: tell Wasender where to deliver inbound messages.
Branch on setup_path from .wa-state.json:
curl -sX PUT "https://www.wasenderapi.com/api/whatsapp-sessions/$WASENDER_SESSION_ID" \
-H "Authorization: Bearer $WASENDER_PAT" \
-H "Content-Type: application/json" \
-d '{
"webhook_url": "'$RENDER_URL'/webhook/wasender",
"webhook_enabled": true,
"webhook_events": ["messages.received", "session.status"]
}'
Verify:
curl -sX GET "https://www.wasenderapi.com/api/whatsapp-sessions/$WASENDER_SESSION_ID" \
-H "Authorization: Bearer $WASENDER_PAT" | jq '.data.webhook_url'
Should return the Render URL.
The user has to set the webhook URL via the dashboard. Tell them (in Hebrew):
עכשיו רק תעדכן את ה-Webhook ב-Wasender ידנית:
- גש ל-https://wasenderapi.com/dashboard ופתח את הסשן שלך.
- לחץ על Manage Webhook (כפתור ימני עליון).
- הדבק את הכתובת הזו בשדה Webhook URL:
{RENDER_URL}/webhook/wasender- סמן את האירוע
messages.received(וגםsession.statusאם רוצים התראה על ניתוקים).- חשוב: וודא שהשדה Webhook Secret זהה למה שיש ב-
.envשלך (WASENDER_WEBHOOK_SECRET). אם לא, או החלף את אחד מהם, או צור חדש בשני המקומות.- לחץ Save.
תגיד לי "שמרתי" ואבדוק שהכל עובד.
Wait for confirmation. Then proceed to step 8.
Tell the user:
הכל מוכן. שלח עכשיו הודעה אמיתית מהטלפון שלך אל {WASENDER_PHONE}. אני אבדוק שהבוט קיבל וענה.
Wait 30 seconds. Then check Render logs:
curl -s "https://api.render.com/v1/services/$RENDER_SERVICE_ID/logs?limit=20" \
-H "Authorization: Bearer $RENDER_API_KEY"
Look for the inbound webhook line. If found and the user confirms they received a reply on their phone:
🚀 הבוט שלך חי! מספר {WASENDER_PHONE} עונה עכשיו אוטומטית.
If no inbound seen after 60 seconds, run the diagnostic from wa-maintain (don't make the user wait — proactively diagnose).
Update .wa-state.json:
{
"current_stage": "connect",
"completed_stages": ["setup", "characterize", "build", "deploy"],
"render_service_id": "<id>",
"render_url": "<url>",
"last_updated": "<ISO>"
}
Tell the user:
השלבים הבאים אופציונליים — להוסיף לבוט יכולות נוספות (יומן, מייל, תזכורות מתמשכות) או לבחור איפה ההיסטוריה נשמרת. רוצה להמשיך, או לעצור כאן?
If they want more: route to wa-connect. If stop: route to wa-maintain (idle mode).
404 Not Found (10 bytes, plain text) for ~10–60s while the service is still spinning up internally. The deploy-status API may already say live while curl gets 404s. Don't panic and don't redeploy — wait 30s and retry /healthz. If it's still 404 after 90s, then something is genuinely wrong (check GET /v1/services/{id} for suspended, and check deploy events)..python-version and/or set PYTHON_VERSION=3.12.7 env var on the service.WASENDER_WEBHOOK_SECRET env var on Render matches the one Wasender returned at session-create time. If user regenerated the secret in dashboard, update both Render env and bot/.env locally.POST /api/whatsapp-sessions/{id}/webhook (some accounts have a dedicated webhook endpoint — verify in their dashboard).account_protection: true, the bot can only send 1 message per 5 seconds. If a long reply gets split into multiple sends (or there's a burst), they'll queue. Mention this if user complains "the bot sometimes feels slow."Provides behavioral guidelines to reduce common LLM coding mistakes, focusing on simplicity, surgical changes, assumption surfacing, and verifiable success criteria.
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
npx claudepluginhub jackvidal/whatsapp-agent-builder --plugin whatsapp-agent-builder