helpdesk-app-framework-sdk
v1.0.16
Published
The HelpDesk App Framework (BAF) SDK is a JavaScript library that simplifies cross-frame communication between iframed apps and the HelpDesk App Framework.
Maintainers
Readme
HelpDesk App Framework SDK
The HelpDesk App Framework (BAF) SDK is a JavaScript library that simplifies cross-frame communication between iframed apps and the HelpDesk App Framework, enabling seamless integration of custom applications into the HelpDesk helpdesk platform.
Overview
The BAF SDK provides a unified interface for:
- Data Access: Retrieve and update ticket, contact, and chat information
- Event Handling: Listen to and respond to platform events
- Cross-Frame Communication: Safely communicate between iframes and the host
- API Requests: Make secure HTTP requests through HelpDesk proxy
- App Instances: Manage app instances and multi-instance scenarios
- Context & Metadata: Access runtime context and app metadata
Getting Started
Installation
npm install helpdesk_app_framework_sdkBasic Usage
<script src="path/to/baf_sdk.min.js"></script>
<script>
const client = BAFClient.init((context) => {
console.log('App initialized!');
console.log('User:', context.user.name);
});
</script>Or as an ES Module
import BAFClient from 'helpdesk_app_framework_sdk';
const client = BAFClient.init((context) => {
console.log('App initialized!');
});Core Concepts
Client Initialization
Initialize the SDK when your app loads:
const client = BAFClient.init((context) => {
// Called when app is registered and ready
console.log('Module:', context.module); // ticket, contact, chat, etc.
console.log('Object ID:', context.objectId); // Current object being viewed
console.log('User:', context.user.name); // Current user information
});The init() function returns a Client instance that provides access to all APIs.
API Reference
Context API
Access runtime environment information through the context object.
// Get organization details
client.context.getOrgId();
client.context.getOrgName();
// Get brand information
client.context.getBrandId();
client.context.getBrandName();
// Get current module and object
client.context.getModule(); // 'ticket', 'contact', 'chat', etc.
client.context.getObjectId(); // ID of current object
// Get user information
client.context.getUser(); // Full user object
client.context.getUserId();
client.context.getUserEmail();
client.context.getUserName();
client.context.getUserTimezone();
// Get plan information
const plan = client.context.getPlan();
console.log(plan.id, plan.name);Metadata API
Access app and installation metadata through the metadata object.
// Get app information
client.metadata.getAppId();
client.metadata.getAppName();
client.metadata.getVersion();
// Get installation details
client.metadata.getInstallationId();
client.metadata.getInstallDate();
// Check permissions
if (client.metadata.hasReadAccess()) {
// App has read permission
}
if (client.metadata.hasWriteAccess()) {
// App has write permission
}
// Check status
client.metadata.isActive();
client.metadata.isEnabled();
// Get locations
const locations = client.metadata.getLocations();
console.log(locations); // ['desk.ticket.view.rightpanel', ...]
// Check if location is supported
if (client.metadata.isLocationSupported('desk.ticket.view.rightpanel')) {
// Location is supported
}Data API (get/set)
Retrieve and update data from the platform context.
Get Data
// Get single data point
client.get('ticket.subject').then(data => {
console.log(data['ticket.subject']);
});
// Get multiple data points
client.get(['ticket.subject', 'ticket.description']).then(data => {
console.log(data['ticket.subject']);
console.log(data['ticket.description']);
});
// Error handling
client.get('ticket.id')
.then(data => console.log(data))
.catch(error => console.error('Error:', error));Set Data
// Update single field
client.set('ticket.subject', 'Updated Subject')
.then(() => console.log('Updated!'))
.catch(error => console.error('Error:', error));
// Set structured data
client.set('ticket.customFields', {
field1: 'value1',
field2: 'value2'
});Event Handling (on/off)
Listen to platform events and react to changes.
// Listen for ticket updates
client.on('ticket.updated', (ticket) => {
console.log('Ticket updated:', ticket);
});
// Listen for custom events
client.on('contact.selected', (contact) => {
console.log('Contact selected:', contact);
});
// Remove specific listener
const handler = (ticket) => console.log(ticket);
client.on('ticket.updated', handler);
client.off('ticket.updated', handler);
// Remove all listeners for an event
client.off('ticket.updated');Invoke Actions (invoke)
Execute platform-exposed methods.
// Open a modal
client.invoke('modal.open', {
title: 'Confirm Action',
message: 'Are you sure?',
buttons: ['Yes', 'No']
}).then(result => {
console.log('User clicked:', result);
});
// Show notification
client.invoke('notification.show', {
type: 'success',
message: 'Operation completed'
});
// Navigate to view
client.invoke('navigation.goto', {
view: 'ticket',
id: '12345'
});Custom Events (trigger)
Emit custom events to communicate with other parts of the system.
// Emit custom event
client.trigger('custom.dataUpdated', {
status: 'success',
recordId: '12345'
});
// Listen for your own events
client.on('custom.dataUpdated', (data) => {
console.log('Data updated:', data);
});Capability Check (has)
Check if a specific capability or data path is available.
// Check if a custom field exists
client.has('ticket.custom_field_123').then(exists => {
if (exists) {
console.log('Custom field is available');
}
});
// Check if a capability is available
client.has('capability.updateTicket').then(available => {
if (available) {
console.log('Can update tickets');
}
});Request API (Secure Proxy)
Make HTTP requests securely through the HelpDesk proxy.
Important: Storage and resources APIs are not available in Zendesk-compatible mode.
// Basic GET request
client.request.get('https://api.example.com/data')
.then(response => console.log(response.data))
.catch(error => console.error(error));
// POST request with data
client.request.post('https://api.example.com/tickets', {
subject: 'New Ticket',
priority: 'high'
}).then(response => console.log('Created:', response.data));
// Using full request method
client.request.request({
url: 'https://api.example.com/users',
method: 'GET',
headers: {
'Authorization': 'Bearer {{setting.api_key}}' // Secure setting placeholder
},
params: {
status: 'active',
limit: 20
},
timeout: 30000,
autoRetry: true,
maxRetry: 3
}).then(response => {
console.log('Status:', response.status);
console.log('Data:', response.data);
});
// PUT request
client.request.put('https://api.example.com/tickets/123', {
status: 'resolved'
});
// DELETE request
client.request.delete('https://api.example.com/tickets/123');
// PATCH request
client.request.patch('https://api.example.com/tickets/123', {
priority: 'low'
});Request Options
| Option | Type | Required | Default | Description |
|--------|------|----------|---------|-------------|
| url | string | Yes | - | Full URL of API endpoint |
| method | string | Yes | - | HTTP method (GET, POST, PUT, DELETE, PATCH) |
| headers | object | No | {} | HTTP headers |
| params | object | No | - | Query parameters |
| body | object/string | No | - | Request payload (POST/PUT/PATCH) |
| timeout | number | No | 15000 | Timeout in ms (max 30000) |
| autoRetry | boolean | No | true | Auto-retry on 429/5xx |
| maxRetry | number | No | 3 | Max retry attempts |
| retryDelay | number | No | 1000 | Delay between retries (ms) |
Request Limitations
- Maximum request payload: 100 KB
- Maximum response size: 6 MB
- Default timeout: 15 seconds (configurable up to 30 seconds)
- Rate limit: 50 requests per minute per app per account
- Binary file upload/download: Not supported
Instance API
Manage app instances (for multi-instance widgets).
// Get current instance
const currentInstance = client.instance.current();
console.log('Instance ID:', currentInstance.getId());
// Get specific instance
const instance = client.instance.get('instance-id-123');
// Get all active instances
const allInstances = client.instance.all();
allInstances.forEach(inst => {
console.log(inst.getId());
});
// Create new instance
client.instance.create({
widgets: ['widget1', 'widget2']
}).then(instance => {
console.log('Created instance:', instance.getId());
});
// Send message to other instances
client.instance.send(['instance-1', 'instance-2'], 'update-channel', {
type: 'refresh',
data: newData
});
// Receive messages from other instances
client.instance.receive('update-channel', (message) => {
console.log('Received message:', message);
});
// Resize widget
client.instance.resize(500); // Set height to 500px
// Close current instance
client.instance.close();Widget Locations
Apps can be placed in specific locations in the HelpDesk UI:
| Location | Area | Description |
|----------|------|-------------|
| desk.menu.left | Left Sidebar | Full-screen app in left menu |
| desk.ticket.view.rightpanel | Right Panel (Ticket View) | Contextual panel on ticket page |
| desk.contact.view.rightpanel | Right Panel (Contact View) | Contextual panel on contact page |
| desk.contactgroup.view.rightpanel | Right Panel (Contact Group View) | Contextual panel on contact group page |
| desk.chat.view.rightpanel | Right Panel (Chat View) | Contextual panel on chat page |
| desk.cti.widget | Bottom-Left | CTI widget in bottom-left corner |
Manifest Configuration
Your app requires a manifest.json file:
{
"name": "My HelpDesk App",
"version": "1.0.0",
"frameworkVersion": "1.0.0",
"product": "HelpDesk",
"developer": {
"name": "John Doe",
"contactEmail": "[email protected]",
"supportEmail": "[email protected]",
"websiteUrl": "https://myapp.com",
"privacyUrl": "https://myapp.com/privacy",
"termsOfUseUrl": "https://myapp.com/terms"
},
"widgets": [
{
"name": "Ticket Widget",
"location": "desk.ticket.view.rightpanel",
"url": "widgets/ticket/index.html"
}
],
"trustedDomains": [
"https://api.example.com",
"https://cdn.example.com"
],
"settings": {
"enablePermission": true,
"enableReadPermission": true,
"enableWritePermission": false,
"fields": [
{
"key": "api_key",
"label": "API Key",
"type": "text",
"required": true,
"secure": true
}
]
},
"internalAuth": {
"authType": "oauth",
"clientId": "your-client-id",
"clientSecret": "your-client-secret",
"authorizeUri": "https://auth.example.com/oauth/authorize",
"accessTokenUri": "https://auth.example.com/oauth/token",
"redirectUri": "https://myapp.com/oauth/callback",
"scopes": ["read", "write"]
}
}Security Best Practices
Never expose sensitive data in client code
- Use
secure: truein manifest for sensitive settings - Reference settings as
{{setting.key}}in API requests - Platform replaces values server-side
- Use
Validate all data
- Validate user input before API calls
- Check response data types and values
- Handle errors gracefully
Use trusted domains
- Only add domains to
trustedDomainsthat you control - Verify HTTPS certificates for external APIs
- Only add domains to
Handle permissions
- Check
metadata.hasReadAccess()andmetadata.hasWriteAccess() - Gracefully degrade functionality for limited permissions
- Check
Error Handling
// Handle promise errors
client.get('ticket.id')
.then(data => console.log(data))
.catch(error => {
console.error('Error:', error.message);
// Show user-friendly error message
});
// Try-catch with async/await
async function fetchTicketData() {
try {
const data = await client.get('ticket.id');
console.log(data);
} catch (error) {
console.error('Failed to fetch ticket:', error);
}
}Development
Build
npm install
npm run buildDevelopment Build
npm run build:dev
npm run server # Serve at http://localhost:9001Testing
npm testLinting
npm run lintLimitations & Compatibility
- Storage API: Not available (use secure settings or your own backend)
- Resources API: Not available (resources are managed via manifest)
- Binary transfers: Not supported via request proxy
- CORS: Handled by proxy (no direct CORS in app code)
- Maximum payload: 100 KB requests, 6 MB responses
- Rate limiting: 50 requests/minute per app per account
Examples
Complete Ticket Widget
import BAFClient from 'helpdesk_app_framework_sdk';
const client = BAFClient.init(async (context) => {
console.log('App loaded for:', context.module);
try {
// Get ticket data
const data = await client.get([
'ticket.subject',
'ticket.description',
'ticket.status',
'ticket.requester.email'
]);
console.log('Ticket:', data);
// Listen for updates
client.on('ticket.updated', (ticket) => {
console.log('Ticket updated:', ticket);
});
// Listen for status changes
client.on('ticket.statusChanged', (status) => {
console.log('New status:', status);
});
} catch (error) {
console.error('Error loading ticket:', error);
}
});API Integration Example
// Make secure API request with auth
client.request.post('https://api.partner.com/sync', {
ticketId: ticketData.id,
subject: ticketData.subject,
description: ticketData.description
}, {
headers: {
'Authorization': 'Bearer {{setting.partner_api_key}}',
'X-App-Version': '1.0.0'
},
timeout: 30000,
autoRetry: true
}).then(response => {
console.log('Sync successful:', response.data);
}).catch(error => {
console.error('Sync failed:', error);
});Support
For issues, questions, or feature requests, please contact [email protected] or visit https://www.helpdesk.com/developer
License
Licensed under the Apache License, Version 2.0. See LICENSE file for details.
Copyright © 2026 HelpDesk
