Webhook Integration
Connect your backend to handle reasoning and business logic. Aployee sends you the conversation context; you return decisions and state updates.
How It Works
When you configure an assistant with reasoning_mode: "webhook", Aployee calls your endpoint after each user utterance. Your webhook runs asynchronously while the conversation agent keeps the dialogue flowing.
- User speaks, Aployee transcribes
- Aployee sends utterance + state + context to your webhook
- Your webhook processes and returns a reply + updated state
- Aployee blends the reply into the next natural turn
Webhook Request
Aployee POSTs JSON to your webhook URL with this structure:
// Aployee sends this to your webhook
POST /your-webhook-endpoint
Content-Type: application/json
{
"call_id": "call_abc123",
"assistant_id": "asst_xyz789",
"utterance": "What's my account balance?",
"state": {
"userId": "user_12345",
"authenticated": true,
"lastAction": "greeting"
},
"context": [
{ "role": "assistant", "content": "Hi! How can I help you today?" },
{ "role": "user", "content": "What's my account balance?" }
],
"timestamp": "2024-01-15T10:30:00Z"
}Request Fields
call_id- Unique identifier for this callassistant_id- The assistant handling the callutterance- What the user just saidstate- JSON object persisted across the callcontext- Recent dialogue historytimestamp- When the utterance was captured
Webhook Response
Your webhook returns JSON with an optional reply and updated state:
// Your webhook responds with
{
"reply": "Your current balance is $1,234.56. Is there anything else I can help with?",
"state": {
"userId": "user_12345",
"authenticated": true,
"lastAction": "balance_lookup",
"lastBalance": 1234.56
}
}Response Fields
reply- (Optional) What the assistant should saystate- Updated state for the next turn
If you omit reply, Aployee's conversation agent generates a response based on the assistant's personality.
Full Example
A complete webhook handler for a banking assistant:
import express from "express";
const app = express();
app.use(express.json());
app.post("/aployee-webhook", async (req, res) => {
const { utterance, state, context, call_id } = req.body;
// Authentication check
if (!state.authenticated) {
return res.json({
reply: "I'll need to verify your identity first. What's your account number?",
state: { ...state, awaitingAccountNumber: true }
});
}
// Handle balance inquiry
if (utterance.toLowerCase().includes("balance")) {
const balance = await fetchBalance(state.userId);
return res.json({
reply: `Your current balance is $${balance.toFixed(2)}. Anything else?`,
state: { ...state, lastBalance: balance, lastAction: "balance_lookup" }
});
}
// Handle transfer request
if (utterance.toLowerCase().includes("transfer")) {
return res.json({
reply: "I can help with that. How much would you like to transfer and to which account?",
state: { ...state, awaitingTransferDetails: true }
});
}
// No specific action - let Aployee's conversation agent handle it
return res.json({ state });
});
app.listen(3000, () => console.log("Webhook running on port 3000"));Best Practices
Keep it Fast
Your webhook runs async, but faster responses mean smoother conversations. Target under 500ms. Cache frequently accessed data.
Use State Wisely
Store only what you need in state. For heavy data, store IDs and fetch from your database when needed.
Let Aployee Handle Small Talk
Don't return replies for greetings, confirmations, or chitchat. Omit reply and let the conversation agent handle it.
Handle Errors Gracefully
If your backend fails, return a helpful message. Don't let exceptions bubble up and break the call.
Timeouts & Retries
- Timeout: Webhooks must respond within 10 seconds
- Retries: No automatic retries. If your webhook fails, the conversation agent continues without your input
- Fallback: If no reply is returned, the assistant responds naturally based on personality
Next steps
- • Set up MCP integration for tool calls
- • Configure assistant personality
- • Review API reference