Overview
Saved Replies are pre-written response templates that agents can use to quickly respond to common ticket scenarios. They support template variables and can be scoped globally, to specific teams, or as personal templates.
Saved Reply DocType Fields
The HD Saved Reply DocType contains the following fields:
Unique title for the saved reply
Template content with support for Jinja2 variables
Visibility scope: Global, Team, or Personal
List of teams that can access this reply (when scope is Team)
Template Variables
Saved reply messages support Jinja2 templating with access to:
Ticket Fields
All HD Ticket fields are available:
{{ subject }} - Ticket subject
{{ description }} - Ticket description
{{ status }} - Ticket status
{{ priority }} - Ticket priority
{{ raised_by }} - Customer email
- And all other ticket fields
User Fields
All User fields for the current agent:
{{ full_name }} - Agent’s full name
{{ email }} - Agent’s email
{{ phone }} - Agent’s phone number
- And all other user fields
Get Rendered Saved Reply
Render a saved reply template with ticket and user context.
This endpoint is defined in helpdesk/api/saved_replies.py:7 and is restricted to agents only
@frappe.whitelist()
@agent_only
def get_rendered_saved_reply(ticket_id: str | int, saved_reply_id: str | None = None):
"""Render a saved reply template
Combines saved reply template with ticket and user data.
Args:
ticket_id: ID of the ticket context
saved_reply_id: ID of the saved reply to render
Returns:
Rendered HTML string with variables replaced
"""
The ticket ID to use as context for template rendering
The saved reply ID to render
Response
Returns the rendered HTML string with all template variables replaced with actual values from the ticket and current user.
Template Context
The template is rendered with two data sources merged:
- Ticket data: All fields from the HD Ticket document
- User data: All fields from the current user’s User document
Error Handling
Throws an error if saved_reply_id is not provided:
- Message: “Please provide saved_reply_id”
Example Request
import frappe
# Render a saved reply for a specific ticket
rendered = frappe.call(
"helpdesk.api.saved_replies.get_rendered_saved_reply",
ticket_id="12345",
saved_reply_id="Password Reset Instructions"
)
print(rendered)
# Output: "<p>Dear customer, we've received your request...</p>"
Example Template
Saved Reply message:
<p>Dear {{ raised_by }},</p>
<p>Thank you for contacting us regarding: <strong>{{ subject }}</strong></p>
<p>I'm {{ full_name }}, and I'll be assisting you with this {{ priority }} priority ticket.</p>
<p>Best regards,<br>
{{ full_name }}<br>
{{ email }}</p>
Rendered output:
<p>Dear [email protected],</p>
<p>Thank you for contacting us regarding: <strong>Cannot login to my account</strong></p>
<p>I'm John Smith, and I'll be assisting you with this High priority ticket.</p>
<p>Best regards,<br>
John Smith<br>
[email protected]</p>
Create Saved Reply
Create a new saved reply template:
import frappe
# Create a global saved reply
saved_reply = frappe.get_doc({
"doctype": "HD Saved Reply",
"title": "Welcome Message",
"scope": "Global",
"message": """<p>Hi {{ raised_by }},</p>
<p>Thank you for contacting support. We've received your ticket
regarding {{ subject }} and will respond within 24 hours.</p>
<p>Best regards,<br>{{ full_name }}</p>"""
})
saved_reply.insert()
print(f"Created: {saved_reply.name}")
Create Team-Scoped Reply
import frappe
# Create a team-specific saved reply
saved_reply = frappe.get_doc({
"doctype": "HD Saved Reply",
"title": "Technical Support Greeting",
"scope": "Team",
"message": "<p>Technical support response template...</p>"
})
# Add teams
saved_reply.append("teams", {
"team": "Technical Support"
})
saved_reply.append("teams", {
"team": "Engineering"
})
saved_reply.insert()
Create Personal Reply
import frappe
# Create a personal saved reply (only visible to creator)
saved_reply = frappe.get_doc({
"doctype": "HD Saved Reply",
"title": "My Personal Template",
"scope": "Personal",
"message": "<p>Personal template content...</p>"
})
saved_reply.insert()
List Saved Replies
Query saved replies with scope filtering:
import frappe
# Get all global saved replies
global_replies = frappe.get_list(
"HD Saved Reply",
filters={"scope": "Global"},
fields=["name", "title", "message"],
order_by="title asc"
)
for reply in global_replies:
print(f"{reply.title}")
Get Replies for Current User’s Team
import frappe
# Get current agent's team
agent = frappe.get_doc("HD Agent", frappe.session.user)
# Get team-specific replies
team_replies = frappe.get_list(
"HD Saved Reply Team",
filters={"team": agent.agent_group},
fields=["parent"],
pluck="parent"
)
for reply_id in team_replies:
reply = frappe.get_doc("HD Saved Reply", reply_id)
print(f"{reply.title}")
Update Saved Reply
import frappe
# Update saved reply content
reply = frappe.get_doc("HD Saved Reply", "Welcome Message")
reply.message = "<p>Updated template content...</p>"
reply.save()
Delete Saved Reply
import frappe
frappe.delete_doc("HD Saved Reply", "Old Template")
Scope Behavior
Global Scope
- Visible to all agents
- Can be used on any ticket
- Typically used for common responses
Team Scope
- Visible only to agents in specified teams
- Multiple teams can be selected
- Useful for department-specific responses
Personal Scope
- Only visible to the creator
- Private templates for individual agent use
Settings Control
The HD Settings DocType has a field that controls saved reply scope:
import frappe
# Disable global scope for saved replies
frappe.db.set_value(
"HD Settings",
"HD Settings",
"disable_saved_replies_global_scope",
1
)
When disable_saved_replies_global_scope is enabled, only team and personal saved replies are available.
Advanced Template Example
<p>Hi {{ raised_by.split('@')[0].title() }},</p>
<p>I hope this email finds you well.</p>
{% if priority == "High" %}
<p><strong>We've marked this as a high priority ticket and will prioritize our response.</strong></p>
{% endif %}
<p>Regarding your ticket: <em>{{ subject }}</em></p>
<p>{{ description[:100] }}...</p>
<p>We'll investigate this issue and get back to you shortly.</p>
<p>Ticket Details:</p>
<ul>
<li>Ticket ID: {{ name }}</li>
<li>Status: {{ status }}</li>
<li>Created: {{ creation.strftime('%B %d, %Y at %I:%M %p') }}</li>
</ul>
<p>Best regards,<br>
{{ full_name }}<br>
{{ email }}</p>
Permissions
Saved Reply permissions:
- Agent Role: Create, read, update, delete
- Agent Manager Role: Create, read, update, delete
- System Manager: Full access
Standard Frappe API Methods
frappe.get_doc("HD Saved Reply", reply_id) - Get single reply
frappe.get_list("HD Saved Reply", filters={...}) - Query replies
frappe.delete_doc("HD Saved Reply", reply_id) - Delete reply