Claude Code Integration
Integrate Ping with Claude Code to get push notifications when Claude finishes tasks or needs approval for deploy commands.
Use Cases
- Long-running tasks - Get notified when Claude finishes a big refactor
- Background agents - Fire off a task and get pinged when it's done
- Deploy approvals - Approve deployments from your phone before they run
- Security alerts - Get notified when Claude runs potentially risky commands
Quick Setup
- Create a channel for Claude Code notifications in the Ping app
- Copy your webhook token
- Add to your project's
.claude/settings.json:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "export PING_WEBHOOK_TOKEN=YOUR_TOKEN && python3 \"$CLAUDE_PROJECT_DIR/.claude/hooks/deploy-approval.py\"",
"timeout": 310
}
]
}
],
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "python3 \"$CLAUDE_PROJECT_DIR/.claude/hooks/ping-notify.py\"",
"timeout": 10
}
]
}
]
}
}- Copy the hook scripts to your
.claude/hooks/directory (available in the Ping repository)
Deploy Approval Flow
When enabled, the deploy approval hook:
- Detects deploy commands (
git push,railway up,vercel deploy, etc.) - Sends a notification to your phone with Approve/Reject buttons
- Waits up to 5 minutes for your response
- If approved: runs the command
- If rejected: blocks the command
This uses Ping's callback polling API - no external server or ngrok required.
Sending Interactive Notifications
To send approve/reject buttons (or any interactive control) from a hook, POST an
actions array to the webhook endpoint. Buttons use a key (the identifier
returned in the result); only url actions use value (the link to open). This
is the most common point of confusion — see the full schema in
Interactive Actions.
{
"title": "Deploy to production?",
"body": "git push origin main",
"priority": "high",
"actions": [
{"type": "button", "label": "Approve", "key": "approve", "style": "primary"},
{"type": "button", "label": "Reject", "key": "reject", "style": "destructive"}
]
}Preview
Deploy to production?
just nowReading the response — two ways. The polling flow (what deploy-approval.py
uses, no server required) sends the payload above without a callback_url,
takes the message_id from the /v1/send response, and polls
GET /v1/callback/{token}/{message_id} until the tapped action comes back.
Alternatively, add a callback_url pointing at your own HTTPS endpoint and
Ping will POST the result there instead — don't point it at Ping's own
/v1/callback route, which is the read-only polling endpoint, not a sink.
The deploy-approval.py hook above already builds the polling payload for you;
reach for the raw schema only when you want custom controls (text input,
selects, toggles).
Available Hooks
| Hook | Event | Description |
|---|---|---|
ping-notify.py | Stop | Notification when Claude finishes working |
ping-notify.py | SessionEnd | Notification when session terminates |
ping-notify.py | Notification | Alert when Claude needs input |
deploy-approval.py | PreToolUse | Self-contained deploy approval (polls Ping for response) |
Minimal Completion Hook
For simple "Claude finished" notifications:
#!/usr/bin/env python3
import os
import sys
import json
import urllib.request
def send_notification():
token = os.environ.get('PING_WEBHOOK_TOKEN')
if not token:
return
payload = json.dumps({
'title': 'Claude Finished',
'body': 'Claude Code completed working on your task'
}).encode()
req = urllib.request.Request(
f'https://ping-api-production.up.railway.app/v1/send/{token}',
data=payload,
headers={'Content-Type': 'application/json'}
)
try:
urllib.request.urlopen(req, timeout=5)
except Exception:
pass
if __name__ == '__main__':
send_notification()For detailed documentation, see the Claude Code Hooks Guide in the Ping repository.