To integrate Freshdesk with Bolt.new, add your Freshdesk API key and domain to server-side environment variables, then create Next.js API routes that call Freshdesk's REST API using HTTP Basic Auth (API key as username, 'X' as password). You can create tickets from contact forms, fetch ticket lists for admin dashboards, and manage contacts — all from the Bolt preview. Incoming webhooks for ticket events require a deployed URL on Netlify or Bolt Cloud.
Integrating Freshdesk Helpdesk into Bolt.new Apps
Freshdesk is one of the easiest helpdesk APIs to integrate with Bolt.new because it uses HTTP Basic Auth with a plain API key — no OAuth flows, no token refresh logic, and no expiration to manage. Your API key (found in your profile settings) combined with the literal letter 'X' as the password is all you need to authenticate any Freshdesk API call. This simplicity makes Freshdesk an excellent choice for adding support ticket functionality to Bolt-built apps.
Freshdesk's free plan (up to 10 agents) includes complete API access, which means you can build and test a full helpdesk integration without paying anything. The free tier supports creating and reading tickets, managing contacts, accessing the knowledge base, and running canned response workflows — more than enough for most Bolt app integrations. When you need SLA management, automation rules, or team collision detection, the paid tiers start at $15/agent/month.
The main Freshdesk integration patterns for Bolt apps are: a contact form that creates tickets (so users can submit support requests without leaving your app), a ticket dashboard for admins to monitor and respond to open tickets, and a knowledge base search widget that lets users find answers before reaching out to support. All three patterns use outbound API calls that work from Bolt's WebContainer preview. Freshdesk webhooks — for triggering actions when a ticket changes status, receives a reply, or is escalated — require a deployed URL, as the WebContainer cannot receive incoming HTTP requests from Freshdesk's servers.
Integration method
Freshdesk integrates with Bolt.new through its REST API using simple HTTP Basic Auth — your API key as the username and the letter 'X' as the password. Create tickets from contact forms, manage contacts, fetch ticket queues for admin dashboards, and build custom helpdesk interfaces using Next.js API routes that proxy requests to Freshdesk's API. The API key must be kept server-side to prevent unauthorized ticket creation. Freshdesk's free plan supports up to 10 agents and includes full API access.
Prerequisites
- A Freshdesk account (free plan available for up to 10 agents at freshdesk.com)
- Your Freshdesk API key (found in your profile picture → Profile Settings → API Key in the Freshdesk dashboard)
- Your Freshdesk domain (the yourcompany.freshdesk.com subdomain you chose when signing up)
- A Bolt.new project using Next.js for server-side API routes
- For webhooks and automation triggers: a deployed URL from Netlify or Bolt Cloud
Step-by-step guide
Get Your Freshdesk API Key
Get Your Freshdesk API Key
Freshdesk provides a personal API key for each agent. Log into your Freshdesk account, click your profile picture in the top-right corner, and select 'Profile Settings'. On your profile page, scroll to the 'API Key' section on the right side. Your API key is displayed here — it's a 20+ character alphanumeric string. Click the eye icon to reveal it if it's hidden, then copy it. If you don't see an API key section, your plan may not include API access, or you may need to enable it in the Admin settings. Your Freshdesk domain is the subdomain you use to access your account — if you go to https://yourcompany.freshdesk.com, then 'yourcompany' is your domain. Store your API key as a server-side environment variable (no NEXT_PUBLIC_ prefix). Freshdesk API calls use HTTP Basic Auth where the username is your API key and the password is the literal letter 'X' — this unusual convention is specific to Freshdesk and is documented in their API reference. Never expose your API key in client-side code — it gives anyone read and write access to all your tickets and customer data.
1# .env2FRESHDESK_API_KEY=your_api_key_here3FRESHDESK_DOMAIN=yourcompanyPro tip: Generate a dedicated API key for your Bolt integration from a system account rather than using your personal API key. This way you can revoke access without affecting your personal Freshdesk login.
Expected result: Your Freshdesk API key and domain are stored in .env as FRESHDESK_API_KEY and FRESHDESK_DOMAIN. You can test the API key with a simple curl: curl -u YOUR_API_KEY:X https://yourcompany.freshdesk.com/api/v2/tickets
Create the Freshdesk API Client Helper
Create the Freshdesk API Client Helper
Build a reusable helper that handles Freshdesk API calls with proper authentication. The helper accepts an endpoint path and request options, adds the Base64-encoded Basic Auth header, and returns the response JSON. Centralizing this logic means all API routes share the same auth pattern and you only need to change credentials in one place. Freshdesk's API base URL is https://{domain}.freshdesk.com/api/v2/. Common endpoints are /tickets (create and list tickets), /contacts (manage contact records), /solution/articles (knowledge base articles), and /agents (list agents for assignment). For Basic Auth with Freshdesk, encode 'API_KEY:X' in Base64. The colon and 'X' are always part of the encoding — Freshdesk ignores the password field and only validates the API key. Error responses from Freshdesk's API are returned as JSON with a 'description' field and an 'errors' array. Parse these carefully since Freshdesk returns different error formats depending on the type of validation failure.
Create a Freshdesk API helper in lib/freshdesk.ts that exports a freshdeskAPI function. It takes an endpoint string (e.g., '/tickets') and optional RequestInit options. It builds the Basic Auth header by base64-encoding FRESHDESK_API_KEY + ':X', sets the Accept and Content-Type headers to application/json, calls https://${FRESHDESK_DOMAIN}.freshdesk.com/api/v2${endpoint}, and returns the response JSON. Throw an error with the Freshdesk error description if the response is not ok.
Paste this in Bolt.new chat
1// lib/freshdesk.ts2const FRESHDESK_BASE = `https://${process.env.FRESHDESK_DOMAIN}.freshdesk.com/api/v2`;34function getFreshdeskHeaders() {5 const auth = Buffer.from(`${process.env.FRESHDESK_API_KEY}:X`).toString('base64');6 return {7 Authorization: `Basic ${auth}`,8 'Content-Type': 'application/json',9 Accept: 'application/json',10 };11}1213export async function freshdeskAPI<T>(14 endpoint: string,15 options: RequestInit = {}16): Promise<T> {17 const url = `${FRESHDESK_BASE}${endpoint}`;18 const response = await fetch(url, {19 ...options,20 headers: {21 ...getFreshdeskHeaders(),22 ...options.headers,23 },24 });2526 if (!response.ok) {27 const error = await response.json().catch(() => ({ description: response.statusText }));28 throw new Error(29 error.description || `Freshdesk API error: ${response.status}`30 );31 }3233 // 204 No Content for DELETE operations34 if (response.status === 204) return {} as T;3536 return response.json();37}Pro tip: Freshdesk paginates lists with 30 items per page by default. Add ?per_page=100&page=1 query parameters when fetching tickets or contacts to get larger result sets.
Expected result: lib/freshdesk.ts exports a typed freshdeskAPI helper. All API routes use this helper for authenticated Freshdesk calls. The Basic Auth header is constructed correctly with API_KEY:X encoding.
Create Tickets from a Contact Form
Create Tickets from a Contact Form
The most common Freshdesk integration for Bolt apps is a contact form that creates support tickets. When a user submits a help request, your API route receives the form data and creates a Freshdesk ticket via the API. Freshdesk tickets require at minimum a subject, description, email (requester), and status (2 = open). Priority is optional but recommended: 1 = low, 2 = medium, 3 = high, 4 = urgent. When you create a ticket, Freshdesk automatically sends a confirmation email to the requester with the ticket number — this is one of the biggest benefits of using Freshdesk over a simple email form. You can also assign the ticket to a specific agent or group by including the responder_id or group_id fields. Tag tickets with custom labels (the tags array) to categorize them — for example, tagging tickets from your Bolt app as 'bolt-app' helps filter them from manually created tickets in the Freshdesk inbox. Always validate user input before sending to Freshdesk — empty subjects, invalid emails, or descriptions over 65,535 characters will result in 400 errors from the API.
Create a Next.js API route at /api/freshdesk/tickets. Handle POST requests to create new tickets: accept subject, description, email, and priority (1-4) from the request body, validate that subject, description, and email are present, then use the freshdeskAPI helper to POST to /tickets. Also handle GET requests to fetch open tickets for the admin dashboard: call /tickets?status=2 (open) to get the ticket list sorted by created_at. Return appropriate error messages if validation fails.
Paste this in Bolt.new chat
1// app/api/freshdesk/tickets/route.ts2import { NextResponse } from 'next/server';3import { freshdeskAPI } from '@/lib/freshdesk';45interface FreshdeskTicket {6 id: number;7 subject: string;8 description: string;9 status: number;10 priority: number;11 requester_id: number;12 created_at: string;13}1415export async function POST(request: Request) {16 try {17 const { subject, description, email, priority = 2 } = await request.json();1819 if (!subject || !description || !email) {20 return NextResponse.json(21 { error: 'subject, description, and email are required' },22 { status: 400 }23 );24 }2526 if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {27 return NextResponse.json(28 { error: 'Invalid email address' },29 { status: 400 }30 );31 }3233 const ticket = await freshdeskAPI<FreshdeskTicket>('/tickets', {34 method: 'POST',35 body: JSON.stringify({36 subject,37 description,38 email,39 priority,40 status: 2, // Open41 source: 2, // Portal42 tags: ['bolt-app'],43 }),44 });4546 return NextResponse.json(47 { ticketId: ticket.id, message: 'Ticket created successfully' },48 { status: 201 }49 );50 } catch (error: unknown) {51 const e = error as { message: string };52 return NextResponse.json({ error: e.message }, { status: 500 });53 }54}5556export async function GET(request: Request) {57 try {58 const { searchParams } = new URL(request.url);59 const status = searchParams.get('status') || '2';60 const page = searchParams.get('page') || '1';6162 const tickets = await freshdeskAPI<FreshdeskTicket[]>(63 `/tickets?status=${status}&per_page=50&page=${page}&order_by=created_at&order_type=desc`64 );6566 return NextResponse.json(tickets);67 } catch (error: unknown) {68 const e = error as { message: string };69 return NextResponse.json({ error: e.message }, { status: 500 });70 }71}Pro tip: Freshdesk ticket status codes: 2=Open, 3=Pending, 4=Resolved, 5=Closed. Use numeric codes in API calls even though the dashboard shows text labels.
Expected result: POST to /api/freshdesk/tickets with subject, description, and email creates a Freshdesk ticket. The submitting user receives an email confirmation from Freshdesk. GET to the same route returns open tickets for the admin dashboard.
Build Ticket Dashboard and Knowledge Base Search
Build Ticket Dashboard and Knowledge Base Search
Complete the integration by building an admin ticket dashboard and a knowledge base search feature. The ticket dashboard queries the Freshdesk API for open tickets and displays them with status indicators, priority colors, and requester information. Agents can update ticket status directly from the dashboard using a PATCH request to Freshdesk's API. For knowledge base search, Freshdesk's Solutions API provides access to all your help articles by category and folder. The search endpoint (/search/solutions?term=query) returns matching articles with their titles and content previews. Display these in a dropdown or slide-over panel to help users self-serve before submitting a ticket. Remember that all Freshdesk API calls (both reads and writes) work from Bolt's WebContainer preview because they're outbound HTTPS calls — you don't need to deploy to test the full ticket creation and dashboard flow. Freshdesk's rate limit is 1,000 API calls per hour per account on most plans, and 10,000 on Enterprise. This is generous for dashboard use but be careful with bulk operations like importing many tickets.
Build the complete helpdesk admin UI. Create /admin/support with a ticket management table showing all open tickets from /api/freshdesk/tickets. Add color-coded priority badges (red=urgent, orange=high, yellow=medium, green=low). Clicking a ticket opens a detail panel showing the full description and conversation history. Add a status change dropdown (Open, Pending, Resolved, Closed) that calls PATCH /api/freshdesk/tickets/[id] to update the status. Also add a search bar at the top that searches knowledge base articles via /api/freshdesk/search?q=term and shows results inline.
Paste this in Bolt.new chat
1// app/api/freshdesk/search/route.ts2import { NextResponse } from 'next/server';3import { freshdeskAPI } from '@/lib/freshdesk';45interface SolutionArticle {6 id: number;7 title: string;8 description_text: string;9 folder_id: number;10}1112interface SearchResult {13 results: SolutionArticle[];14 total: number;15}1617export async function GET(request: Request) {18 const { searchParams } = new URL(request.url);19 const query = searchParams.get('q');2021 if (!query || query.trim().length < 2) {22 return NextResponse.json({ results: [] });23 }2425 try {26 const data = await freshdeskAPI<SearchResult>(27 `/search/solutions?term=${encodeURIComponent(query)}`28 );29 return NextResponse.json(data);30 } catch (error: unknown) {31 const e = error as { message: string };32 return NextResponse.json({ error: e.message }, { status: 500 });33 }34}Pro tip: Freshdesk knowledge base requires the Solutions feature to be enabled in your account. If the search endpoint returns 403, go to your Freshdesk admin panel and enable the Solutions module.
Expected result: The /admin/support dashboard shows real Freshdesk tickets with color-coded priority badges. Clicking a ticket shows full details. The knowledge base search returns relevant articles as users type. Status updates persist immediately in Freshdesk.
Common use cases
In-App Support Ticket Submission
Replace your email-based contact form with a Freshdesk ticket submission that creates properly formatted support tickets. Users submit a subject and description from your app; your API route creates a Freshdesk ticket with their email, assigns priority, and returns a ticket number for tracking. Customers get automatic email confirmation from Freshdesk with a ticket number.
Create a support ticket form component that lets users submit help requests. The form has fields: subject (text input), description (textarea), and priority (dropdown: Low, Medium, High, Urgent). On submit, call /api/freshdesk/tickets (POST) which creates a Freshdesk ticket using the FRESHDESK_API_KEY and FRESHDESK_DOMAIN env vars. Pass the authenticated user's email as the requester email. Return the ticket ID and confirmation number to display in a success message: 'Ticket #[id] submitted. Check your email for confirmation.'
Copy this prompt to try it in Bolt.new
Agent Ticket Management Dashboard
Build an internal admin dashboard that shows all open Freshdesk tickets sorted by priority and age. Support agents can see ticket status, read the conversation thread, and update ticket status without logging into Freshdesk directly. This is useful for embedding support workflows into internal tools built on Bolt.
Create an admin dashboard at /admin/support showing open Freshdesk tickets. Fetch tickets from /api/freshdesk/tickets which calls Freshdesk's API with status=open. Show tickets in a table with columns: ID, Subject, Requester Email, Priority (color-coded: red=urgent, orange=high, yellow=medium, green=low), Status, and Created date. Add filters for priority and status. Clicking a ticket row expands the ticket details and conversation thread below. Add buttons to update ticket status (Open, Pending, Resolved, Closed) that call /api/freshdesk/tickets/[id] PATCH.
Copy this prompt to try it in Bolt.new
Self-Service Knowledge Base Widget
Embed a knowledge base search widget in your Bolt app that queries Freshdesk's solution articles before users open a ticket. Reduce support volume by surfacing relevant help articles when users encounter problems. If no article answers the question, provide a fallback to the ticket submission form.
Build a help search widget component that appears as a floating button in the bottom-right corner of every page. When clicked, open a search panel. As the user types, call /api/freshdesk/search?q=query which searches Freshdesk's Solution Articles API. Show up to 5 matching articles as clickable links that open in a new tab. Show a 'No results found? Submit a ticket' button when there are no matching articles. The search should debounce for 300ms to avoid excessive API calls while typing.
Copy this prompt to try it in Bolt.new
Troubleshooting
Freshdesk API returns 401 Unauthorized for all requests
Cause: The HTTP Basic Auth credentials are wrong. The most common mistakes are using the wrong format for the password field, having extra whitespace in the API key, or base64-encoding the wrong string.
Solution: Freshdesk uses 'API_KEY:X' (literally the letter X as the password) for Basic Auth. The Base64 encoding must be of the string 'YOUR_API_KEY:X'. Verify your FRESHDESK_API_KEY environment variable contains exactly what's shown in your profile settings, with no leading or trailing spaces. Test with curl: curl -u YOUR_API_KEY:X https://yourcompany.freshdesk.com/api/v2/tickets
1// Correct Basic Auth for Freshdesk:2const auth = Buffer.from(`${process.env.FRESHDESK_API_KEY}:X`).toString('base64');3// Result: 'Authorization: Basic BASE64(apikey:X)'Ticket creation returns 422 Unprocessable Entity
Cause: The request body is missing required fields or contains invalid values. Freshdesk requires at minimum email, subject, and description (or description_html). Status and priority must be numeric codes, not strings.
Solution: Check the Freshdesk error response body — it contains an 'errors' array with specific field validation failures. Ensure email is a valid format, subject is a non-empty string, and description/description_html is provided. Priority must be 1, 2, 3, or 4 (not 'low', 'medium', etc.). Status must be 2, 3, 4, or 5.
1// Valid minimal ticket payload:2{3 email: 'user@example.com', // Required4 subject: 'Help with login', // Required5 description: 'I cannot...', // Required (or description_html)6 status: 2, // 2=Open (number, not string)7 priority: 2 // 2=Medium (number, not string)8}Freshdesk webhooks never fire when ticket status changes
Cause: Freshdesk webhooks require a publicly accessible URL. Bolt's WebContainer runs inside a browser tab with no public URL, so Freshdesk cannot deliver webhook payloads during development.
Solution: Deploy your app to Netlify or Bolt Cloud first. Then go to Freshdesk Admin → Automations → Ticket Creation / Ticket Updates → New Rule and set the webhook action URL to your deployed endpoint. Freshdesk automations support complex trigger conditions (ticket priority changes, status changes, new replies) that fire webhooks accordingly.
GET /tickets returns empty array but tickets exist in the Freshdesk dashboard
Cause: The API key belongs to an agent who doesn't have view permissions for all tickets, or the status filter excludes the tickets you're looking for.
Solution: Ensure the API key is from an admin account rather than a regular agent to see all tickets. Check the status parameter — the default API call returns only open tickets (status=2). Use status=all to fetch tickets of all statuses, or try without a status filter: /tickets?per_page=50.
1// Fetch tickets of all statuses:2const tickets = await freshdeskAPI('/tickets?per_page=50');3// Or fetch only open tickets explicitly:4const openTickets = await freshdeskAPI('/tickets?status=2&per_page=50');Best practices
- Store FRESHDESK_API_KEY as a server-side environment variable (no NEXT_PUBLIC_ prefix) — it grants read and write access to all tickets, contacts, and customer data
- Use Freshdesk's built-in email notifications rather than building your own — when you create a ticket via the API, Freshdesk automatically sends a confirmation email to the requester with their ticket number
- Tag tickets created through your Bolt app (e.g., tags: ['bolt-app', 'web-form']) to distinguish them from tickets created through other channels in the Freshdesk dashboard
- Validate email format and required fields client-side before calling your API route to avoid unnecessary API calls and provide faster user feedback
- Use Freshdesk's numeric status and priority codes (not strings) in API calls — the API rejects string values even if they match what the UI displays
- Cache knowledge base article searches for 5-10 minutes — article content rarely changes and caching reduces API calls significantly in busy apps
- Implement pagination for ticket lists from the start — Freshdesk paginates at 30 items per page by default and you'll hit this limit quickly in production
- Deploy early and test Freshdesk webhooks from your deployed URL — webhooks are essential for real-time ticket status updates and cannot be tested from Bolt's WebContainer
Alternatives
Zendesk has a larger marketplace, more advanced automation, and enterprise-grade SLAs — choose Zendesk when you need deep customization and are willing to pay more per agent.
Intercom combines helpdesk with proactive customer engagement, product tours, and AI chatbots — choose Intercom when you need more than ticket management and want to drive customer engagement.
LiveChat focuses on real-time chat rather than ticket management — choose LiveChat when your primary support channel is live chat and you don't need a full ticketing system.
Frequently asked questions
Is Freshdesk really free for up to 10 agents?
Yes. Freshdesk's Free plan supports up to 10 agents with email ticketing, knowledge base, ticket dispatch, team collaboration, and full API access. The API is not restricted on the free plan. Paid plans (Growth at $15/agent/month, Pro at $49, Enterprise at $79) add SLA management, automation, custom reports, and advanced analytics. The free plan is sufficient for building and testing most Bolt.new helpdesk integrations.
How do I find my Freshdesk domain name?
Your Freshdesk domain is the subdomain in your Freshdesk URL. If you access Freshdesk at https://acme.freshdesk.com, your domain is 'acme'. This is set when you first create your Freshdesk account and cannot be changed. Store it as FRESHDESK_DOMAIN in your .env file — it's used in every API call URL.
Can I create tickets without the user being a Freshdesk contact?
Yes. When you create a ticket with an email that doesn't exist as a contact, Freshdesk automatically creates a new contact record for that email address. The ticket is linked to the new contact. This means your contact form can accept any valid email — no pre-registration in Freshdesk is required.
How do I attach files to Freshdesk tickets created via the API?
File attachments in Freshdesk's API use multipart/form-data instead of JSON. Send the ticket fields as form fields and include files as attachment[] fields. This requires switching from JSON body to FormData in your API route: const form = new FormData(); form.append('subject', subject); form.append('attachments[]', fileBlob, filename);. Do not set Content-Type manually — fetch will set the multipart boundary automatically.
What's Freshdesk's API rate limit?
Freshdesk's API rate limit depends on your plan: Free plan allows 40 API calls per minute, Growth plan allows 60, Pro plan allows 160, and Enterprise plan allows 400. Rate limit information is returned in response headers (X-RateLimit-Remaining and X-RateLimit-Total). If you hit the limit, Freshdesk returns 429 Too Many Requests. For dashboards, add caching for ticket lists and avoid re-fetching on every page render.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation