Try Live
Add Docs
Rankings
Pricing
Docs
Install
Theme
Install
Docs
Pricing
More...
More...
Try Live
Rankings
Enterprise
Create API Key
Add Docs
Freshservice API V2
https://github.com/sambegui/freshservice-api-v2-docs
Admin
The Freshservice API V2 provides programmatic access to Freshservice functionalities, enabling
...
Tokens:
1,013,886
Snippets:
2,748
Trust Score:
5.3
Update:
4 months ago
Context
Skills
Chat
Benchmark
60.1
Suggestions
Latest
Show doc for...
Code
Info
Show Results
Context Summary (auto-generated)
Raw
Copy
Link
# Freshservice API V2 Documentation ## Introduction Freshservice API V2 provides comprehensive REST endpoints for IT Service Management (ITSM) operations across Freshservice, Freshservice for Business Teams, and Freshservice for MSPs. This API enables developers to integrate service desk functionality into their applications, automating ticket management, asset tracking, change requests, problem management, and service catalog operations. The API follows RESTful principles with JSON payloads and supports OAuth 2.0 for select endpoints. This documentation repository contains complete API reference materials scraped from the official Freshservice API portal, organized into endpoint modules with detailed schemas, code examples in multiple languages (cURL, JavaScript, Python), and automated documentation generation scripts. The project maintains synchronized documentation through scheduled GitHub Actions workflows and deploys to GitHub Pages for easy access. All API requests require authentication via API key with Base64 encoding, and responses follow standard HTTP status codes with rate limiting at 1000 requests per hour. ## Authentication ### API Key Authentication All Freshservice API requests require Basic authentication with your API key encoded as `base64(api_key:X)`. ```bash # Export your credentials export FRESHSERVICE_DOMAIN="acme" export FRESHSERVICE_API_KEY="your_api_key_here" # List all tickets with proper authentication curl -X GET "https://${FRESHSERVICE_DOMAIN}.freshservice.com/api/v2/tickets" \ -H "Authorization: Basic $(printf '%s:X' "$FRESHSERVICE_API_KEY" | base64)" \ -H "Accept: application/json" \ -H "Content-Type: application/json" ``` ```javascript // JavaScript authentication helper const domain = process.env.FRESHSERVICE_DOMAIN; const apiKey = process.env.FRESHSERVICE_API_KEY; const auth = Buffer.from(`${apiKey}:X`).toString('base64'); async function fetchFromFreshservice(endpoint, method = 'GET', body = null) { const url = `https://${domain}.freshservice.com/api/v2/${endpoint}`; const options = { method, headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', 'Authorization': `Basic ${auth}` } }; if (body) { options.body = JSON.stringify(body); } const response = await fetch(url, options); if (!response.ok) { const error = await response.json(); throw new Error(`API Error ${response.status}: ${JSON.stringify(error)}`); } return await response.json(); } ``` ```python import os import requests from requests.auth import HTTPBasicAuth # Python authentication setup domain = os.environ.get("FRESHSERVICE_DOMAIN") api_key = os.environ.get("FRESHSERVICE_API_KEY") def freshservice_request(endpoint, method="GET", payload=None): url = f"https://{domain}.freshservice.com/api/v2/{endpoint}" try: response = requests.request( method, url, auth=HTTPBasicAuth(api_key, "X"), headers={ 'Accept': 'application/json', 'Content-Type': 'application/json' }, json=payload ) response.raise_for_status() return response.json() except requests.exceptions.HTTPError as e: print(f"HTTP Error: {e}") print(f"Response: {response.text}") raise ``` ## Tickets API ### Create a Ticket with Full Error Handling Create support tickets with comprehensive validation, custom fields, and multi-recipient CC support. ```javascript const domain = process.env.FRESHSERVICE_DOMAIN; const apiKey = process.env.FRESHSERVICE_API_KEY; async function createTicket(ticketData) { const url = `https://${domain}.freshservice.com/api/v2/tickets`; const auth = Buffer.from(`${apiKey}:X`).toString('base64'); const payload = { description: ticketData.description, subject: ticketData.subject, email: ticketData.requesterEmail, priority: ticketData.priority || 2, // 1=Low, 2=Medium, 3=High, 4=Urgent status: 2, // 2=Open, 3=Pending, 4=Resolved, 5=Closed source: ticketData.source || 2, // 2=Portal cc_emails: ticketData.ccEmails || [], custom_fields: ticketData.customFields || {}, workspace_id: ticketData.workspaceId || 3 }; try { const response = await fetch(url, { method: 'POST', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', 'Authorization': `Basic ${auth}` }, body: JSON.stringify(payload) }); if (!response.ok) { const errorBody = await response.json(); console.error('Ticket creation failed:', errorBody); throw new Error(`HTTP ${response.status}: ${errorBody.description || 'Unknown error'}`); } const data = await response.json(); console.log(`Ticket created successfully: ID=${data.ticket.id}, Display ID=${data.ticket.display_id}`); return data.ticket; } catch (error) { console.error('Failed to create ticket:', error.message); throw error; } } // Usage example const newTicket = await createTicket({ subject: "Login issues with SSO", description: "<p>Users are experiencing timeout errors when authenticating via SSO.</p>", requesterEmail: "john.doe@company.com", priority: 3, ccEmails: ["manager@company.com", "security@company.com"], customFields: { affected_systems: "Authentication Service", business_impact: "High" }, workspaceId: 3 }); ``` ```bash # cURL example with full ticket creation curl -v -u your_api_key:X \ -H "Content-Type: application/json" \ -X POST 'https://acme.freshservice.com/api/v2/tickets' \ -d '{ "description": "<p>Users are experiencing timeout errors when authenticating via SSO.</p>", "subject": "Login issues with SSO", "email": "john.doe@company.com", "priority": 3, "status": 2, "source": 2, "cc_emails": ["manager@company.com", "security@company.com"], "custom_fields": { "affected_systems": "Authentication Service", "business_impact": "High" }, "workspace_id": 3 }' # Expected Response: # { # "ticket": { # "id": 265, # "display_id": 265, # "subject": "Login issues with SSO", # "status": 2, # "priority": 3, # "requester_id": 1000000675, # "created_at": "2025-11-24T10:34:28Z", # "updated_at": "2025-11-24T10:34:28Z", # ... # } # } ``` ```python import os import requests from requests.auth import HTTPBasicAuth def create_ticket_with_validation(subject, description, requester_email, **kwargs): """ Create a Freshservice ticket with comprehensive error handling Args: subject: Ticket subject line description: HTML description of the issue requester_email: Email of person reporting the issue **kwargs: Additional fields (priority, cc_emails, custom_fields, etc.) Returns: dict: Created ticket object """ domain = os.environ.get("FRESHSERVICE_DOMAIN") api_key = os.environ.get("FRESHSERVICE_API_KEY") url = f"https://{domain}.freshservice.com/api/v2/tickets" payload = { "subject": subject, "description": description, "email": requester_email, "priority": kwargs.get("priority", 2), "status": 2, "cc_emails": kwargs.get("cc_emails", []), "custom_fields": kwargs.get("custom_fields", {}), "workspace_id": kwargs.get("workspace_id", 3) } try: response = requests.post( url, auth=HTTPBasicAuth(api_key, "X"), headers={'Accept': 'application/json', 'Content-Type': 'application/json'}, json=payload ) response.raise_for_status() ticket = response.json()["ticket"] print(f"✓ Ticket #{ticket['id']} created: {ticket['subject']}") return ticket except requests.exceptions.HTTPError as e: error_detail = e.response.json() if e.response.text else str(e) print(f"✗ Ticket creation failed: {error_detail}") raise # Example usage ticket = create_ticket_with_validation( subject="VPN connection dropping frequently", description="<p>VPN disconnects every 15 minutes requiring re-authentication.</p>", requester_email="alice@company.com", priority=3, cc_emails=["network-team@company.com"], custom_fields={"location": "Remote Office", "device_type": "Windows Laptop"} ) ``` ## Assets API ### Create and Track IT Assets Manage hardware and software assets with full lifecycle tracking including assignments and depreciation. ```javascript async function createAssetWithDetails(assetInfo) { const url = `https://${process.env.FRESHSERVICE_DOMAIN}.freshservice.com/api/v2/assets`; const auth = Buffer.from(`${process.env.FRESHSERVICE_API_KEY}:X`).toString('base64'); const payload = { name: assetInfo.name, asset_type_id: assetInfo.assetTypeId, asset_tag: assetInfo.assetTag, impact: assetInfo.impact || "low", // low, medium, high usage_type: assetInfo.usageType || "permanent", // permanent, loaner description: assetInfo.description, user_id: assetInfo.assignedUserId, location_id: assetInfo.locationId, department_id: assetInfo.departmentId, agent_id: assetInfo.managedByAgentId, group_id: assetInfo.managedByGroupId, assigned_on: assetInfo.assignedOn || new Date().toISOString(), workspace_id: assetInfo.workspaceId || 3, type_fields: { [`product_${assetInfo.assetTypeId}`]: assetInfo.productId, [`vendor_${assetInfo.assetTypeId}`]: assetInfo.vendorId, [`cost_${assetInfo.assetTypeId}`]: assetInfo.cost, salvage: assetInfo.salvageValue, depreciation_id: assetInfo.depreciationId, [`warranty_${assetInfo.assetTypeId}`]: assetInfo.warrantyMonths, [`acquisition_date_${assetInfo.assetTypeId}`]: assetInfo.acquisitionDate, [`warranty_expiry_date_${assetInfo.assetTypeId}`]: assetInfo.warrantyExpiryDate, [`serial_number_${assetInfo.assetTypeId}`]: assetInfo.serialNumber, [`asset_state_${assetInfo.assetTypeId}`]: assetInfo.state || "In Use" } }; try { const response = await fetch(url, { method: 'POST', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', 'Authorization': `Basic ${auth}` }, body: JSON.stringify(payload) }); if (!response.ok) { throw new Error(`Asset creation failed: ${response.status}`); } const data = await response.json(); console.log(`Asset created: ${data.asset.name} (Display ID: ${data.asset.display_id})`); return data.asset; } catch (error) { console.error('Asset creation error:', error); throw error; } } // Example: Create a laptop asset const laptop = await createAssetWithDetails({ name: "MacBook Pro 16-inch", assetTypeId: 25, assetTag: "LAPTOP-2024-0156", impact: "medium", usageType: "permanent", description: "16-inch MacBook Pro, M3 Max, 64GB RAM, 2TB SSD", assignedUserId: 1000234, locationId: 45, departmentId: 12, managedByGroupId: 9, productId: 10, vendorId: 14, cost: 3500, salvageValue: 500, warrantyMonths: 36, serialNumber: "C02YX1234567", acquisitionDate: "2024-01-15T00:00:00Z", warrantyExpiryDate: "2027-01-15T00:00:00Z", state: "In Use" }); ``` ```python import os import requests from requests.auth import HTTPBasicAuth from datetime import datetime, timedelta def create_asset(name, asset_type_id, serial_number, **kwargs): """ Create an IT asset in Freshservice Args: name: Asset name/model asset_type_id: Type of asset (laptop, server, etc.) serial_number: Unique serial number **kwargs: Optional fields (user_id, location_id, cost, etc.) Returns: dict: Created asset with ID and display_id """ domain = os.environ.get("FRESHSERVICE_DOMAIN") api_key = os.environ.get("FRESHSERVICE_API_KEY") url = f"https://{domain}.freshservice.com/api/v2/assets" # Calculate warranty expiry if warranty months provided warranty_months = kwargs.get("warranty_months", 12) acquisition_date = kwargs.get("acquisition_date", datetime.utcnow()) warranty_expiry = acquisition_date + timedelta(days=warranty_months*30) payload = { "name": name, "asset_type_id": asset_type_id, "asset_tag": kwargs.get("asset_tag", f"ASSET-{serial_number}"), "impact": kwargs.get("impact", "low"), "usage_type": kwargs.get("usage_type", "permanent"), "description": kwargs.get("description", ""), "user_id": kwargs.get("user_id"), "location_id": kwargs.get("location_id"), "department_id": kwargs.get("department_id"), "agent_id": kwargs.get("agent_id"), "group_id": kwargs.get("group_id"), "assigned_on": acquisition_date.isoformat() + "Z", "workspace_id": kwargs.get("workspace_id", 3), "type_fields": { f"product_{asset_type_id}": kwargs.get("product_id"), f"vendor_{asset_type_id}": kwargs.get("vendor_id"), f"cost_{asset_type_id}": kwargs.get("cost", 0), "salvage": kwargs.get("salvage_value", 0), f"warranty_{asset_type_id}": warranty_months, f"acquisition_date_{asset_type_id}": acquisition_date.isoformat() + "Z", f"warranty_expiry_date_{asset_type_id}": warranty_expiry.isoformat() + "Z", f"serial_number_{asset_type_id}": serial_number, f"asset_state_{asset_type_id}": kwargs.get("state", "In Use") } } response = requests.post( url, auth=HTTPBasicAuth(api_key, "X"), headers={'Accept': 'application/json', 'Content-Type': 'application/json'}, json=payload ) response.raise_for_status() asset = response.json()["asset"] print(f"✓ Asset created: {asset['name']} (ID: {asset['display_id']})") return asset # Example: Batch create multiple assets servers = [ {"name": "Web Server 01", "serial": "WS-001", "cost": 5000}, {"name": "Database Server 01", "serial": "DB-001", "cost": 8000}, {"name": "Application Server 01", "serial": "AS-001", "cost": 6000} ] for server in servers: create_asset( name=server["name"], asset_type_id=28, # Server type ID serial_number=server["serial"], cost=server["cost"], impact="high", location_id=5, department_id=2, vendor_id=10, warranty_months=36 ) ``` ```bash # Get asset assignment history curl -v -u api_key:X \ -H "Content-Type: application/json" \ -X GET 'https://acme.freshservice.com/api/v2/assets/8/assignment-history' # Response shows who had the asset and when # { # "assignment_history": [ # { # "id": 3, # "user_id": 2, # "user_name": "John Smith", # "assigned_on": "2024-01-01T04:05:36Z", # "assigned_by": 1, # "assigned_by_name": "Admin User", # "unassigned_by": 2, # "unassigned_on": "2024-06-31T04:05:36Z" # } # ] # } ``` ## Changes API ### Create Change Request with Planning Window Submit and track change requests with maintenance windows, risk assessment, and approval workflows. ```javascript async function createChangeRequest(changeDetails) { const url = `https://${process.env.FRESHSERVICE_DOMAIN}.freshservice.com/api/v2/changes`; const auth = Buffer.from(`${process.env.FRESHSERVICE_API_KEY}:X`).toString('base64'); const payload = { subject: changeDetails.subject, description: changeDetails.description, requester_id: changeDetails.requesterId, agent_id: changeDetails.agentId, group_id: changeDetails.groupId, priority: changeDetails.priority || 2, // 1=Low, 2=Medium, 3=High, 4=Urgent impact: changeDetails.impact || 2, // 1=Low, 2=Medium, 3=High status: 1, // 1=Open, 2=Planning, 3=Approval, 4=Pending Release, 5=Pending Review, 6=Closed risk: changeDetails.risk || 2, // 1=Low, 2=Medium, 3=High, 4=Very High change_type: changeDetails.changeType || 2, // 1=Minor, 2=Standard, 3=Major, 4=Emergency planned_start_date: changeDetails.plannedStartDate, planned_end_date: changeDetails.plannedEndDate, department_id: changeDetails.departmentId, maintenance_window: changeDetails.maintenanceWindowId ? { id: changeDetails.maintenanceWindowId } : undefined, custom_fields: changeDetails.customFields || {}, workspace_id: changeDetails.workspaceId || 3 }; try { const response = await fetch(url, { method: 'POST', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', 'Authorization': `Basic ${auth}` }, body: JSON.stringify(payload) }); if (!response.ok) { const error = await response.json(); throw new Error(`Change request failed: ${JSON.stringify(error)}`); } const data = await response.json(); console.log(`Change #${data.change.id} created: ${data.change.subject}`); if (data.change.blackout_window) { console.warn(`⚠️ Overlaps with blackout window: ${data.change.blackout_window.name}`); } return data.change; } catch (error) { console.error('Change request error:', error); throw error; } } // Example: Schedule infrastructure upgrade const change = await createChangeRequest({ subject: "Upgrade database cluster to version 14.2", description: "<div>Upgrading PostgreSQL cluster from 13.8 to 14.2 for improved performance and security patches.<br><br><b>Impact:</b> 2-hour maintenance window required.<br><b>Rollback plan:</b> Automated snapshot restore available.</div>", requesterId: 1000100, agentId: 1000250, groupId: 5, priority: 3, impact: 3, risk: 2, changeType: 3, // Major change plannedStartDate: "2025-11-30T02:00:00Z", plannedEndDate: "2025-11-30T04:00:00Z", departmentId: 8, maintenanceWindowId: 12, customFields: { affected_services: "Customer Portal, API Gateway", rollback_plan: "Automated snapshot restore - 30 min RTO" } }); ``` ```python import requests from requests.auth import HTTPBasicAuth from datetime import datetime, timedelta def create_change_request(subject, description, requester_id, start_date, end_date, **kwargs): """ Create a change request with scheduling and risk management Args: subject: Change request title description: HTML description of the change requester_id: User ID initiating the change start_date: Planned start datetime end_date: Planned end datetime **kwargs: priority, impact, risk, change_type, etc. Returns: dict: Created change request """ domain = os.environ.get("FRESHSERVICE_DOMAIN") api_key = os.environ.get("FRESHSERVICE_API_KEY") url = f"https://{domain}.freshservice.com/api/v2/changes" payload = { "subject": subject, "description": description, "requester_id": requester_id, "agent_id": kwargs.get("agent_id"), "group_id": kwargs.get("group_id"), "priority": kwargs.get("priority", 2), "impact": kwargs.get("impact", 2), "status": 1, "risk": kwargs.get("risk", 2), "change_type": kwargs.get("change_type", 2), "planned_start_date": start_date.isoformat() + "Z" if isinstance(start_date, datetime) else start_date, "planned_end_date": end_date.isoformat() + "Z" if isinstance(end_date, datetime) else end_date, "department_id": kwargs.get("department_id"), "workspace_id": kwargs.get("workspace_id", 3) } if kwargs.get("maintenance_window_id"): payload["maintenance_window"] = {"id": kwargs["maintenance_window_id"]} response = requests.post( url, auth=HTTPBasicAuth(api_key, "X"), headers={'Accept': 'application/json', 'Content-Type': 'application/json'}, json=payload ) response.raise_for_status() change = response.json()["change"] print(f"✓ Change #{change['id']} scheduled: {change['subject']}") if change.get("blackout_window"): print(f"⚠️ WARNING: Overlaps with blackout window '{change['blackout_window']['name']}'") return change # Example: Schedule emergency patch emergency_patch = create_change_request( subject="Emergency security patch for CVE-2024-12345", description="<p>Critical vulnerability in authentication module requires immediate patching.</p>", requester_id=1000100, start_date=datetime.utcnow() + timedelta(hours=2), end_date=datetime.utcnow() + timedelta(hours=3), priority=4, impact=3, risk=2, change_type=4, # Emergency agent_id=1000250, group_id=5 ) ``` ## Problems API ### Create Problem Record with Root Cause Analysis Document recurring issues with symptom, cause, and impact analysis for knowledge base building. ```python import os import requests from requests.auth import HTTPBasicAuth from datetime import datetime, timedelta def create_problem(subject, description, requester_id, due_by, **kwargs): """ Create a problem record with root cause analysis Args: subject: Problem title description: Detailed problem description requester_id: User ID reporting the problem due_by: Due date for resolution **kwargs: priority, impact, analysis_fields, custom_fields, etc. Returns: dict: Created problem record """ domain = os.environ.get("FRESHSERVICE_DOMAIN") api_key = os.environ.get("FRESHSERVICE_API_KEY") url = f"https://{domain}.freshservice.com/api/v2/problems" payload = { "subject": subject, "description": description, "requester_id": requester_id, "due_by": due_by.isoformat() + "Z" if isinstance(due_by, datetime) else due_by, "priority": kwargs.get("priority", 2), # 1=Low, 2=Medium, 3=High, 4=Urgent "status": kwargs.get("status", 1), # 1=Open, 2=Change Requested, 3=Closed "impact": kwargs.get("impact", 2), # 1=Low, 2=Medium, 3=High "known_error": kwargs.get("known_error", False), "agent_id": kwargs.get("agent_id"), "group_id": kwargs.get("group_id"), "department_id": kwargs.get("department_id"), "category": kwargs.get("category"), "sub_category": kwargs.get("sub_category"), "item_category": kwargs.get("item_category"), "custom_fields": kwargs.get("custom_fields", {}), "workspace_id": kwargs.get("workspace_id", 3) } # Add root cause analysis fields if kwargs.get("analysis_fields"): payload["analysis_fields"] = kwargs["analysis_fields"] response = requests.post( url, auth=HTTPBasicAuth(api_key, "X"), headers={'Accept': 'application/json', 'Content-Type': 'application/json'}, json=payload ) response.raise_for_status() problem = response.json()["problem"] print(f"✓ Problem #{problem['id']} created: {problem['subject']}") if problem.get("associated_change"): print(f" → Associated with Change #{problem['associated_change']}") return problem # Example: Document recurring email server issue problem = create_problem( subject="Email server intermittent connection failures", description="<p>Users report sporadic 'connection timed out' errors when connecting to Exchange Server.<br><br><b>Frequency:</b> 3-5 times daily<br><b>Affected users:</b> ~150 in sales department<br><b>Related tickets:</b> #1234, #1267, #1289</p>", requester_id=1000100, due_by=datetime.utcnow() + timedelta(days=7), priority=3, impact=2, status=1, agent_id=1000250, group_id=3, department_id=5, category="Hardware", sub_category="Server", item_category="Exchange", analysis_fields={ "problem_cause": { "description": "<p>Network switch intermittently dropping packets due to failing power supply module. Performance logs show correlation between errors and power fluctuations.</p>" }, "problem_symptom": { "description": "<p>Users experience 5-10 second connection timeouts when accessing email via Outlook. Web access (OWA) also affected. No pattern based on time of day.</p>" }, "problem_impact": { "description": "<p>Sales team productivity reduced by estimated 15%. Email delays affecting customer response times. High ticket volume consuming support resources.</p>" } }, custom_fields={ "estimated_affected_users": "150", "business_unit": "Sales" } ) # Mark as known error after validation def mark_as_known_error(problem_id): url = f"https://{os.environ.get('FRESHSERVICE_DOMAIN')}.freshservice.com/api/v2/problems/{problem_id}" response = requests.put( url, auth=HTTPBasicAuth(os.environ.get('FRESHSERVICE_API_KEY'), "X"), headers={'Accept': 'application/json', 'Content-Type': 'application/json'}, json={"known_error": True} ) response.raise_for_status() print(f"✓ Problem #{problem_id} marked as known error") mark_as_known_error(problem["id"]) ``` ## Requesters/Contacts API ### Create Requester with Department Association Manage end users who submit tickets and consume IT services. ```javascript async function createRequester(requesterData) { const url = `https://${process.env.FRESHSERVICE_DOMAIN}.freshservice.com/api/v2/requesters`; const auth = Buffer.from(`${process.env.FRESHSERVICE_API_KEY}:X`).toString('base64'); const payload = { first_name: requesterData.firstName, last_name: requesterData.lastName, primary_email: requesterData.email, secondary_emails: requesterData.secondaryEmails || [], job_title: requesterData.jobTitle, work_phone_number: requesterData.workPhone, mobile_phone_number: requesterData.mobilePhone, department_ids: requesterData.departmentIds || [], can_see_all_tickets_from_associated_departments: requesterData.canSeeAllDeptTickets || false, reporting_manager_id: requesterData.managerId, address: requesterData.address, time_zone: requesterData.timeZone || "Pacific Time (US & Canada)", time_format: "12h", language: "en", location_id: requesterData.locationId, background_information: requesterData.backgroundInfo || "", custom_fields: requesterData.customFields || {} }; try { const response = await fetch(url, { method: 'POST', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', 'Authorization': `Basic ${auth}` }, body: JSON.stringify(payload) }); if (!response.ok) { const error = await response.json(); throw new Error(`Failed to create requester: ${JSON.stringify(error)}`); } const data = await response.json(); console.log(`Requester created: ${data.requester.first_name} ${data.requester.last_name} (ID: ${data.requester.id})`); return data.requester; } catch (error) { console.error('Requester creation error:', error); throw error; } } // Example: Onboard new employee const newEmployee = await createRequester({ firstName: "Sarah", lastName: "Johnson", email: "sarah.johnson@company.com", secondaryEmails: ["sjohnson@company.com"], jobTitle: "Senior Software Engineer", workPhone: "555-0123", mobilePhone: "555-0124", departmentIds: [15], canSeeAllDeptTickets: false, managerId: 1000450, address: "123 Tech Street, San Francisco, CA 94105", timeZone: "Pacific Time (US & Canada)", locationId: 8, backgroundInfo: "Joining from TechCorp, specializes in microservices architecture", customFields: { employee_id: "EMP-2024-0456", start_date: "2024-12-01", security_clearance: "Level 2" } }); ``` ## Service Catalog API ### Retrieve Service Item Details Access service catalog items for self-service request automation. ```bash # Get specific service item by display ID curl -v -u your_api_key:X \ -H "Content-Type: application/json" \ -X GET 'https://acme.freshservice.com/api/v2/service_catalog/items/56' # Response includes full item configuration # { # "service_item": { # "id": 1004300649, # "display_id": 56, # "name": "Request Software License", # "category_id": 12, # "delivery_time": 24, # "cost": "150.00", # "visibility": 2, # "allow_quantity": true, # "description": "Request a software license for approved applications", # "workspace_id": 2, # "custom_fields": [] # } # } ``` ```python def get_service_catalog_items(): """List all published service catalog items""" domain = os.environ.get("FRESHSERVICE_DOMAIN") api_key = os.environ.get("FRESHSERVICE_API_KEY") url = f"https://{domain}.freshservice.com/api/v2/service_catalog/items" response = requests.get( url, auth=HTTPBasicAuth(api_key, "X"), headers={'Accept': 'application/json'} ) response.raise_for_status() items = response.json()["service_items"] print(f"Available Service Catalog Items ({len(items)}):") for item in items: print(f" [{item['display_id']}] {item['name']}") print(f" Cost: ${item['cost']} | Delivery: {item['delivery_time']}hrs") return items catalog = get_service_catalog_items() ``` ## Pagination and Rate Limiting ### Handle Large Result Sets with Pagination Efficiently retrieve large datasets while respecting API rate limits. ```javascript async function getAllTicketsWithPagination() { const domain = process.env.FRESHSERVICE_DOMAIN; const apiKey = process.env.FRESHSERVICE_API_KEY; const auth = Buffer.from(`${apiKey}:X`).toString('base64'); let allTickets = []; let page = 1; const perPage = 100; // Max 100 per page let hasMorePages = true; while (hasMorePages) { const url = `https://${domain}.freshservice.com/api/v2/tickets?page=${page}&per_page=${perPage}`; try { const response = await fetch(url, { headers: { 'Accept': 'application/json', 'Authorization': `Basic ${auth}` } }); // Handle rate limiting (429 Too Many Requests) if (response.status === 429) { const retryAfter = parseInt(response.headers.get('Retry-After') || '60', 10); console.log(`Rate limited. Waiting ${retryAfter} seconds...`); await new Promise(resolve => setTimeout(resolve, retryAfter * 1000)); continue; // Retry same page } if (!response.ok) { throw new Error(`HTTP ${response.status}: ${await response.text()}`); } const data = await response.json(); const tickets = data.tickets; allTickets = allTickets.concat(tickets); console.log(`Fetched page ${page}: ${tickets.length} tickets (Total: ${allTickets.length})`); // Check if there are more pages hasMorePages = tickets.length === perPage; page++; // Respect rate limits: 1000 requests/hour = ~1 request every 3.6 seconds await new Promise(resolve => setTimeout(resolve, 4000)); } catch (error) { console.error(`Error fetching page ${page}:`, error); throw error; } } return allTickets; } // Usage const allTickets = await getAllTicketsWithPagination(); console.log(`Total tickets retrieved: ${allTickets.length}`); ``` ```python import time import requests from requests.auth import HTTPBasicAuth def fetch_all_with_pagination(endpoint, per_page=30): """ Generic pagination handler with rate limit management Args: endpoint: API endpoint path (e.g., 'tickets', 'assets') per_page: Items per page (default: 30, max: 100) Returns: list: All items from paginated API """ domain = os.environ.get("FRESHSERVICE_DOMAIN") api_key = os.environ.get("FRESHSERVICE_API_KEY") all_items = [] page = 1 while True: url = f"https://{domain}.freshservice.com/api/v2/{endpoint}?page={page}&per_page={per_page}" try: response = requests.get( url, auth=HTTPBasicAuth(api_key, "X"), headers={'Accept': 'application/json'} ) # Handle rate limiting with exponential backoff if response.status_code == 429: retry_after = int(response.headers.get('Retry-After', 60)) print(f"⏱ Rate limit hit. Waiting {retry_after}s...") time.sleep(retry_after) continue response.raise_for_status() data = response.json() # Extract items (endpoint name is usually the key) items_key = endpoint if endpoint in data else list(data.keys())[0] items = data.get(items_key, []) all_items.extend(items) print(f"Page {page}: {len(items)} items (Total: {len(all_items)})") # Stop if we got fewer items than requested (last page) if len(items) < per_page: break page += 1 # Respect rate limits: sleep between requests time.sleep(3.6) # ~1000 requests/hour = 1 per 3.6s except requests.exceptions.RequestException as e: print(f"✗ Error on page {page}: {e}") raise return all_items # Example: Get all assets all_assets = fetch_all_with_pagination('assets', per_page=100) print(f"Total assets: {len(all_assets)}") # Example: Filter open tickets all_tickets = fetch_all_with_pagination('tickets/filter?query="status:2"', per_page=50) print(f"Open tickets: {len(all_tickets)}") ``` ## Summary The Freshservice API V2 provides comprehensive programmatic access to enterprise IT service management capabilities across tickets, assets, changes, problems, and service catalog operations. Primary use cases include automated ticket creation from monitoring systems, bulk asset imports during onboarding, scheduled change management workflows, problem tracking for recurring incidents, and self-service portal integrations. Developers can leverage the API to build custom integrations with HR systems for employee lifecycle management, monitoring tools for alert-to-ticket automation, asset discovery tools for CMDB synchronization, and chatbots for conversational service request submission. Integration patterns typically involve API key-based authentication with Base64 encoding, pagination for large datasets with rate limit awareness (1000 requests/hour), webhook subscriptions for real-time event notifications, and bulk operations using batch processing with exponential backoff for 429 responses. The API supports multi-workspace environments for MSP deployments, custom field extensions for organization-specific data models, and OAuth 2.0 flows for user-delegated access in Status Page and Journeys modules. Error handling should implement retry logic for transient failures, validate required fields before submission, handle workspace ID requirements correctly for MSP environments, and log detailed error responses including field-level validation messages for troubleshooting.