Skip to main content
https://.thoughtindustries.com

Users

Updates the specified user's profile, license assignments, course access, and related attributes

Updates the specified user's profile, license assignments, course access, and related attributes.

PUThttps://example.thoughtindustries.com/incoming/v2/users/:id

Example request

curl -X PUT "https://example.thoughtindustries.com/incoming/v2/users/:id" \
  -H 'Authorization: Bearer YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{
  "clientId": "00000000-0000-0000-0000-000000000000",
  "studentLicenseIds": ["00000000-0000-0000-0000-000000000000"],
  "replaceLicenseAccess": true,
  "panoramaEnrollmentOptions": {
    "preserveEnrollments": false,
    "preserveProgress": true
  }
}'

Parameters

NameTypeRequiredLocationDescription
iduuidYespathThe id identifier.
emailstringNobodyThe user's email address.
externalCustomerIdstringNobodyAn external system identifier for the user, used to map the user to a record in an outside platform.
studentLicenseSkusstring[]NobodySKUs of licenses to assign to the user in the student role.
managerLicenseSkusstring[]NobodySKUs of licenses to assign to the user in the manager role.
studentLicenseIdsuuid[]NobodyIDs of licenses to assign to the user in the student role.
managerLicenseIdsuuid[]NobodyIDs of licenses to assign to the user in the manager role.
rolestringNobodyThe user's platform role (e.g., admin, learner).
clientSkustringNobodySKU of the client (tenant) to associate with the user.
clientSlugstringNobodyURL slug of the client (tenant) to associate with the user.
clientIduuidNobodyID of the client (tenant) to associate with the user.
replaceLicenseAccessbooleanNobodyWhen true, replaces the user's existing license assignments with the ones provided; otherwise merges them.
courseIdsuuid[]NobodyIDs of courses to grant the user direct access to.
courseSlugsstring[]NobodyURL slugs of courses to grant the user direct access to.
courseSkusstring[]NobodySKUs of courses to grant the user direct access to.
bundleSlugsstring[]NobodyURL slugs of bundles to grant the user access to.
learningPathSlugsstring[]NobodyURL slugs of learning paths to grant the user access to.
learningPathSkusstring[]NobodySKUs of learning paths to grant the user access to.
learningPathIdsuuid[]NobodyIDs of learning paths to grant the user access to.
firstNamestringNobodyThe user's first name.
lastNamestringNobodyThe user's last name.
address1stringNobodyThe first line of the user's mailing address.
address2stringNobodyThe second line of the user's mailing address (e.g., suite or apartment number).
citystringNobodyThe city component of the user's mailing address.
statestringNobodyThe state or province component of the user's mailing address.
zipCodestringNobodyThe postal code component of the user's mailing address.
countrystringNobodyThe country component of the user's mailing address.
telephonestringNobodyThe user's phone number.
ref1stringNobodyCustom reference field 1 for storing arbitrary external data.
ref2stringNobodyCustom reference field 2 for storing arbitrary external data.
ref3stringNobodyCustom reference field 3 for storing arbitrary external data.
ref4stringNobodyCustom reference field 4 for storing arbitrary external data.
ref5stringNobodyCustom reference field 5 for storing arbitrary external data.
ref6stringNobodyCustom reference field 6 for storing arbitrary external data.
ref7stringNobodyCustom reference field 7 for storing arbitrary external data.
ref8stringNobodyCustom reference field 8 for storing arbitrary external data.
ref9stringNobodyCustom reference field 9 for storing arbitrary external data.
ref10stringNobodyCustom reference field 10 for storing arbitrary external data.
languagestringNobodyThe user's preferred language code (e.g., en, fr).
tieredSubscriptionbooleanNobodyWhen true, enables tiered subscription pricing for the user.
replaceCourseAccessbooleanNobodyWhen true, replaces the user's existing course access with the courses provided; otherwise merges them.
replaceLearningPathAccessbooleanNobodyWhen true, replaces the user's existing learning path access with the learning paths provided; otherwise merges them.
replaceBundleAccessbooleanNobodyWhen true, replaces the user's existing bundle access with the bundles provided; otherwise merges them.
customFieldsobjectNobodyKey-value pairs of custom field data defined for the user's client.
sfContactIduuidNobodyThe Salesforce Contact ID linked to this user.
sfAccountIduuidNobodyThe Salesforce Account ID linked to this user.
dualRolebooleanNobodyWhen true, grants the user both learner and manager roles simultaneously.
balancenumberNobodyThe user's credit balance, in the platform's configured currency units.
enforceAccessDaysbooleanNobodyWhen true, enforces license access-day limits on the user's content access.
preferredCurrencystringNobodyThe user's preferred currency code for pricing display (e.g., USD, EUR).
panoramaEnrollmentOptionsobjectNobodyControls how the learner's existing enrollments and progress are handled when this request moves them to a different Panorama (clientId) or replaces their license assignments (replaceLicenseAccess). Ignored when the request changes neither the Panorama nor the license assignments. When omitted, all enrollments and progress are preserved. See "Panorama enrollment options" below.
panoramaEnrollmentOptions.preserveEnrollmentsbooleanNobodyDefaults to true. When true, enrollments tied only to licenses the user is losing are kept as direct enrollments so the learner retains access; when false, those enrollments are removed.
panoramaEnrollmentOptions.preserveProgressbooleanNobodyDefaults to true. When true, the learner's course progress and completion history are retained; when false, progress for the removed enrollments is permanently reset. Must be true whenever preserveEnrollments is true.

