---
title: Best Practices
url: https://docs.kaltura.com/docs/events-collaboration/app-registry-api/app-registry-best-practices
---

## Best Practices

- **Use `appCustomId` for external system mapping.** Map virtual event IDs or external identifiers to app GUIDs for cross-service lookups (e.g., Events Platform auto-registers with `appCustomId` = virtual event ID).
- **Track `version` numbers for concurrency detection.** The version increments on each state change — use it to detect concurrent modifications.
- **Enable apps after configuration is complete.** Create and configure first, then enable — other services (User Profile, Messaging) only interact with enabled apps.
- **Use the delta sync pattern for production integrations.** Filter by `updatedAt` range and paginate to keep your system in sync without full re-scans.
- **Use AppTokens for production access.** Generate KS via `appToken.startSession` with HMAC — keep admin secrets off application servers.

### Common Integration Patterns

#### Virtual Event ID to App GUID Mapping

When the Events Platform creates a virtual event, it automatically registers an app in the App Registry with `appType: "epmEvent"` and sets the `appCustomId` to the **virtual event ID**. This is the primary cross-service linkage — to work with registration data for a specific event, resolve the virtual event ID to an `appGuid` first:

```bash
# Step 1: Get the virtual event ID
# (from virtualEvent_virtualEvent/action/list or an existing workflow)
VIRTUAL_EVENT_ID="12345"

# Step 2: Resolve to App GUID via appCustomIdIn filter
APP_GUID=$(curl -s -X POST "$KALTURA_APP_REGISTRY_URL/app-registry/list" \
  -H "Authorization: Bearer $KALTURA_KS" \
  -H "Content-Type: application/json" \
  -d "{
    \"filter\": {
      \"appCustomIdIn\": [\"$VIRTUAL_EVENT_ID\"]
    },
    \"pager\": {\"offset\": 0, \"limit\": 1}
  }" | jq -r '.objects[0].id')

echo "App GUID for event $VIRTUAL_EVENT_ID: $APP_GUID"
# Use this APP_GUID with the User Profile API to get registration/attendance data
```

The `appCustomIdIn` filter accepts an array, so you can resolve multiple events in a single call:

```bash
# Resolve multiple virtual events at once
curl -s -X POST "$KALTURA_APP_REGISTRY_URL/app-registry/list" \
  -H "Authorization: Bearer $KALTURA_KS" \
  -H "Content-Type: application/json" \
  -d '{
    "filter": {
      "appCustomIdIn": ["12345", "12346", "12347"]
    }
  }'
```

#### Register App for Custom Integration

For custom integrations outside the Events Platform, register apps explicitly:

```bash
APP_GUID=$(curl -s -X POST "$KALTURA_APP_REGISTRY_URL/app-registry/add" \
  -H "Authorization: Bearer $KALTURA_KS" \
  -H "Content-Type: application/json" \
  -d '{
    "appCustomId": "annual-conference-2025",
    "appType": "ep",
    "appCustomName": "Annual Conference 2025"
  }' | jq -r '.id')

echo "App GUID: $APP_GUID"
```

#### Register App -> Manage User Profiles

The [User Profile API](/docs/events-collaboration/user-profile-api/user-profile-overview) associates user data with specific app instances. The `appGuid` parameter in user profile operations must reference a registered, enabled app:

```bash
# Use the app GUID from registration when creating user profiles
curl -X POST "$KALTURA_USER_PROFILE_URL/user-profile/add" \
  -H "Authorization: Bearer $KALTURA_KS" \
  -H "Content-Type: application/json" \
  -d "{
    \"appGuid\": \"$APP_GUID\",
    \"userId\": \"user@example.com\",
    \"profileData\": {\"name\": \"Jane Doe\"}
  }"
```

The User Profile service validates that the `appGuid` exists and is enabled in the App Registry. Validation results are cached for up to 24 hours — if you disable or delete an app, existing user profile operations may continue to work briefly.


#### Cross-Service Registration Data Retrieval

The full flow for extracting event registration and attendance data spans four services:

```bash
# Step 1: List virtual events
curl -s -X POST "$KALTURA_SERVICE_URL/service/virtualevent_virtualevent/action/list" \
  -d "ks=$KALTURA_KS" -d "format=1" | jq '.objects[] | {id, name}'
# → Get virtual event IDs

# Step 2: Resolve virtual event ID → App GUID
APP_GUID=$(curl -s -X POST "$KALTURA_APP_REGISTRY_URL/app-registry/list" \
  -H "Authorization: Bearer $KALTURA_KS" \
  -H "Content-Type: application/json" \
  -d "{\"filter\": {\"appCustomIdIn\": [\"$VIRTUAL_EVENT_ID\"]}}" \
  | jq -r '.objects[0].id')

# Step 3: Get registration/attendance data from User Profile
curl -s -X POST "$KALTURA_USER_PROFILE_URL/user-profile/list" \
  -H "Authorization: Bearer $KALTURA_KS" \
  -H "Content-Type: application/json" \
  -d "{
    \"filter\": {\"appGuidIn\": [\"$APP_GUID\"]},
    \"pager\": {\"offset\": 0, \"limit\": 500},
    \"orderBy\": \"createdAt\",
    \"includeTotalCount\": true
  }"
# → eventData has attendance status, profileData has registration form fields

# Step 4: Join with core user data (email, name, company)
# Extract userIds from step 3, then call user.list
USER_IDS="user1@example.com,user2@example.com"
curl -s -X POST "$KALTURA_SERVICE_URL/service/user/action/list" \
  -d "ks=$KALTURA_KS" -d "format=1" \
  -d "filter[objectType]=KalturaUserFilter" \
  -d "filter[idIn]=$USER_IDS"
# → firstName, lastName, email, company, jobTitle, country, state
```

For incremental syncs, use `updatedAtGreaterThanOrEqual` in both App Registry `list` and User Profile `list` filters to pull only records changed since your last sync.

#### Incremental Data Sync

Use date filters for efficient delta pulls instead of full data dumps:

```bash
# Pull only apps updated since yesterday
curl -s -X POST "$KALTURA_APP_REGISTRY_URL/app-registry/list" \
  -H "Authorization: Bearer $KALTURA_KS" \
  -H "Content-Type: application/json" \
  -d '{
    "filter": {
      "updatedAtGreaterThanOrEqual": "2025-06-14T00:00:00Z",
      "appType": "epmEvent"
    },
    "pager": {"offset": 0, "limit": 500}
  }'
```

Store the last record's `updatedAt` timestamp as a watermark and use it as the start of the next sync window.
