Technical documentation for the AI Connector

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_credentials

2. 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:

  1. Go to Administration > Integrations > Enterprise Search.
  2. Create a new API client.
  3. Copy the clientId and clientSecret (the secret is only shown once).
  4. 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

entityType

string

Yes

Type of entity to retrieve. See Supported Entity Types

Query Parameters

Parameter

Type

Required

Default

Description

startId

integer

No

0

The event ID to start from (for pagination)

pageSize

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

amount

integer

Number of items in this response

lastEventId

integer

ID of the last event in this batch (use for next page)

content

array

Array of event objects

Common Event Fields

Every event object contains these base fields:

Field

Type

Description

eventId

integer (int64)

Unique identifier for this event

entityType

string

Type of entity (user, app, blog-article, etc.)

entityId

string

Unique identifier of the entity

eventType

string

Type of event (CREATE, UPDATE, DELETE)

tenantId

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

  1. Make initial request with startId=0 (or omit parameter)

  2. Process the returned content array

  3. Use the lastEventId from the response as the startId for the next request

  4. Continue until amount is 0 or less than pageSize

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 lastEventId to resume interrupted syncs

  • Implement 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 from imageUrls field

  • imageType - Either avatar or cover

  • modified (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 - From currentVersionBlobReference.groupId

  • uid - From currentVersionBlobReference.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

  1. Initial Sync

    • Use large page sizes (5000-10000) to minimize API calls

    • Process entity types in parallel when possible

    • Store the highest lastEventId for each entity type

  2. Incremental Updates

    • Poll for new events periodically (e.g., every 5-15 minutes)

    • Use the stored lastEventId as startId to get only new/updated entities

    • Process deletes endpoint to handle removed content

  3. Error Handling

    • Implement retry logic with exponential backoff

    • Handle 401 errors by refreshing the access token

    • Log failed entity IDs for manual review

  4. Performance

    • Cache image URLs and refresh when modified parameter changes

    • Process entities in batches for database insertion

    • Use parallel processing for different entity types

  5. Data Quality

    • Validate entity data before indexing

    • Handle missing optional fields gracefully

    • Respect the status and visibility fields for content filtering

  6. 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

  1. Use defaultLanguage to determine the primary content

  2. Index all language variants for multilingual search

  3. Extract the appropriate language variant based on user locale

  4. Fall back to defaultLanguage if 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)

Was this article helpful?

0 out of 0 found this helpful