The AI Connector provides a RESTful API that enables customers to retrieve content and metadata from their Haiilo SaaS Intranet platform. This connector is designed to feed external AI systems, enterprise search solutions, or other third-party applications with structured data from Haiilo.
The primary endpoint delivers various entity types (users, content, files, etc.) in a paginated format, making it easy to synchronize large datasets and keep external systems up-to-date with your Haiilo content.
Authentication
The AI Connector uses OAuth 2.0 Client Credentials flow for authentication.
Authentication Flow
1. Obtain Access Token
POST {baseUrl}/api/oauth/token
Content-Type: application/x-www-form-urlencoded
Authorization: Basic {base64(clientId:clientSecret)}
grant_type=client_credentials2. Response
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "events:read"
}3. Use Token in API Requests
GET {baseUrl}/web/content-connector/events/{entityType}
Authorization: Bearer {access_token}Required Scope
All AI Connector endpoints require the events:read scope, which is automatically granted to API clients.
API Credentials Setup
API credentials can be obtained through the Haiilo Admin interface:
- Go to Administration > Integrations > Enterprise Search.
- Create a new API client.
- Copy the clientId and clientSecret (the secret is only shown once).
- Store the credentials securely.
Core Endpoint
Get Events
Retrieves entities of a specific type from your Haiilo platform.
GET /web/content-connector/events/{entityType}
Path Parameters
Parameter |
Type |
Required |
Description |
|---|---|---|---|
|
string |
Yes |
Type of entity to retrieve. See Supported Entity Types |
Query Parameters
Parameter |
Type |
Required |
Default |
Description |
|---|---|---|---|---|
|
integer |
No |
0 |
The event ID to start from (for pagination) |
|
integer |
No |
100 |
Number of items to return (min: 1, max: 10000) |
Response
{
"amount": 100,
"lastEventId": 12345,
"content": [
{
"eventId": 12245,
"entityType": "user",
"entityId": "abc-123-def",
"eventType": "CREATE",
"tenantId": "your-tenant-id",
... // entity-specific fields
}
]
}
Response Fields
Field |
Type |
Description |
|---|---|---|
|
integer |
Number of items in this response |
|
integer |
ID of the last event in this batch (use for next page) |
|
array |
Array of event objects |
Common Event Fields
Every event object contains these base fields:
Field |
Type |
Description |
|---|---|---|
|
integer (int64) |
Unique identifier for this event |
|
string |
Type of entity (user, app, blog-article, etc.) |
|
string |
Unique identifier of the entity |
|
string |
Type of event (CREATE, UPDATE, DELETE) |
|
string |
Your tenant/organization identifier |
Supported Entity Types
The AI Connector supports 11 different entity types. Read more in this article: Supported entity types for the AI Connector.
Pagination
The API uses cursor-based pagination with the lastEventId field.
Pagination Strategy
Make initial request with
startId=0(or omit parameter)Process the returned
contentarrayUse the
lastEventIdfrom the response as thestartIdfor the next requestContinue until
amountis 0 or less thanpageSize
Example Pagination Flow
let startId = 0;
let allItems = [];
const pageSize = 1000; while (true) { const response = await getEvents('user', startId, pageSize); if (response.content.length === 0) { break; // No more data } allItems.push(...response.content); if (response.content.length < pageSize) { break; // Last page } startId = response.lastEventId; }
Best Practices
Use larger page sizes (1000-10000) for initial full sync to reduce API calls
Use smaller page sizes (100-500) for incremental updates
Store
lastEventIdto resume interrupted syncsImplement exponential backoff for rate limiting
Deleted Entities
Track entities that have been deleted to keep your external system in sync.
GET /web/content-connector/events/{entityType}/deletes
Parameters
Same as the main events endpoint: startId, pageSize
Response
{
"amount": 10,
"lastEventId": 12350,
"content": [
{
"eventId": 12346,
"entityId": "deleted-entity-id",
"entityType": "blog-article"
}
]
}
Use Case
Use this endpoint to identify which entities have been deleted since your last sync, allowing you to remove them from your external system.
Helper Endpoints
Get Sender Images
Retrieve avatar or cover images for users, pages, or workspaces.
GET /web/content-connector/api/senders/{senderId}/images/{imageType}
Parameters:
senderId(UUID) - ID fromimageUrlsfieldimageType- Eitheravatarorcovermodified(optional) - Modification timestamp for caching
Response:
{
"imageUrl": "https://cdn.haiilo.com/..."
}
Get Blog Teaser Images
Retrieve teaser images for blog articles.
GET /web/content-connector/api/blogs/{blogId}/teaser
Response:
{
"image": {
"contentType": "image/png",
"downloadUrl": "https://...",
"validityMinutes": 60
},
"imageWide": {
"contentType": "image/png",
"downloadUrl": "https://...",
"validityMinutes": 60
}
}
Get File Download URL
Retrieve a download URL for a file.
GET /web/content-connector/api/files/{groupId}/{uid}
Parameters:
groupId- FromcurrentVersionBlobReference.groupIduid- FromcurrentVersionBlobReference.uid
Response:
{
"fileUrl": "https://cdn.haiilo.com/..."
}
Note: Download URLs are time-limited and should be used promptly or refreshed as needed.
Get Theme Icon
Retrieve the tenant's theme icon (favicon).
GET /web/content-connector/theme-icon
Response: PNG image (binary)
Usage Examples
Node.js Example Client
See example-client/example-client.js for a complete reference implementation.
const ContentConnectorClient = require('./example-client');
const client = new ContentConnectorClient(
'your-client-id',
'your-client-secret',
'https://your-tenant.haiilo.com'
);
// Authenticate
await client.connect();
// Get all users
const users = await client.getAllEntitiesWithPagination('user');
// Get blog articles
const articles = await client.getAllEntitiesWithPagination('blog-article');
// Get specific page
const response = await client.getEvents('page', 0, 100);
Python Example
import requests import base64
class ContentConnectorClient: def __init__(self, client_id, client_secret, base_url): self.client_id = client_id self.client_secret = client_secret self.base_url = base_url self.token = None def connect(self): credentials = base64.b64encode( f"{self.client_id}:{self.client_secret}".encode() ).decode() response = requests.post( f"{self.base_url}/api/oauth/token", data={"grant_type": "client_credentials"}, headers={"Authorization": f"Basic {credentials}"} ) self.token = response.json()["access_token"] def get_events(self, entity_type, start_id=0, page_size=100): response = requests.get( f"{self.base_url}/web/content-connector/events/{entity_type}", params={"startId": start_id, "pageSize": page_size}, headers={"Authorization": f"Bearer {self.token}"} )
return response.json()
cURL Example
# Get access token TOKEN=$(curl -X POST "https://your-tenant.haiilo.com/api/oauth/token" \ -H "Authorization: Basic $(echo -n 'clientId:clientSecret' | base64)" \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=client_credentials" | jq -r '.access_token')
# Get users curl "https://your-tenant.haiilo.com/web/content-connector/events/user?startId=0&pageSize=100" \ -H "Authorization: Bearer $TOKEN"
Rate Limits and Best Practices
Best Practices
-
Initial Sync
Use large page sizes (5000-10000) to minimize API calls
Process entity types in parallel when possible
Store the highest
lastEventIdfor each entity type
-
Incremental Updates
Poll for new events periodically (e.g., every 5-15 minutes)
Use the stored
lastEventIdasstartIdto get only new/updated entitiesProcess deletes endpoint to handle removed content
-
Error Handling
Implement retry logic with exponential backoff
Handle 401 errors by refreshing the access token
Log failed entity IDs for manual review
-
Performance
Cache image URLs and refresh when
modifiedparameter changesProcess entities in batches for database insertion
Use parallel processing for different entity types
-
Data Quality
Validate entity data before indexing
Handle missing optional fields gracefully
Respect the
statusandvisibilityfields for content filtering
-
Security
Store API credentials securely (environment variables, secrets manager)
Use HTTPS for all API communications
Don't log access tokens
Multilingual Content
Many entities support multilingual content through map fields (e.g., title, textContent).
Structure
{
"title": {
"en": "Welcome to our company",
"de": "Willkommen in unserem Unternehmen",
"fr": "Bienvenue dans notre entreprise"
},
"defaultLanguage": "en"
}
Handling Strategy
Use
defaultLanguageto determine the primary contentIndex all language variants for multilingual search
Extract the appropriate language variant based on user locale
Fall back to
defaultLanguageif requested locale is unavailable
Common Objects
SenderReference
References to entities (users, workspaces, pages) that "own" or are associated with content.
{
"id": "entity-id",
"type": "user" // or "workspace", "page", etc.
}
Target
Link target information for frontend navigation.
{
"name": "blog_article_detail",
"displayName": "Article Detail",
"params": {
"appId": "123",
"articleId": "456"
}
}
Use these to construct deep links into the Haiilo frontend.
Frequently Asked Questions
Q: How often should I poll for updates?
A: For most use cases, polling every 5-15 minutes provides a good balance between freshness and API load. For real-time requirements, consider polling every 1-2 minutes, but ensure you implement proper rate limiting.
Q: Can I filter events by date or status?
A: Filtering is not currently supported at the API level. Retrieve all events and filter on your side based on createdDate, modifiedDate, status, or other fields.
Q: What happens if I miss events during downtime?
A: Simply resume using your last stored lastEventId. The API returns all events after that ID, so you won't miss any updates.
Q: How do I handle deleted content?
A: Use the /deletes endpoint for each entity type to retrieve deleted entity IDs, then remove them from your external system.
Q: Are image URLs permanent?
A: Image URLs returned by helper endpoints are time-limited (typically 60 minutes). Refresh them as needed rather than storing them long-term.
Q: Can I request only specific fields?
A: No, the API returns complete entity objects. Filter fields on the client side as needed.
Q: What's the maximum page size?
A: The maximum pageSize is 10,000 items per request.
Support and Resources
- OpenAPI Specification
- Integration Setup: Administration > Integrations > Enterprise Search in your Haiilo platform.
- Example Client: enterprise-search-example-client.zip (download below)
- Swagger (like) Document: swagger-doc.html (download below)