Tutorial 5 - Gracefully Handling Operating Hours During Handoff
Learn how to gracefully handle operating hours in bot-to-human handoff scenarios with Pingstreams.
Fork the Tutorial Code
Section titled “Fork the Tutorial Code”We’ll start from Tutorial 1 - Dialogflow as external chatbot, building on the foundation and adding operating hours awareness.
You must use the code in Tutorial 1. The code is available on Github here.
Fork the tutorial code using the Fork button. Now you have a copy of the tutorial on your own repo.
Introduction
Section titled “Introduction”What happens if, while you switch to the human operator, your support team is outside of operating hours? The request will be placed in the unserved queue and will become served as soon as your team becomes available again. Meanwhile you should notify the user that the request will be taken in some hours, or probably the day after. So, telling “I’m putting you in touch with an operator” is not enough.
How can you write a handoff message that depends on operating hours? You can mix Dialogflow message fulfillment and Pingstreams APIs to reach your goal.
Enable Agent Fulfillment
Section titled “Enable Agent Fulfillment”Open Dialogflow dashboard on your agent, then in the menu Fulfillment option enable “Webhook” option. In the URL field insert your heroku app url where you published your app followed by /dfwebhook and your project_id:

This “webhook” endpoint is already provided in the script:
// Tutorial 5 - Webhook for Bot-to-Agent handoff message based on opening hours
app.post('/dfwebhook/:project_id', (req, res) => {
const fulfillmentText = req.body.queryResult.fulfillmentText;
console.log("fulfillmentText:", fulfillmentText);
const languageCode = req.body.queryResult.languageCode;
console.log("languageCode:", languageCode);
// replace the following with your project id
const project_id = req.params.project_id;
const intent = req.body.queryResult.intent.displayName.toUpperCase();
if (intent === "TALK TO AGENT") {
const psClient = new PingstreamsClient();
psClient.openNow(function(isopen) {
var df_res = {};
if (isopen) {
df_res['fulfillmentText'] = "We are open! Switching to agent\\agent";
} else {
df_res['fulfillmentText'] = "I'm sorry but we are closed right now.";
}
res.status(200).send(JSON.stringify(df_res));
});
}
});This endpoint uses a project_id in the webhook URL that you must replace with your own.
Re-train the ‘Talk to Agent’ Intent to Use Fulfillment
Section titled “Re-train the ‘Talk to Agent’ Intent to Use Fulfillment”Fulfillment is not automatically active on the intents. You must activate it for each intent that you want to reply dynamically. We will re-train the ‘talk to agent’ intent to use our webhook to reply, instead of the static response.
Switch to the intent UI from Dialogflow dashboard, then go to the form bottom and switch to “on” the fulfillment button, as in the following picture:

Configure Operating Hours in Pingstreams
Section titled “Configure Operating Hours in Pingstreams”Now go to your project in Pingstreams dashboard and activate operating hours, taking care to set offline the interval when you ask the bot to switch to human agents. If you try to switch to human operators during offline hours you will get the following message:

Enhanced Operating Hours Logic
Section titled “Enhanced Operating Hours Logic”You can enhance the basic operating hours check with more sophisticated logic:
Different Messages by Time Zone
Section titled “Different Messages by Time Zone”app.post('/dfwebhook/:project_id', (req, res) => {
const intent = req.body.queryResult.intent.displayName.toUpperCase();
if (intent === "TALK TO AGENT") {
const psClient = new PingstreamsClient();
const userTimezone = req.body.queryResult.parameters.timezone || 'UTC';
psClient.openNow(userTimezone, function(isopen, nextOpenTime) {
var df_res = {};
if (isopen) {
df_res['fulfillmentText'] = "We are open! Connecting you to an agent now.\\agent";
} else {
const nextOpen = new Date(nextOpenTime).toLocaleString();
df_res['fulfillmentText'] = `We are currently closed. Our next available time is ${nextOpen}. Would you like to leave a message?`;
}
res.status(200).send(JSON.stringify(df_res));
});
}
});Queue Status Awareness
Section titled “Queue Status Awareness”app.post('/dfwebhook/:project_id', (req, res) => {
const intent = req.body.queryResult.intent.displayName.toUpperCase();
if (intent === "TALK TO AGENT") {
const psClient = new PingstreamsClient();
psClient.getQueueStatus(function(queueInfo) {
var df_res = {};
if (queueInfo.isOpen && queueInfo.availableAgents > 0) {
df_res['fulfillmentText'] = "Connecting you to an available agent now!\\agent";
} else if (queueInfo.isOpen && queueInfo.queueLength < 5) {
df_res['fulfillmentText'] = `We are open but all agents are busy. Current wait time is approximately ${queueInfo.estimatedWait} minutes.\\agent`;
} else if (queueInfo.isOpen) {
df_res['fulfillmentText'] = "We are experiencing high volume. Would you prefer to schedule a callback or continue waiting?";
} else {
df_res['fulfillmentText'] = "We are currently closed. Our support hours are 9 AM to 5 PM, Monday through Friday.";
}
res.status(200).send(JSON.stringify(df_res));
});
}
});Best Practices
Section titled “Best Practices”Clear Communication
Section titled “Clear Communication”- Always inform users about current status (open/closed)
- Provide specific information about when agents will be available
- Offer alternatives when agents are unavailable
Graceful Degradation
Section titled “Graceful Degradation”- Collect user information for follow-up when closed
- Offer self-service options during off-hours
- Provide clear escalation paths for urgent issues
User Experience
Section titled “User Experience”- Set appropriate expectations about response times
- Provide multiple contact options when available
- Maintain brand voice even in automated responses
Advanced Features
Section titled “Advanced Features”You can further enhance this system by:
- Holiday schedules: Account for special business hours during holidays
- Department-specific hours: Different operating hours for different support teams
- Urgency detection: Route urgent requests differently even during off-hours
- Callback scheduling: Allow users to schedule callbacks during business hours
- Multi-language support: Provide operating hours messages in multiple languages
This approach ensures that users always receive appropriate and helpful responses, regardless of when they need assistance.
Enjoy Pingstreams!