Migrate importExternalCoursesStats

This guide details how to migrate from the v1 importExternalCoursesStats endpoint to the new v2 architecture.

💡

Key changes

  • From synchronous to asynchronous processing: API v2 processes statistics imports asynchronously, allowing bulk operations of up to 10,000 records per request.
  • Simplified field structure: v2 consolidates activity tracking with clearer semantics and removes complex auto-calculation scenarios.
  • Enhanced control: v2 introduces the forceNew parameter to explicitly control whether statistics create new attempts or update existing ones.
  • Flexible user and course identification: v2 introduces identifier objects that allow you to reference courses and users by either external or internal IDs

 Documentation links

Endpoint mapping

  • v1: /api/v1/externalContents/groups/:groupId/externalPlatforms/:externalPlatform/courses/stats
  • v2: /api/v2/bulk/integrations/{integrationId}/stats

Prerequisites

Before migrating to v2, you must have an integration configuration created. If you haven't done this yet, see step 2 in Create an API-based integration for instructions on creating an integration using the POST /api/v2/integrations endpoint.

You'll need your integrationId (the _id returned when creating the integration).

Main input changes

Change typeAPI v1API v2
Modified
Platform context
Path variables: groupId and externalPlatformPath variable: integrationId (contains both platform and group context)
Modified
statistics (max 20 objects)input (max 10,000 objects): Renamed.
Modified
externalIdcourseIdentifier.value: Now nested in object with type field
Modified
mailuserIdentifier.value: Now nested in object with type field
Modified
globalTimetimeSpent: Renamed and now required; still in milliseconds
Modified
completedAtlastActivityAt: Renamed and now required; when progress=100, this represents completion date
Modified
firstActivityfirstActivityAt: Renamed and now required
Modified
lastActivitylastActivityAt: Renamed and now required
Added

courseIdentifier.type: New field: "externalId" or "internalId"
Added

userIdentifier.type: New field: "mail" or "internalId"
Added

forceNew: New field: controls attempt creation vs. update behavior
Added

lang: New field: language in which learner played the course

Behavioral changes

v1: Complex auto-calculation logic

v1 had four scenarios for calculating activity timestamps and globalTime.

v2 removes all auto-calculation logic. You must provide all required fields explicitly:

  • progress (0-100)
  • timeSpent (in milliseconds)
  • firstActivityAt (ISO 8601 datetime)
  • lastActivityAt (ISO 8601 datetime)

Attempt creation/update logic

v2 uses the forceNew parameter to control behavior:

  • forceNew: true → Always creates a new attempt
  • forceNew: false (default) → Updates existing non-completed attempts OR creates new attempt if:
    • No attempt exists for this course/user combination
    • firstActivityAt is later than all existing attempts' lastActivityAt or completedAt

Main output changes

API v2 shifted from synchronous to asynchronous operations. Instead of an immediate result (200 OK), it returns a 202 Accepted status code indicating the bulk request has been queued. The full result must be tracked via the Location header.


Did this page help you?