> For clean Markdown of any page, append .md to the page URL. > For a complete documentation index, see https://docs.agentphone.ai/documentation/reference/testing/llms.txt. > For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.agentphone.ai/_mcp/server. # Testing > Test webhooks locally, use mock payloads, and verify your integration This guide covers how to test your AgentPhone integration during development, including local webhook testing and mock payloads. ## Testing webhooks locally To receive webhooks during development, you need to expose your local server to the internet. We recommend ngrok. ### Using ngrok ### Install ngrok Download from [ngrok.com](https://ngrok.com/download), or install via Homebrew: ```bash brew install ngrok ``` ### Start your local server ```bash python app.py # or node server.js ``` ### Expose your local port In a separate terminal: ```bash ngrok http 3000 ``` Copy the HTTPS URL (e.g., `https://abc123.ngrok.io`). ### Register the URL as your webhook ```bash curl -X POST "https://api.agentphone.ai/v1/webhooks" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url": "https://abc123.ngrok.io/webhook"}' ``` ### Send a test webhook ```bash curl -X POST "https://api.agentphone.ai/v1/webhooks/test" \ -H "Authorization: Bearer YOUR_API_KEY" ``` ### Using localtunnel ```bash npm install -g localtunnel lt --port 3000 ``` Use the provided URL as your webhook URL. > **Warning** > > Free ngrok accounts have session limits. The tunnel will disconnect and you'll need to restart ngrok and update your webhook URL. For persistent tunnels, consider a paid ngrok plan or deploying to a cloud service. ## Test webhook endpoint Use the test endpoint to verify your webhook handler is working correctly. This sends a sample `agent.message` payload to your configured URL: ```bash curl -X POST "https://api.agentphone.ai/v1/webhooks/test" \ -H "Authorization: Bearer YOUR_API_KEY" ``` ```json { "success": true, "httpStatus": 200, "errorMessage": null } ``` You can also test per-agent webhooks: ```bash curl -X POST "https://api.agentphone.ai/v1/agents/agt_abc123/webhook/test" \ -H "Authorization: Bearer YOUR_API_KEY" ``` ## Mock webhook payloads Use these sample payloads to test your webhook handler locally with `curl` or in your test suite. ### SMS payload ```json { "event": "agent.message", "channel": "sms", "timestamp": "2025-12-03T10:05:00Z", "agentId": "agent_123", "data": { "conversationId": "conv_test456", "numberId": "num_abc", "from": "+14155551234", "to": "+18571234567", "message": "Test message", "direction": "inbound", "receivedAt": "2025-12-03T10:05:00Z" }, "conversationState": { "testMode": true }, "recentHistory": [ { "content": "Hello", "direction": "inbound", "channel": "sms", "at": "2025-12-03T10:04:00Z" } ] } ``` ### Voice payload ```json { "event": "agent.message", "channel": "voice", "timestamp": "2025-12-03T10:05:00Z", "agentId": "agent_123", "data": { "callId": "call_abc123", "numberId": "num_abc", "from": "+14155551234", "to": "+18571234567", "status": "in-progress", "transcript": "I need help with my order", "confidence": 0.95, "direction": "inbound" }, "conversationState": null, "recentHistory": [ { "content": "Hello, how can I help?", "direction": "outbound", "channel": "voice", "at": "2025-12-03T10:04:30Z" } ] } ``` ### Testing with curl Send a mock payload to your local server: ```bash curl -X POST http://localhost:3000/webhook \ -H "Content-Type: application/json" \ -d '{ "event": "agent.message", "channel": "voice", "agentId": "agent_123", "data": { "callId": "call_test", "from": "+14155551234", "to": "+18571234567", "transcript": "What are your hours?", "confidence": 0.95, "direction": "inbound" }, "conversationState": null, "recentHistory": [] }' ``` ## Example test handlers ### Python (Flask) ```python from flask import Flask, request, jsonify app = Flask(__name__) @app.route('/webhook', methods=['POST']) def webhook(): payload = request.json channel = payload.get('channel') data = payload.get('data', {}) if channel == 'sms': print(f"SMS from {data['from']}: {data['message']}") return jsonify({'status': 'ok'}), 200 if channel == 'voice': print(f"Voice from {data['from']}: {data['transcript']}") return jsonify({'text': f"I heard: {data['transcript']}"}), 200 return jsonify({'status': 'ok'}), 200 if __name__ == '__main__': app.run(port=3000) ``` ### Node.js (Express) ```javascript const express = require('express'); const app = express(); app.use(express.json()); app.post('/webhook', (req, res) => { const { channel, data } = req.body; if (channel === 'sms') { console.log(`SMS from ${data.from}: ${data.message}`); return res.status(200).json({ status: 'ok' }); } if (channel === 'voice') { console.log(`Voice from ${data.from}: ${data.transcript}`); return res.status(200).json({ text: `I heard: ${data.transcript}` }); } res.status(200).json({ status: 'ok' }); }); app.listen(3000, () => console.log('Webhook server on port 3000')); ``` ## Checking webhook deliveries Monitor delivery status to debug issues: ```bash curl "https://api.agentphone.ai/v1/webhooks/deliveries?limit=10" \ -H "Authorization: Bearer YOUR_API_KEY" ``` The response shows delivery attempts, HTTP status codes, error messages, and retry timestamps. Use this to verify your endpoint is receiving and acknowledging webhooks correctly. > Test webhooks locally, use mock payloads, and verify your integration