Panorama enrollment options

panoramaEnrollmentOptions only takes effect when this request actually changes the user's Panorama or license access — for example, when clientId moves the user to a different Panorama, or when license fields (such as studentLicenseIds or studentLicenseSkus) are combined with replaceLicenseAccess: true. On any other update the field is ignored.

Both options apply only to source-only enrollments: content the learner reaches through the licenses being removed and through no other license they keep or gain. Content available through both the old and the new licenses — overlap content — is never removed and never has its progress reset, whatever the two options are set to. Only its license association changes: the removed license IDs are dropped from the enrollment and the retained or newly added license that also covers it is stamped in their place. Courses the learner reaches through a learning path that survives the move are treated as overlap content for the same reason.

The object accepts two booleans, each defaulting to true. Three combinations are valid:

preserveEnrollmentspreserveProgressEffect
truetrueDefault (also applied when panoramaEnrollmentOptions is omitted). Enrollments from licenses the user is losing are converted to direct enrollments; the learner keeps access and all progress. This is the backward-compatible behavior.
falsetrueThe learner loses access to content from the removed licenses, but their progress and completion history are retained. If they regain access later, they resume where they left off. Courses set to restart progress on re-enrollment are the exception — see the note below.
falsefalseThe learner loses access to content from the removed licenses and their progress for that content is permanently reset.

The fourth combination — preserveEnrollments: true with preserveProgress: false — is invalid, because progress cannot be reset while the enrollment is preserved. It is rejected without applying the update (see "Validation errors" below).

Always preserved: preserveProgress: false clears only in-course progress for the affected content — topic-level progress, the resume position, the completion percentage, and assignment submissions, quiz attempts, and SCORM attempts. Certificates are never revoked, hidden, or invalidated, and the course and learning path completion records that make up their transcript are left in place (milestone completions inside a reset learning path are cleared, because learning path progress is derived from them). Achievements and awards move with the learner to the new Panorama rather than being removed. No parameter on this endpoint resets certificates, transcripts, or achievements — panoramaEnrollmentOptions accepts only the two booleans above.

Note: Courses with Restart Progress After Re-Enrollment enabled are the one exception. That setting is off by default and is turned on per course, in the course's eCommerce settings under Access, typically for recertification. Whenever the learner loses access to such a course — any time preserveEnrollments is false, including the false / true combination — that course's saved progress, quiz attempts, and SCORM attempts are cleared and its completion entry is removed from the transcript. The certificate itself is retained, and if your company displays past completions on the transcript, the completion still appears there. This is long-standing platform behavior for any loss of access — the same reset happens when access expires or a learner is automatically unenrolled — not something specific to panoramaEnrollmentOptions.

Example response

{
  "id": "00000000-0000-0000-0000-000000000000",
  "learnerUserId": "00000000-0000-0000-0000-000000000000",
  "managerUserId": "00000000-0000-0000-0000-000000000000",
  "clientId": "00000000-0000-0000-0000-000000000000",
  "createdAt": "2024-01-01T00:00:00.000Z",
  "disabled": true,
  "sfAccountId": "00000000-0000-0000-0000-000000000000",
  "sfContactId": "00000000-0000-0000-0000-000000000000",
  "roleKey": "string",
  "address1": "string",
  "address2": "string",
  "city": "string",
  "state": "string",
  "zipCode": "string",
  "telephone": "string",
  "country": "string",
  "stripeCustomerId": "00000000-0000-0000-0000-000000000000",
  "externalCustomerId": "string",
  "shippingName": "string",
  "asset": "string",
  "email": "string",
  "firstName": "string",
  "lastName": "string",
  "lastActiveAt": "2024-01-01T00:00:00.000Z",
  "ref1": "string",
  "ref2": "string",
  "ref3": "string",
  "ref4": "string",
  "ref5": "string",
  "ref6": "string",
  "ref7": "string",
  "ref8": "string",
  "ref9": "string",
  "ref10": "string",
  "language": "string",
  "customFields": {},
  "purchasedBundles": [
    {
      "bundleId": "00000000-0000-0000-0000-000000000000"
    }
  ],
  "allocatedLicenses": [
    {
      "licenseId": "00000000-0000-0000-0000-000000000000"
    }
  ],
  "allocatedLearningPaths": [
    {
      "learningPathId": "00000000-0000-0000-0000-000000000000",
      "status": "string"
    }
  ],
  "purchasedCourses": [
    {
      "courseId": "00000000-0000-0000-0000-000000000000",
      "status": "string"
    }
  ],
  "waitlistedCourses": [
    {
      "courseId": "00000000-0000-0000-0000-000000000000"
    }
  ],
  "balance": 0,
  "preferredCurrency": "string"
}

