Integration API Reference
import { Tabs, TabItem } from ‘@astrojs/starlight/components’;
Integration API overview
The Klarify Integration API provides read-only access to your organization’s process data, enabling you to integrate Klarify information into external systems, dashboards, and analytics tools. This API is designed for safe, secure data access without the ability to modify your organization’s content.
What the API enables
Data retrieval capabilities:
- Access all procedures, processes, subprocesses, and tasks from your organization
- Retrieve metadata including ownership, status, and modification dates
- Export process information for business intelligence and reporting
- Integrate with external workflow management and project tracking systems
Common integration scenarios:
- Business intelligence dashboards showing process performance and compliance status
- Project management tools that need current process information for planning
- Training systems that reference current organizational procedures
- Compliance monitoring tools that track process updates and versions
Read-only access to organizational data
Security and access control:
- Read-only permissions prevent accidental modification of your process documentation
- Organization-scoped access - API keys only access data from your organization
- Secure authentication through access keys rather than username/password
- Activity logging for all API access for audit and security monitoring
Data scope: The API provides access to all published content that would be visible to a user with appropriate permissions in your organization, including:
- Process models and their associated metadata
- Global task documentation and details
- Organizational structure information relevant to processes
- Process relationships and dependencies
Generating your access key
Navigate to Settings > Integrations
- Log into Klarify with administrator privileges
- Navigate to Settings from your profile menu
- Select Integrations from the settings sidebar
- Locate the API Key section on the integrations page
Click Generate key
Key generation process:
- Click “Generate Key” button in the API Key section
- Copy the generated key immediately - it’s displayed only once
- Store securely in your password manager or secure key storage system
- Test the key with a simple API call to verify functionality
Key characteristics:
- Unique to your organization - Each organization has a distinct key
- Long random string - Cryptographically secure and difficult to guess
- No expiration - Keys remain valid until manually regenerated
- Immediate activation - Keys are ready for use immediately after generation
Important: Key regeneration invalidates previous key
Critical security behavior: When you regenerate an API key, the previous key stops working immediately. This security feature ensures that if a key is compromised, regenerating it instantly revokes all access using the old key.
Before regenerating:
- Identify all systems currently using the API key
- Plan coordinated updates to minimize service disruption
- Prepare update procedures for all integration points
- Consider maintenance windows for key rotation
After regenerating:
- Update all integrations with the new key as quickly as possible
- Test all integration points to ensure they’re working with the new key
- Monitor for errors from systems that might still be using the old key
- Document the change for audit and maintenance records
API endpoint reference
Base URL: https://integration.klarify.biz
All API requests use this base URL with specific endpoints for different data types and operations.
Request format:
GET https://integration.klarify.biz/api/procedures?access_key=YOUR_KEY&additional_parametersResponse format: All responses are returned in JSON format with consistent structure for easy parsing and integration.
GET /api/procedures
Endpoint purpose: Returns a paginated list of all procedures, processes, subprocesses, and tasks in your organization. This is currently the primary endpoint for accessing Klarify data programmatically.
Endpoint URL:
GET https://integration.klarify.biz/api/proceduresQuery parameters
access_key (required) - Your organization API key
Parameter details:
- Type: String
- Required: Yes
- Description: The organization API key generated from Settings > Integrations
- Security: Must be kept confidential and secure
Usage example:
?access_key=your-32-character-api-key-hereError responses:
- HTTP 404: “invalid access_key” - The provided key doesn’t exist or is inactive
- HTTP 500: “missing required access_key” - The parameter wasn’t included in the request
page (optional) - Zero-based pagination, defaults to 0
Parameter details:
- Type: Integer
- Required: No
- Default: 0
- Description: Zero-based page number for pagination (0 = first page, 1 = second page, etc.)
Usage examples:
?page=0 # First page of results?page=1 # Second page of results?page=5 # Sixth page of resultsPagination logic:
- Page 0 returns items 0 through (pageSize-1)
- Page 1 returns items pageSize through (2*pageSize-1)
- Continue until all items are retrieved
pageSize (optional) - Items per page, defaults to 100 (max recommended)
Parameter details:
- Type: Integer
- Required: No
- Default: 100
- Recommended maximum: 100
- Description: Number of items to return per page
Usage examples:
?pageSize=25 # Small pages for quick response?pageSize=50 # Medium pages for balanced performance?pageSize=100 # Large pages for efficient bulk retrievalPerformance considerations:
- Smaller page sizes (25-50) provide faster individual responses
- Larger page sizes (up to 100) reduce total number of requests needed
- Page sizes over 100 may cause timeouts and are not recommended
- Very small pages (under 10) create unnecessary request overhead
sort (optional) - Format: ‘field,direction’ e.g. ‘updated_at,desc’
Parameter details:
- Type: String
- Required: No
- Format: ‘field_name,direction’
- Available directions: ‘asc’ (ascending), ‘desc’ (descending)
Sortable fields:
- updated_at - When the item was last modified
- name - Alphabetical sorting by item name
- created_at - When the item was originally created
- status - Current publication status
Usage examples:
?sort=updated_at,desc # Most recently updated first?sort=name,asc # Alphabetical order A-Z?sort=created_at,asc # Oldest items first?sort=status,desc # Published items firstlast_updated_at (optional) - ISO 8601 timestamp for incremental sync
Parameter details:
- Type: String (ISO 8601 timestamp)
- Required: No
- Format: YYYY-MM-DDTHH:mm:ssZ
- Description: Filter to only items modified after this timestamp
Incremental sync strategy:
# Initial sync - get all items?pageSize=100
# Subsequent syncs - only get items modified since last sync?last_updated_at=2024-01-15T10:30:00Z&pageSize=100Usage examples:
?last_updated_at=2024-01-15T09:00:00Z # Items updated since 9 AM on Jan 15?last_updated_at=2024-01-01T00:00:00Z # Items updated since start of yearBenefits of incremental sync:
- Reduced bandwidth - Only transfer changed data
- Faster processing - Fewer items to process per request
- Efficient polling - Regular updates without full data transfer
- Lower server load - Smaller requests put less load on both systems
Response structure
data array - List of procedure objects
The response contains a data array with procedure objects and additional metadata for pagination:
{ "data": [ { "id": "12345", "name": "Customer Onboarding Process", "status": "published", "owner": "John Smith", "performer": "Customer Service Team", "updated_at": "2024-01-15T14:30:00Z", "url": "https://yourorg.klarify.me/process/12345", "lanes": ["Customer Service", "Account Management"], "called_within": [], "called_from": ["Sales Pipeline Process"] } ], "hasNext": true, "totalCount": 1247}hasNext boolean - Indicates more pages available
hasNext field:
- true - More pages of data are available, continue pagination
- false - This is the last page, no more data to retrieve
Pagination loop example:
let page = 0;let hasNext = true;
while (hasNext) { const response = await fetch( `https://integration.klarify.biz/api/procedures?access_key=${key}&page=${page}&pageSize=100` ); const data = await response.json();
// Process data.data array processItems(data.data);
// Check if more pages exist hasNext = data.hasNext; page++;}Procedure object fields: id, name, status, owner, performer, updated_at, url, lanes, called_within, called_from
Field descriptions:
id (string): Unique identifier for the procedure
- Example: “12345” or “proc_abc123def”
- Use for tracking and referencing specific procedures
- Stable across updates (doesn’t change when content is modified)
name (string): Display name of the procedure
- Example: “Customer Onboarding Process”
- Human-readable title shown in Klarify interface
- May change when procedures are updated or renamed
status (string): Current publication state
- Values: “published”, “draft”, “archived”
- Only published items are typically included in API responses
- Useful for filtering or conditional processing
owner (string): Person responsible for the procedure
- Example: “John Smith” or “jane.doe@company.com”
- May be name or email depending on organization setup
- Person with ultimate accountability for procedure accuracy
performer (string): Role or team that executes the procedure
- Example: “Customer Service Team” or “Sales Representatives”
- May be individual role or team name
- Indicates who actually carries out the work described
lanes (array): Process roles involved in execution
- Example: [“Customer Service”, “Account Management”, “IT Support”]
- Represents different organizational roles or departments
- Useful for understanding cross-functional processes
updated_at (string): ISO 8601 timestamp of last modification
- Example: “2024-01-15T14:30:00Z”
- Useful for incremental sync and change tracking
- Updates when any aspect of the procedure changes
url (string): Direct link to view the procedure in Klarify
- Example: “https://yourorg.klarify.me/process/12345”
- Allows users to access full procedure details
- Useful for notifications and external references
called_within (array): Procedures that include this one as a sub-process
- Example: [“Master Sales Process”, “Customer Lifecycle”]
- Shows where this procedure is referenced or embedded
- Helps understand procedure relationships and dependencies
called_from (array): Related or prerequisite procedures
- Example: [“Lead Qualification”, “Initial Contact Process”]
- Shows procedures that typically happen before this one
- Useful for understanding process flows and sequences
Example requests
Basic request with pagination
Simple data retrieval:
# Get first page of procedurescurl "https://integration.klarify.biz/api/procedures?access_key=YOUR_KEY&pageSize=50"
# Get specific pagecurl "https://integration.klarify.biz/api/procedures?access_key=YOUR_KEY&page=2&pageSize=50"Processing paginated results:
import requestsimport json
def get_all_procedures(api_key): base_url = "https://integration.klarify.biz/api/procedures" all_procedures = [] page = 0
while True: response = requests.get(base_url, params={ 'access_key': api_key, 'page': page, 'pageSize': 100 })
if response.status_code == 200: data = response.json() all_procedures.extend(data['data'])
if not data.get('hasNext', False): break page += 1 else: print(f"Error: {response.status_code} - {response.text}") break
return all_proceduresIncremental sync using last_updated_at
Efficient ongoing synchronization:
# Initial sync - get all current procedurescurl "https://integration.klarify.biz/api/procedures?access_key=YOUR_KEY&pageSize=100&sort=updated_at,desc"
# Daily sync - only get items modified in last 24 hourscurl "https://integration.klarify.biz/api/procedures?access_key=YOUR_KEY&last_updated_at=2024-01-14T09:00:00Z&pageSize=100"Incremental sync implementation:
class KlarifySync { constructor(apiKey) { this.apiKey = apiKey; this.baseUrl = 'https://integration.klarify.biz/api/procedures'; this.lastSyncTime = localStorage.getItem('lastKlarifySync') || '2024-01-01T00:00:00Z'; }
async syncUpdates() { const params = new URLSearchParams({ access_key: this.apiKey, last_updated_at: this.lastSyncTime, pageSize: 100, sort: 'updated_at,asc' });
try { const response = await fetch(`${this.baseUrl}?${params}`); const data = await response.json();
if (data.data.length > 0) { // Process updated procedures this.processUpdatedProcedures(data.data);
// Update sync timestamp to most recent item const latestUpdate = data.data[data.data.length - 1].updated_at; this.lastSyncTime = latestUpdate; localStorage.setItem('lastKlarifySync', this.lastSyncTime); }
return data.data; } catch (error) { console.error('Sync failed:', error); throw error; } }}Sorting by name or date
Different sorting approaches:
# Alphabetical sorting for directory-style displayscurl "https://integration.klarify.biz/api/procedures?access_key=YOUR_KEY&sort=name,asc&pageSize=50"
# Most recently updated procedures firstcurl "https://integration.klarify.biz/api/procedures?access_key=YOUR_KEY&sort=updated_at,desc&pageSize=25"
# Oldest procedures for historical analysiscurl "https://integration.klarify.biz/api/procedures?access_key=YOUR_KEY&sort=created_at,asc&pageSize=100"Error handling
404: Invalid access_key
Error response:
{ "error": "invalid access_key", "message": "The provided access key does not exist or has been disabled"}Common causes and solutions:
- Key regeneration: Access key was regenerated, invalidating the previous key
- Typo in key: Verify the key is copied correctly without extra spaces
- Wrong organization: Ensure you’re using the key for the correct Klarify organization
- Key deactivation: Contact your administrator if key access has been revoked
500: Missing required access_key
Error response:
{ "error": "missing required access_key", "message": "The access_key parameter is required for API authentication"}Resolution steps:
- Check parameter name: Ensure parameter is named
access_keyexactly - Verify request format: Confirm parameter is included in query string or POST body
- URL encoding: Make sure special characters in key are properly encoded
- HTTP method: Verify you’re using GET request for the procedures endpoint
General error handling strategy
Robust error handling implementation:
import requestsimport time
def safe_api_request(url, params, max_retries=3): for attempt in range(max_retries): try: response = requests.get(url, params=params, timeout=30)
if response.status_code == 200: return response.json() elif response.status_code == 404: raise ValueError("Invalid API key - check key and regenerate if necessary") elif response.status_code == 500: raise ValueError("Missing access_key parameter in request") else: print(f"Unexpected status code: {response.status_code}")
except requests.exceptions.Timeout: print(f"Request timeout on attempt {attempt + 1}") except requests.exceptions.ConnectionError: print(f"Connection error on attempt {attempt + 1}")
if attempt < max_retries - 1: time.sleep(2 ** attempt) # Exponential backoff
raise Exception("API request failed after all retry attempts")Best practices
Keep pageSize at 100 or below to prevent timeouts
Performance optimization:
- Page size 50-100: Optimal balance between request efficiency and response time
- Page size 25-50: Better for real-time applications needing fast responses
- Page size over 100: Risk of timeouts, especially for organizations with complex processes
- Page size under 25: Creates unnecessary request overhead for bulk operations
Timeout prevention strategies:
// Adaptive page sizing based on response timesclass AdaptiveApiClient { constructor(apiKey) { this.apiKey = apiKey; this.currentPageSize = 100; this.minPageSize = 25; this.maxPageSize = 100; }
async fetchWithAdaptiveSize(page = 0) { const startTime = Date.now();
try { const response = await this.makeRequest(page, this.currentPageSize); const responseTime = Date.now() - startTime;
// Adjust page size based on response time if (responseTime > 10000 && this.currentPageSize > this.minPageSize) { this.currentPageSize = Math.max(this.minPageSize, this.currentPageSize - 25); } else if (responseTime < 3000 && this.currentPageSize < this.maxPageSize) { this.currentPageSize = Math.min(this.maxPageSize, this.currentPageSize + 25); }
return response; } catch (error) { // Reduce page size on timeout if (error.name === 'TimeoutError' && this.currentPageSize > this.minPageSize) { this.currentPageSize = Math.max(this.minPageSize, this.currentPageSize - 25); } throw error; } }}Use incremental sync for continuous updates
Efficient ongoing synchronization:
Instead of fetching all data repeatedly, use the last_updated_at parameter to only retrieve items that have changed since your last sync.
import datetimeimport json
class IncrementalSync: def __init__(self, api_key, storage_file='sync_state.json'): self.api_key = api_key self.storage_file = storage_file self.state = self.load_state()
def load_state(self): try: with open(self.storage_file, 'r') as f: return json.load(f) except FileNotFoundError: return {'last_sync': '2024-01-01T00:00:00Z', 'known_items': {}}
def save_state(self): with open(self.storage_file, 'w') as f: json.dump(self.state, f)
def sync_updates(self): params = { 'access_key': self.api_key, 'last_updated_at': self.state['last_sync'], 'pageSize': 100, 'sort': 'updated_at,asc' }
updated_items = [] page = 0
while True: params['page'] = page response = requests.get('https://integration.klarify.biz/api/procedures', params=params) data = response.json()
for item in data['data']: # Track changes for incremental processing item_id = item['id'] if item_id in self.state['known_items']: if self.state['known_items'][item_id] != item['updated_at']: updated_items.append(('modified', item)) else: updated_items.append(('new', item))
self.state['known_items'][item_id] = item['updated_at']
if not data.get('hasNext'): break page += 1
# Update last sync time if updated_items: self.state['last_sync'] = max(item[1]['updated_at'] for item in updated_items)
self.save_state() return updated_itemsStore access keys securely - never in version control
Security best practices:
Environment variables:
# Set environment variableexport KLARIFY_API_KEY="your-api-key-here"
# Use in applicationimport osapi_key = os.getenv('KLARIFY_API_KEY')Configuration files (excluded from version control):
# config.py (add to .gitignore)KLARIFY_API_KEY = "your-api-key-here"
from config import KLARIFY_API_KEYKey management services:
# Using AWS Secrets Managerimport boto3
def get_api_key(): secrets_client = boto3.client('secretsmanager') response = secrets_client.get_secret_value(SecretId='klarify-api-key') return response['SecretString']What NOT to do:
# ❌ NEVER DO THIS - API key in source codeapi_key = "your-api-key-here" # Will be exposed in version control
# ❌ NEVER DO THIS - API key in committed configconfig = { "api_key": "your-api-key-here" # Visible to anyone with repo access}
# ❌ NEVER DO THIS - API key in logsprint(f"Using API key: {api_key}") # Sensitive information in logsImplement retry logic for network failures
Resilient API client implementation:
import requestsimport timeimport randomfrom typing import Optional, Dict, Any
class ResilientApiClient: def __init__(self, api_key: str): self.api_key = api_key self.base_url = "https://integration.klarify.biz/api/procedures" self.session = requests.Session()
def make_request( self, params: Dict[str, Any], max_retries: int = 3, base_delay: float = 1.0 ) -> Optional[Dict]: """Make API request with exponential backoff retry logic"""
params['access_key'] = self.api_key
for attempt in range(max_retries + 1): try: response = self.session.get( self.base_url, params=params, timeout=30 )
if response.status_code == 200: return response.json() elif response.status_code == 404: raise ValueError("Invalid API key") elif response.status_code >= 500: # Server error - retry if attempt < max_retries: continue else: raise Exception(f"Server error: {response.status_code}") else: # Client error - don't retry raise Exception(f"Client error: {response.status_code}")
except requests.exceptions.Timeout: print(f"Request timeout on attempt {attempt + 1}") except requests.exceptions.ConnectionError: print(f"Connection error on attempt {attempt + 1}") except requests.exceptions.RequestException as e: print(f"Request error on attempt {attempt + 1}: {e}")
if attempt < max_retries: # Exponential backoff with jitter delay = base_delay * (2 ** attempt) + random.uniform(0, 1) print(f"Retrying in {delay:.1f} seconds...") time.sleep(delay)
raise Exception("API request failed after all retry attempts")Ready to explore advanced API usage? Contact our support team at support@klarify.me for assistance with complex integration scenarios or custom API requirements.