Zluri SDK Documentation V2
Zluri SDK Documentation
Welcome to the Zluri SDK documentation. This guide will help you integrate your custom applications and push data to Zluri when native connectors are not available.
Table of Contents
- What is Zluri SDK?
- Why Use Zluri SDK?
- Getting Started
- API Reference
- Code Examples
- Best Practices
- Troubleshooting
What is Zluri SDK?
The Zluri SDK is a set of APIs that enables customers to push data from their custom applications into the Zluri platform. It provides a standardized way to sync user information, application usage, transactions, and other critical SaaS management data when a native integration is not available.
Key Features
- Custom Integration Support: Build integrations for applications not natively supported by Zluri
- Flexible Data Upload: Support for multiple data entities (users, applications, licenses, roles, etc.)
- Chunked Uploads: Handle large datasets efficiently with paginated uploads
- Schema Validation: Automatic validation ensures data quality
- Real-time Sync Status: Monitor the progress of your data syncs
- Error Handling: Detailed error reports for troubleshooting
Why Use Zluri SDK?
Common Use Cases
- Custom or Internal Applications: Integrate proprietary tools built in-house
- Legacy Systems: Connect older applications that don't have modern APIs
- Specialized Software: Sync data from niche applications specific to your industry
- Data Consolidation: Aggregate data from multiple sources before sending to Zluri
Benefits
- No Native Connector Required: Push data even when Zluri doesn't have a pre-built integration
- Full Control: You manage when and what data to sync
- Scalable: Handle datasets of any size with chunked uploads
- Reliable: Built-in validation and error handling ensure data integrity
Getting Started
Prerequisites
- Access to Zluri dashboard
- Administrative privileges to generate API keys
- Basic understanding of REST APIs
- Programming knowledge in any language that supports HTTP requests
Step 1: Generate an API Key
- Log in to your Zluri dashboard
- Navigate to Settings → API Keys
- Click Generate New API Key
- Name your key (e.g., "SDK Integration Key")
- Copy and securely store the generated key
Important: API keys are shown only once. Store them securely and never share them publicly.
Step 2: Choose Your Application
Before creating an instance, you need to identify the application you want to integrate:
- Use the
appId
(orgAppId) of the application - If the application doesn't exist in Zluri, you may need to create it first
Step 3: Understand the Data Flow
graph LR A[Generate API Key] --> B[Create Instance] B --> C[Initialize Sync] C --> D[Upload Data Chunks] D --> E[Finish Sync] E --> F[Data Processing] F --> G[View in Zluri]
API Reference
Base URL
https://api.zluri.com
Authentication
All API requests must include your API key in the header:
Authorization: Bearer YOUR_API_KEY
1. Create Instance
Creates an SDK instance for syncing data with a specific application.
Endpoint
POST /ext/integrations/sync-sdk/v2/instances
Request Headers
{
"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json"
}
Request Body
{
"appId": "0365e45164d9fa3b3e274122",
"instanceName": "my-custom-app-integration",
"notificationEmails": ["[email protected]", "[email protected]"]
}
Parameters
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| appId | string | Yes | The orgAppId of the application |
| instanceName | string | Yes | Unique name for this integration instance |
| notificationEmails | array | No | Email addresses for sync notifications |
Response
{
"data": {
"instanceId": "651c2235e0eda4199c32e2dd",
"name": "my-custom-app-integration",
"status": "connected"
}
}
Example Code (Python)
import requests
api_key = "YOUR_API_KEY"
base_url = "https://api.zluri.com"
headers = {
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
}
instance_data = {
"appId": "0365e45164d9fa3b3e274122",
"instanceName": "my-custom-app-integration",
"notificationEmails": ["[email protected]"]
}
response = requests.post(
f"{base_url}/ext/integrations/sync-sdk/v2/instances",
json=instance_data,
headers=headers
)
instance_id = response.json()["data"]["instanceId"]
print(f"Instance created with ID: {instance_id}")
2. List Instances
Retrieve all SDK instances for your organization.
Endpoint
GET /ext/integrations/sync-sdk/v2/instances
Query Parameters
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| offset | integer | 0 | Pagination offset |
| limit | integer | 50 | Number of results (max: 100) |
| status | string | connected | Filter by status (connected, not-connected, error) |
Response
[
{
"instanceId": "651bb1396744c91d8886167",
"name": "my-custom-app-integration",
"appId": "0365e45164d9fa3b3e274122",
"status": "connected"
}
]
3. Initialize Sync
Start a new sync session for uploading data.
Endpoint
POST /ext/integrations/sync-sdk/v2/instances/{instanceId}/syncs
Response
{
"syncId": "684b7697a29ac1902134fd8b",
"message": "sync is successfully initiated"
}
Example Code (Python)
# Initialize a new sync
sync_response = requests.post(
f"{base_url}/ext/integrations/sync-sdk/v2/instances/{instance_id}/syncs",
headers=headers
)
sync_id = sync_response.json()["syncId"]
print(f"Sync initiated with ID: {sync_id}")
4. Upload Data - Snapshots
Upload snapshot data (current state) for entities like users, applications, licenses, etc.
Endpoint
POST /ext/integrations/sync-sdk/v2/syncs/{syncId}/data/snapshots
Request Body
{
"entityName": "users",
"pageNumber": 1,
"data": [
{
"email": "[email protected]",
"name": "John Doe",
"department": "Engineering",
"isActive": true,
"jobTitle": "Senior Software Engineer",
"reportingManagerEmail": "[email protected]",
"createdAt": "2023-06-10T08:45:00Z"
}
]
}
Supported Entity Names for Snapshots
users
applications
licenses
roles
groups
group_users
group_applications
Response
{
"message": "data uploaded successfully",
"totalRecordsUploaded": 1
}
Example Code (Python) - Chunked Upload
import math
def upload_users_in_chunks(users_data, sync_id, chunk_size=1000):
total_users = len(users_data)
total_chunks = math.ceil(total_users / chunk_size)
for page_num in range(total_chunks):
start_idx = page_num * chunk_size
end_idx = min((page_num + 1) * chunk_size, total_users)
chunk = users_data[start_idx:end_idx]
upload_data = {
"entityName": "users",
"pageNumber": page_num + 1,
"data": chunk
}
response = requests.post(
f"{base_url}/ext/integrations/sync-sdk/v2/syncs/{sync_id}/data/snapshots",
json=upload_data,
headers=headers
)
if response.status_code == 200:
print(f"Page {page_num + 1} uploaded successfully")
else:
print(f"Error uploading page {page_num + 1}: {response.json()}")
# Handle error appropriately
5. Upload Data - Facts
Upload fact data (events/activities) like user activities, transactions, or contracts.
Endpoint
POST /ext/integrations/sync-sdk/v2/syncs/{syncId}/data/facts
Request Body
{
"entityName": "user_activity",
"pageNumber": 1,
"data": [
{
"log_type": "sign_in",
"application_name": "Zoom",
"timestamp": "2025-06-16T09:30:00Z",
"username": "jdoe",
"work_email": "[email protected]",
"ip": "192.168.1.10",
"device": "MacBook Pro"
}
]
}
Supported Entity Names for Facts
user_activity
transactions
contracts
6. Get Sync Details
Check the status and details of a specific sync.
Endpoint
GET /ext/integrations/sync-sdk/v2/syncs/{syncId}
Response
{
"syncId": "684b7eb5a29ac1902134fd8e",
"status": "started",
"instanceId": "684b5a0953d3aba8ac97276c",
"entitiesUploaded": {
"users": {
"pages": [
{
"page_number": 1,
"totalRecordsUploaded": 1000,
"uploadStatus": "finished"
}
]
}
}
}
7. Finish Sync
Complete the sync and trigger data processing.
Endpoint
PUT /ext/integrations/sync-sdk/v2/syncs/{syncId}/status
Request Body
{
"status": "finished"
}
Response
{
"message": "Sync has been finished successfully and processing has started.",
"entitiesUploaded": {
"users": {
"pages": [
{
"page_number": 1,
"totalRecordsUploaded": 1000,
"status": "finished"
}
]
}
}
}
8. Cancel Sync
Abort an ongoing sync if needed.
Endpoint
DELETE /ext/integrations/sync-sdk/v2/syncs/{syncId}
Response
{
"message": "Sync has been killed successfully"
}
9. Get Entity Schemas
Retrieve the schema definitions for all supported entities.
Endpoint
GET /ext/integrations/sync-sdk/v2/entities/schemas
This returns the complete schema for each entity, helping you understand the required and optional fields.
Code Examples
Complete Sync Flow Example (Python)
import requests
import json
from datetime import datetime
class ZluriSDKClient:
def __init__(self, api_key):
self.api_key = api_key
self.base_url = "https://api.zluri.com"
self.headers = {
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
}
def create_instance(self, app_id, instance_name, notification_emails=None):
"""Create a new SDK instance"""
data = {
"appId": app_id,
"instanceName": instance_name
}
if notification_emails:
data["notificationEmails"] = notification_emails
response = requests.post(
f"{self.base_url}/ext/integrations/sync-sdk/v2/instances",
json=data,
headers=self.headers
)
response.raise_for_status()
return response.json()["data"]["instanceId"]
def init_sync(self, instance_id):
"""Initialize a new sync"""
response = requests.post(
f"{self.base_url}/ext/integrations/sync-sdk/v2/instances/{instance_id}/syncs",
headers=self.headers
)
response.raise_for_status()
return response.json()["syncId"]
def upload_snapshot_data(self, sync_id, entity_name, data, page_number=1):
"""Upload snapshot data for an entity"""
upload_data = {
"entityName": entity_name,
"pageNumber": page_number,
"data": data
}
response = requests.post(
f"{self.base_url}/ext/integrations/sync-sdk/v2/syncs/{sync_id}/data/snapshots",
json=upload_data,
headers=self.headers
)
response.raise_for_status()
return response.json()
def finish_sync(self, sync_id):
"""Complete the sync"""
response = requests.put(
f"{self.base_url}/ext/integrations/sync-sdk/v2/syncs/{sync_id}/status",
json={"status": "finished"},
headers=self.headers
)
response.raise_for_status()
return response.json()
def sync_users(self, instance_id, users_data):
"""Complete flow to sync users"""
try:
# Step 1: Initialize sync
sync_id = self.init_sync(instance_id)
print(f"Sync initiated: {sync_id}")
# Step 2: Upload data in chunks
chunk_size = 1000
for i in range(0, len(users_data), chunk_size):
chunk = users_data[i:i+chunk_size]
page_number = (i // chunk_size) + 1
result = self.upload_snapshot_data(
sync_id,
"users",
chunk,
page_number
)
print(f"Uploaded page {page_number}: {result['totalRecordsUploaded']} records")
# Step 3: Finish sync
finish_result = self.finish_sync(sync_id)
print(f"Sync completed: {finish_result['message']}")
return sync_id
except requests.exceptions.RequestException as e:
print(f"Error during sync: {e}")
if hasattr(e.response, 'json'):
print(f"Error details: {e.response.json()}")
raise
# Example usage
if __name__ == "__main__":
# Initialize client
client = ZluriSDKClient("YOUR_API_KEY")
# Sample user data
users = [
{
"email": "[email protected]",
"name": "John Doe",
"department": "Engineering",
"isActive": True,
"jobTitle": "Software Engineer",
"createdAt": datetime.utcnow().isoformat() + "Z"
},
{
"email": "[email protected]",
"name": "Jane Smith",
"department": "Marketing",
"isActive": True,
"jobTitle": "Marketing Manager",
"createdAt": datetime.utcnow().isoformat() + "Z"
}
]
# Sync users
instance_id = "YOUR_INSTANCE_ID"
sync_id = client.sync_users(instance_id, users)
Node.js Example
const axios = require('axios');
class ZluriSDKClient {
constructor(apiKey) {
this.apiKey = apiKey;
this.baseUrl = 'https://api.zluri.com';
this.headers = {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json'
};
}
async createInstance(appId, instanceName, notificationEmails = []) {
const response = await axios.post(
`${this.baseUrl}/ext/integrations/sync-sdk/v2/instances`,
{
appId,
instanceName,
notificationEmails
},
{ headers: this.headers }
);
return response.data.data.instanceId;
}
async initSync(instanceId) {
const response = await axios.post(
`${this.baseUrl}/ext/integrations/sync-sdk/v2/instances/${instanceId}/syncs`,
{},
{ headers: this.headers }
);
return response.data.syncId;
}
async uploadSnapshotData(syncId, entityName, data, pageNumber = 1) {
const response = await axios.post(
`${this.baseUrl}/ext/integrations/sync-sdk/v2/syncs/${syncId}/data/snapshots`,
{
entityName,
pageNumber,
data
},
{ headers: this.headers }
);
return response.data;
}
async finishSync(syncId) {
const response = await axios.put(
`${this.baseUrl}/ext/integrations/sync-sdk/v2/syncs/${syncId}/status`,
{ status: 'finished' },
{ headers: this.headers }
);
return response.data;
}
}
// Example usage
async function syncUsers() {
const client = new ZluriSDKClient('YOUR_API_KEY');
const instanceId = 'YOUR_INSTANCE_ID';
try {
// Initialize sync
const syncId = await client.initSync(instanceId);
console.log(`Sync initiated: ${syncId}`);
// Upload users
const users = [
{
email: '[email protected]',
name: 'Test User',
department: 'IT',
isActive: true
}
];
await client.uploadSnapshotData(syncId, 'users', users, 1);
// Finish sync
const result = await client.finishSync(syncId);
console.log('Sync completed:', result.message);
} catch (error) {
console.error('Sync failed:', error.response?.data || error.message);
}
}
Best Practices
1. Data Validation
- Always validate your data against the schema before uploading
- Use the
/entities/schemas
endpoint to get the latest schema definitions - Handle validation errors gracefully
2. Chunking Strategy
- Keep chunks under 1000 records
- Implement retry logic for failed chunks
- Track page numbers to ensure no data is missed
3. Error Handling
def upload_with_retry(client, sync_id, entity_name, data, page_number, max_retries=3):
for attempt in range(max_retries):
try:
return client.upload_snapshot_data(sync_id, entity_name, data, page_number)
except requests.exceptions.RequestException as e:
if attempt == max_retries - 1:
raise
print(f"Retry {attempt + 1}/{max_retries} after error: {e}")
time.sleep(2 ** attempt) # Exponential backoff
4. Rate Limiting
- Respect rate limits: One sync at a time per instance
- Syncs can be run every 6 hours
- Implement exponential backoff for rate limit errors
5. Monitoring
- Subscribe to notification emails for sync status
- Use the sync details API to track progress
- Implement logging for debugging
6. Data Consistency
- Ensure related entities are synced together
- For example, sync users before user activities
- Maintain referential integrity in your data
Troubleshooting
Common Issues and Solutions
1. Authentication Errors
Error: 401 Unauthorized
Solution:
- Verify your API key is correct
- Ensure you're using "Bearer" prefix in the Authorization header
- Check if the API key has been revoked
2. Schema Validation Errors
Error: 422 Schema validation failed
Solution:
- Check the error details for specific field issues
- Verify data types (e.g., boolean vs string)
- Ensure required fields are present
- Check date formats (use ISO 8601)
3. Rate Limit Errors
Error: 429 Rate limit exceeded
Solution:
- Wait for the time specified in the
Retry-At
header - Implement proper rate limiting in your code
- Ensure you're not running multiple syncs simultaneously
4. Sync Already Running
Error: A sync with syncId <id> is already running
Solution:
- Complete or cancel the existing sync before starting a new one
- Use the
/syncs/{syncId}
endpoint to check sync status - Call the DELETE endpoint to cancel if needed
5. Missing Data Dependencies
Error: Cross-entity validation failed
Solution:
- Ensure referenced entities exist (e.g., manager email must exist in users)
- Sync entities in the correct order
- Verify all foreign key relationships
Debug Checklist
- API key is valid and properly formatted
- Instance ID is correct
- Data conforms to the schema
- Required fields are present
- Data types are correct
- Dates are in ISO 8601 format
- Chunk size is under 1000 records
- No duplicate sync is running
- Rate limits are respected
Support
If you encounter issues not covered in this documentation:
- Check the detailed error messages in API responses
- Review sync logs in the Zluri dashboard
- Contact Zluri support at [email protected]
- Include your instance ID and sync ID in support requests
Appendix
Data Entity Schemas
For detailed schema information for each entity, use the GET /entities/schemas
endpoint. Key entities include:
Users Schema (Key Fields)
email
(required): User's email addressname
: Full namedepartment
: Department nameisActive
: Account status (boolean)reportingManagerEmail
: Manager's emailcreatedAt
: ISO 8601 datetime
User Activity Schema (Key Fields)
timestamp
(required): Event timestampwork_email
(required): User's emailapplication_name
: Name of the applicationlog_type
: Type of activity (e.g., sign_in)
Transaction Schema (Key Fields)
id
(required): Transaction IDtransaction_date
(required): Transaction datetransaction_amount
(required): Amounttransaction_currency
(required): Currency codevendor_name
: Vendor name
Status Codes
Code | Description |
---|---|
200 | Success |
400 | Bad Request - Invalid parameters |
401 | Unauthorized - Invalid API key |
404 | Not Found - Resource doesn't exist |
422 | Unprocessable Entity - Validation error |
429 | Too Many Requests - Rate limit exceeded |
500 | Internal Server Error |
Sync Status Values
started
: Sync is in progressfinished
: Sync completed successfullyfailed
: Sync failed with errorsaborted
: Sync was cancelled
Last updated: June 2025
Updated about 8 hours ago