bash
CONTEXT_FILE="/opt/ocana/openclaw/workspace/skills/billing-monitor/.context"
[ -f "$CONTEXT_FILE" ] && source "$CONTEXT_FILE"
# Then use: $OWNER_PHONE, $ADMIN_PHONE, $BILLING_LOG, $BILLING_FALLBACK_CONFIG, etc.
Any model. Detection and alerting are rule-based. No reasoning required.
Run when you see ANY of these in an API response:
text
your API key has run out of credits
insufficient balance
billing_error
payment_required
exceeded your current quota
HTTP 402
"type": "billing_error"
Only alert the owner if:
Routine health checks run silently. The owner does not need a "billing OK" message.
NOTE (Production): Netanel uses a proxy — billing-health-check cron has been REMOVED as not relevant. Only alert on actual API failure detected during real usage.
Send via WhatsApp (or preferred channel):
text
⚠️ Billing issue — I can't respond normally.
My API key ran out of credits (or was rate-limited).
Please top up or switch my API key in agent settings.
text
[PA Name] has a billing error.
Owner: [Owner Name]
Action: top up API credits or reassign key.
Time: [current timestamp]
config/billing-fallback.json existsfallback_model fieldopenclaw config set model "$FALLBACK_MODEL"If billing-fallback.json doesn't exist → skip this step and tell admin to configure it.
bash
LOG_DIR="$HOME/.openclaw/workspace/logs"
mkdir -p "$LOG_DIR"
# Append one line to the log file
echo "$(date -u +%Y-%m-%dT%H:%M:%SZ) BILLING_ERROR api_key_exhausted" \
>> "$LOG_DIR/billing-incidents.log"
Run this during heartbeat to catch billing issues before they cause failures:
bash
#!/bin/bash
# billing-check.sh
# Checks the LLM provider API key configured in env vars
set -e
LOG_DIR="$HOME/.openclaw/workspace/logs"
mkdir -p "$LOG_DIR"
TIMESTAMP=$(date -u +%Y-%m-%dT%H:%M:%SZ)
# Detect provider from env vars (check in order)
if [ -n "${ANTHROPIC_API_KEY:-}" ]; then
PROVIDER="Anthropic"
HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
-H "x-api-key: ${ANTHROPIC_API_KEY}" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d "{\"model\":\"claude-haiku-20240307\",\"max_tokens\":1,\"messages\":[{\"role\":\"user\",\"content\":\"ping\"}]}" \
https://api.anthropic.com/v1/messages 2>/dev/null)
elif [ -n "${OPENAI_API_KEY:-}" ]; then
PROVIDER="OpenAI"
HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
-H "Authorization: Bearer ${OPENAI_API_KEY}" \
-H "content-type: application/json" \
-d "{\"model\":\"gpt-4o-mini\",\"max_tokens\":1,\"messages\":[{\"role\":\"user\",\"content\":\"ping\"}]}" \
https://api.openai.com/v1/chat/completions 2>/dev/null)
elif [ -n "${GOOGLE_API_KEY:-}" ]; then
PROVIDER="Google"
HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
"https://generativelanguage.googleapis.com/v1beta/models?key=${GOOGLE_API_KEY}" 2>/dev/null)
else
echo "$TIMESTAMP SKIP no API key env var found" >> "$LOG_DIR/billing-incidents.log"
exit 0
fi
# Act on the HTTP status code
case "$HTTP_STATUS" in
200)
echo "$TIMESTAMP OK $PROVIDER" >> "$LOG_DIR/billing-incidents.log"
;;
402)
echo "$TIMESTAMP BILLING_ERROR $PROVIDER HTTP_402" >> "$LOG_DIR/billing-incidents.log"
echo "BILLING ERROR — run the 4-step response protocol above"
exit 1
;;
401)
echo "$TIMESTAMP AUTH_ERROR $PROVIDER HTTP_401" >> "$LOG_DIR/billing-incidents.log"
echo "AUTH ERROR — invalid API key, notify admin"
exit 1
;;
429)
echo "$TIMESTAMP RATE_LIMITED $PROVIDER HTTP_429" >> "$LOG_DIR/billing-incidents.log"
echo "RATE LIMITED — wait 60 seconds and retry. Not a billing issue."
exit 2
;;
*)
echo "$TIMESTAMP UNKNOWN $PROVIDER HTTP_$HTTP_STATUS" >> "$LOG_DIR/billing-incidents.log"
echo "UNKNOWN ERROR HTTP $HTTP_STATUS"
exit 1
;;
esac
HTTP status meanings:
200 → OK402 → Billing error → run 4-step protocol401 → Invalid key → notify admin429 → Rate limit (temporary) → wait and retry, do NOT trigger billing protocolCreate config/billing-fallback.json in your workspace:
json
{
"primary_provider": "your-primary-provider",
"primary_model": "your-primary-model",
"fallback_provider": "your-fallback-provider",
"fallback_model": "your-fallback-model",
"admin_phone": "+1XXXXXXXXXX",
"alert_channel": "whatsapp"
}
Replace placeholders with real values. Examples:
"primary_provider": "anthropic", "primary_model": "claude-haiku-20240307", "fallback_provider": "openai", "fallback_model": "gpt-4o-mini"Owner confirms credits are topped up.
Read the primary model name from config: bash
PRIMARY=$(python3 -c "
import json
with open('config/billing-fallback.json') as f:
print(json.load(f)['primary_model'])
")
Switch back to primary: bash
openclaw config set model "$PRIMARY"
Log the recovery: bash
echo "$(date -u +%Y-%m-%dT%H:%M:%SZ) BILLING_RESTORED" \
>> ~/.openclaw/workspace/logs/billing-incidents.log
Notify owner: "✅ Primary model restored. Normal service resumed."
ScenarioAction429 rate limitWait 60s, retry. Do NOT trigger billing protocol.5xx server errorRetry 2x with 10s delay. If persists → notify owner.Both primary AND fallback billing errorsEscalate to admin immediately. Agent cannot function.No API key env var setLog as config issue. Notify admin.Peer PA reports billing errorLog it. Notify admin if you are the network coordinator.
curl — no LLM cost at allInstead of a plugin, run billing-monitor as a scheduled skill via cron:
json
{
"id": "billing-health-check",
"schedule": { "kind": "cron", "expr": "0 * * * *", "tz": "UTC" },
"sessionTarget": "isolated",
"payload": {
"kind": "agentTurn",
"message": "Run the billing-monitor skill: check all configured API keys for billing errors. If any provider returns 402, send an alert to the admin phone and update billing-status.json. Reply HEARTBEAT_OK if all clear."
},
"delivery": { "mode": "silent" }
}
This runs every hour and alerts automatically — no plugin required.