Validation errors

Supplying panoramaEnrollmentOptions with preserveEnrollments: true and preserveProgress: false is invalid — progress cannot be reset while the enrollment is preserved. The request is rejected and no changes are applied.

Unlike a successful response, which is unwrapped to the user object, this validation failure keeps the GraphQL envelope and is returned with HTTP status 200. Detect it by checking for an errors key rather than by status code:

{
  "errors": [
    { "message": "Cannot reset progress while preserving enrollment" }
  ],
  "data": {
    "APIUpdateUser": null
  }
}

Note: Entries in errors may carry additional GraphQL fields such as locations, path, and extensions. Match on errors[0].message rather than on the exact object shape.

Response fields

FieldTypeDescription
iduuidUnique identifier of the user.
learnerUserIduuidIdentifier of the associated learner user record, when the user has a dual role.
managerUserIduuidIdentifier of the associated manager user record, when the user has a dual role.
clientIduuidIdentifier of the client (tenant) the user belongs to.
createdAtISO 8601 timestampTimestamp when the user was created.
disabledbooleanWhether the user account is disabled.
sfAccountIduuidSalesforce Account ID associated with the user.
sfContactIduuidSalesforce Contact ID associated with the user.
roleKeystringPlatform role key assigned to the user.
address1stringPrimary street address line.
address2stringSecondary street address line.
citystringCity component of the address.
statestringState or province component of the address.
zipCodestringPostal code component of the address.
telephonestringUser's phone number.
countrystringCountry component of the address.
stripeCustomerIduuidStripe customer identifier for the user.
externalCustomerIdstringIdentifier for the user in an external system.
shippingNamestringName used for shipping physical goods.
assetstringURL of the user's avatar asset.
emailstringUser's email address.
firstNamestringUser's first name.
lastNamestringUser's last name.
lastActiveAtISO 8601 timestampTimestamp of the last recorded user activity.
ref1stringCustom reference field 1 for storing arbitrary external data.
ref2stringCustom reference field 2 for storing arbitrary external data.
ref3stringCustom reference field 3 for storing arbitrary external data.
ref4stringCustom reference field 4 for storing arbitrary external data.
ref5stringCustom reference field 5 for storing arbitrary external data.
ref6stringCustom reference field 6 for storing arbitrary external data.
ref7stringCustom reference field 7 for storing arbitrary external data.
ref8stringCustom reference field 8 for storing arbitrary external data.
ref9stringCustom reference field 9 for storing arbitrary external data.
ref10stringCustom reference field 10 for storing arbitrary external data.
languagestringUser's preferred language (BCP 47 tag). Null for non-learner roles.
customFieldsobjectKey-value pairs for custom profile fields defined on the client.
purchasedBundlesobject[]Bundles the user has purchased.
purchasedBundles.bundleIduuidIdentifier of the purchased bundle.
allocatedLicensesobject[]Licenses allocated to the user.
allocatedLicenses.licenseIduuidIdentifier of the allocated license.
allocatedLearningPathsobject[]Learning paths allocated to the user.
allocatedLearningPaths.learningPathIduuidIdentifier of the allocated learning path.
allocatedLearningPaths.statusstringStatus of the learning path allocation.
purchasedCoursesobject[]Courses the user has purchased.
purchasedCourses.courseIduuidIdentifier of the purchased course.
purchasedCourses.statusstringEnrollment status for the course.
waitlistedCoursesobject[]Courses the user is waitlisted for.
waitlistedCourses.courseIduuidIdentifier of the waitlisted course.
balancenumberUser's current credit balance.
preferredCurrencystringUser's preferred display currency (ISO 4217).