Migrate importExternalCourses

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

💡

Key changes

  • From a single request to a two-step proces: API v2 decouples the environment setup from the data transfer.
  • Asynchronous bulk operation: Unlike the synchronous v1 response, Step 2 handles up to 10,000 objects asynchronously. You will receive a 202 Accepted status and must poll the URL provided in the Location header to retrieve the final import results.

Documentation links

Here are the links to the API reference for:

Endpoint mapping

Here's the direct correlation between the v1 and v2 endpoint URLs:

  • API v1: POST /api/v1/externalContents/groups/:groupId/externalPlatforms/:externalPlatform/courses
  • API v2:
    • Step 1 (Configure): POST /api/v2/integrations
    • Step 2 (Sync): PUT /api/v2/bulk/integrations/{integrationId}/courses

Step 1 (Configure): Create an integration configuration

In v1, you had to define the platform, group, and author context for every single import. In v2, you define these once to create a persistent environment.

Target URL: POST /api/v2/integrations

Example v2 request (Step 1)

curl --location 'https://app.360learning.com/api/v2/integrations' \
--header '360-api-version: v2.0' \
--header 'Authorization: Bearer YOUR_OAUTH_TOKEN' \
--header 'Content-Type: application/json' \
--data '{
    "externalPlatform": "myPlatform",
    "groupId": "62be0535045424d93edaad7b",
    "authorId": "62bdbc00293a604543f44386",
    "externalPlatformLogoUrl": "https://upload.wikimedia.org/wikipedia/commons/0/07/Wikipedia_logo_%28svg%29.svg",
    "defaultCompletion": true,
    "defaultProgress": 0,
    "noGroupPropagation": false
}'

Main input differences (Step 1)

Change typeAPI v1API v2
Modified
Parameter
externalPlatform: Path parameter.externalPlatform: Body parameter (serves as unique identifier for the configuration).
Modified
Parameter
groupId: Path parameter.groupId: Body parameter (defines the root group where all content will be stored).
Modified
Parameter
authorId: Body parameter defined per batch.authorId: Body parameter defined once as the default author for the entire integration.
Modified
Body parameter
externalPlatformLogoUrl: Single URL.externalPlatformLogoUrl (Standard) AND externalPlatformUnicolorLogoUrl (for banner contrast).
Added
Header parameter

360-api-version (Required): API version identifier. Example: v2.0.
Added
Body parameter

noGroupPropagation: true to restrict content to the target group; false to share with all subgroups.
Added
Body parameter

defaultCompletion: true if the content is auto-completed at launch; false otherwise.
Added
Body parameter

defaultProgress: The completion rate at launch as a percentage.

Example v2 response (Step 1)

{
    "_id": "64a1b2c3d4e5f6a7b8c9d0e1",
    "externalPlatform": "myPlatform",
    "groupId": "62be0535045424d93edaad7b",
    "authorId": "62bdbc00293a604543f44386",
    "defaultCompletion": true,
    "defaultProgress": 0,
    "noGroupPropagation": false,
    "createdAt": "2023-07-02T10:30:00.000Z"
}
💡

Save the _id from the response: This is your integrationIdfor Step 2.

Step 2 (Sync): Bulk upsert content

Once your configuration is created, you use the resulting _id (the integrationId) to perform content synchronizations.

Target URL: PUT /api/v2/bulk/integrations/{integrationId}/courses

Example v2 request (Step 2)

curl --location --request PUT 'https://app.360learning.com/api/v2/bulk/integrations/64a1b2c3d4e5f6a7b8c9d0e1/courses' \
--header '360-api-version: v2.0' \
--header 'Authorization: Bearer YOUR_OAUTH_TOKEN' \
--header 'Content-Type: application/json' \
--data '{
    "input": [
        {
            "externalId": "l3ssup3rh3r0s",
            "defaultLang": "en",
            "name": "Machine Learning Crash Course",
            "description": "Learn the basics of machine learning.",
            "launchUrl": "https://player.mylearningplatform.com/ql/fg-q6dfax2e_6ys",
            "mobileLaunchUrl": "https://player.mylearningplatform.com/mobile/fg-q6dfax2e_6ys",
            "imageUrl": "https://upload.wikimedia.org/wikipedia/commons/0/07/Wikipedia_logo_%28svg%29.svg",
            "difficultyLevel": "beginner",
            "contentType": "course",
            "duration": 10,
            "subjects": ["Machine learning"],
            "sources": [
                {
                    "name": "Wikipedia",
                    "logoUrl": "https://en.wikipedia.org/static/images/icons/wikipedia.png"
                }
            ],
            "translations": [
                {
                    "lang": "fr",
                    "translatedFields": {
                        "name": "Cours accéléré sur l'apprentissage automatique",
                        "description": "Apprenez les bases de l'apprentissage automatique.",
                        "subjects": ["Apprentissage automatique"]
                    }
                }
            ]
        }
    ]
}'

Main input differences (Step 2)

Change typeAPI v1API v2
Removed
numberOfVideos

Removed
skills

Modified
externalCourses: Array of course objectsinput: Array name changed, up to 10,000 per request
Modified
titlename: Renamed
Modified
thumbnailUrlimageUrl: Renamed
Modified
courseDurationduration: Renamed
Modified
languagedefaultLang: Renamed
Modified
authors: Array of stringsauthorId: single string
Modified
alternativeLanguages: array of stringstranslations: Array of objects. Each translation requires a full translatedFields object with translated content. Any field not provided in translatedFields falls back to the defaultLang values.
Modified
sources.logosources.logoUrl: Renamed
Added
Header parameter

360-api-version (Required): API version identifier. Example: v2.0.
Added
Path parameter

integrationId: Context passed via this path variable.

Main output differences (Step 2)

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?