Certification and Retraining APIs: How-to guide

Prev Next

Purpose of this article: a task-oriented, one-endpoint-at-a-time guide for working with certifications via the API. This article shows you how to call each endpoint. For a list of what changed for certifications on existing endpoints (blocked fields, new error codes, silent exclusions), see Deprecated and changed API calls.

Availability: Since the October 2026 primary release, the new type of certifications is generally available to all customers as a standard platform capability, and Launchpad does not offer an option to enable or disable it. Legacy certifications and the new type of certifications will co-exist for a while.

Please note: In this article, certifications always means the new type of certifications, which are Learning Plans with "type": 2. This article does not cover legacy certifications.

Before you start

All examples below assume:

  • Your platform domain is https://yourdomain.docebosaas.com. Replace it with your own.

  • You already have a valid OAuth2 access token (see APIs authentication) and send it as Authorization: Bearer YOUR_ACCESS_TOKEN on every call.

  • A certification is a learning plan with "type": 2. A standard Learning Plan is "type": 1. Everything below that is not certification-specific applies equally to both.

  • Required permission slugs are the same ones used for standard Learning Plans:

    • learning-plan/view

    • learning-plan/create

    • learning-plan/update

    • learning-plan/delete

    • enrollment/lp/manage

    See the Permission model note under each endpoint for which one applies.

Power Users can work with the new type of certifications through the same Learning Plan permissions as standard Learning Plans. Grant the Power User the Learning Plan permissions for View, Create, Edit and Delete on their profile. Then assign the relevant resources to them, which can include the new type of certifications alongside standard Learning Plans. A Power User does not need access to the individual courses inside a certification to view or manage the certification itself, because access follows the Learning Plan permissions and the assignment of the certification to the Power User. The Power User needs the individual courses assigned only to add or select those courses in a certification, which is the same behavior as for standard Learning Plans.

To try any of these calls interactively first, open your platform's API browser at https://yourdomain.docebosaas.com/api-browser/, select the Learning Plan service, and follow the steps in Get started with the Docebo API browser to authorize and use the Try button. Each endpoint section below tells you which grouping to open in the left-hand navigation.

Create a learning plan or certification

POST /learningplan/v1/learningplans

Permission required: learning-plan/create (Superadmin; Power User within their perimeter).

What it does: Creates a new Learning Plan or Certification. Set "type": 2 to create a certification instead of a standard Learning Plan.

Parameters (request body)

Parameter

Type

Required

Description

title

string

Yes

Title of the Learning Plan or certification.

type

integer

No (defaults to 1)

1 = standard Learning Plan, 2 = Certification.

description

string

Yes

Description text.

Please note: This endpoint does not accept the certification_config object. To set the expiration and renewal behavior of a certification, create the certification first, and then update it with the update endpoint described in section 4. If your platform has mandatory additional fields, you must also pass them in an additional_fields array of objects, each with an id and a value. Without them, the call returns error 1001 (Missing parameter: additional_field ids).

Example request body

{
  "title": "Certified Safety Trainer",
  "type": 2,
  "description": "Annual safety certification for warehouse staff."
}

Example calls

  • Go to:

    • Service Learning Plan

    • Grouping Learning Plans

    • POST /learningplan/v1/learningplans

  • Paste the body above into the request body field

  • Click Try

const response = await fetch('https://yourdomain.docebosaas.com/learningplan/v1/learningplans', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    title: 'Certified Safety Trainer',
    type: 2,
    description: 'Annual safety certification for warehouse staff.'
  })
});
const data = await response.json();
console.log(data);
import requests
url = "https://yourdomain.docebosaas.com/learningplan/v1/learningplans"
headers = {
    "Authorization": "Bearer YOUR_ACCESS_TOKEN",
    "Content-Type": "application/json"
}
payload = {
    "title": "Certified Safety Trainer",
    "type": 2,
    "description": "Annual safety certification for warehouse staff."
}
response = requests.post(url, headers=headers, json=payload)
print(response.json())
<?php
$curl = curl_init();
curl_setopt_array($curl, [
    CURLOPT_URL => "https://yourdomain.docebosaas.com/learningplan/v1/learningplans",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => "POST",
    CURLOPT_POSTFIELDS => json_encode([
        "title" => "Certified Safety Trainer",
        "type" => 2,
        "description" => "Annual safety certification for warehouse staff."
    ]),
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer YOUR_ACCESS_TOKEN",
        "Content-Type: application/json"
    ],
]);
$response = curl_exec($curl);
curl_close($curl);
echo $response;
  • Method: POST

  • URL: https://yourdomain.docebosaas.com/learningplan/v1/learningplans

  • Headers: Authorization: Bearer YOUR_ACCESS_TOKEN, Content-Type: application/json

  • Body (raw, JSON): same as the example request body above

Response

Returns data.id_lp, the ID of the new Learning Plan or certification.

Retrieve a learning plan or certification

GET /learningplan/v1/learningplans/{lp_id}

Permission required: learning-plan/view.

What it does: Returns all properties of a single Learning Plan or Certification. For certifications, the response includes the certification_config object.

Parameters

Parameter

Location

Type

Required

Description

lp_id

path

integer

Yes

The ID of the Learning Plan or certification.

Example calls

  • Go to:

    • Service Learning Plan

    • Grouping Learning Plans

    • GET /learningplan/v1/learningplans/{lp_id}

  • Enter the lp_id

  • Click Try

const lpId = 123;
const response = await fetch(`https://yourdomain.docebosaas.com/learningplan/v1/learningplans/${lpId}`, {
  headers: { 'Authorization': 'Bearer YOUR_ACCESS_TOKEN' }
});
const data = await response.json();
console.log(data);
import requests
lp_id = 123
url = f"https://yourdomain.docebosaas.com/learningplan/v1/learningplans/{lp_id}"
headers = {"Authorization": "Bearer YOUR_ACCESS_TOKEN"}
response = requests.get(url, headers=headers)
print(response.json())
<?php
$lpId = 123;
$curl = curl_init();
curl_setopt_array($curl, [
    CURLOPT_URL => "https://yourdomain.docebosaas.com/learningplan/v1/learningplans/{$lpId}",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => ["Authorization: Bearer YOUR_ACCESS_TOKEN"],
]);
$response = curl_exec($curl);
curl_close($curl);
echo $response;
  • Method: GET

  • URL: https://yourdomain.docebosaas.com/learningplan/v1/learningplans/123

  • Headers: Authorization: Bearer YOUR_ACCESS_TOKEN

Response

Returns the Learning Plan/certification object. For type: 2, includes certification_config.

List learning plans and certifications

GET /learningplan/v1/learningplans

Permission required: learning-plan/view (filtering by type_filter=2 is available to Superadmins only).

What it does: Returns a paginated list of Learning Plans and/or Certifications.

Parameters (query string)

Parameter

Type

Required

Description

type_filter

integer

No

1 for standard Learning Plans only, 2 for Certifications only. Omit for both.

award_status

string

No

Certification-only filter on award status. Accepted values are valid (at least one valid award), expiring (at least one expiring award) and expired (at least one expired award). You can pass more than one value.

page

integer

No

Page number, default 1.

page_size

integer

No

Items per page (1–200), default 10.

sort_attr

string

No

Field to sort by.

Possible values are:

  • uuid

  • code

  • title

  • price

  • credits

  • created_on

  • updated_on

Default value: created_on

sort_dir

string

No

  • asc

  • desc

Default value: desc

Example calls

  • Go to:

    • Service Learning Plan

    • Grouping Learning Plans

    • GET /learningplan/v1/learningplans

  • Set type_filter=2 in the parameters panel

  • Click Try

const response = await fetch('https://yourdomain.docebosaas.com/learningplan/v1/learningplans?type_filter=2&page_size=20', {
  headers: { 'Authorization': 'Bearer YOUR_ACCESS_TOKEN' }
});
const data = await response.json();
console.log(data);
import requests
url = "https://yourdomain.docebosaas.com/learningplan/v1/learningplans"
headers = {"Authorization": "Bearer YOUR_ACCESS_TOKEN"}
params = {"type_filter": 2, "page_size": 20}
response = requests.get(url, headers=headers, params=params)
print(response.json())
<?php
$curl = curl_init();
curl_setopt_array($curl, [
    CURLOPT_URL => "https://yourdomain.docebosaas.com/learningplan/v1/learningplans?type_filter=2&page_size=20",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => ["Authorization: Bearer YOUR_ACCESS_TOKEN"],
]);
$response = curl_exec($curl);
curl_close($curl);
echo $response;
  • Method: GET

  • URL: https://yourdomain.docebosaas.com/learningplan/v1/learningplans?type_filter=2&page_size=20

  • Headers: Authorization: Bearer YOUR_ACCESS_TOKEN

Response

Returns a paginated items array. For certification results, each item includes award_counters (lazy-loaded certification award summary).

Update a learning plan or certification

PUT /learningplan/v1/learningplans/{lp_id}

Permission required: learning-plan/update.

What it does: Updates a Learning Plan or Certification, including its certification_config.

Please note: Updating a certification's configuration does not trigger the LearningPlanUpdated webhook event. If your integration listens for that event to detect changes, you will not be notified of certification updates today. See Deprecated and changed API calls for details.

Parameters (request body)

Parameter

Type

Required

Description

title

string

Yes

Updated title.

description

string

Yes

Updated description.

lang_code

string

Yes

The language of the learning plan or certification, written as the language name, such as english.

certification_config

object

No (certifications only)

Certification-specific settings (expiration and renewal behavior). Set these settings with this endpoint, because the create endpoint does not accept this object. The next table describes the structure of this object.

The certification_config object

Use the certification_config object to set when awards of a certification expire and how learners renew them. The following table lists each field with its full path inside the object.

Field

Type

Description

expiration

object

Required. Defines when an award expires.

expiration.type

string

Required. The expiration logic.

Possible values are:

  • NONE

  • FIXED_DATE

  • RELATIVE

expiration.fixed_date.month

integer

Required when type is FIXED_DATE. The month, from 1 to 12.

expiration.fixed_date.day

integer

Required when type is FIXED_DATE. The day of the month, from 1 to 31.

expiration.relative.duration

integer

Required when type is RELATIVE. The duration value. The value must be at least 1.

expiration.relative.unit

string

Required when type is RELATIVE. The time unit of the duration.

Possible values are:

  • DAY

  • WEEK

  • MONTH

  • YEAR

expiration.relative.snap_to_end

string

Required when type is RELATIVE. Whether the date snaps to the end of a period.

Possible values are:

  • NONE

  • MONTH

  • YEAR

recert

object

Required. Defines how learners renew an award. Pass this object next to expiration, not inside it. Always include it when you pass certification_config. For ANYTIME renewal, you do not need to pass window.

recert.type

string

Required. The renewal logic.

Possible values are:

  • ANYTIME

  • WINDOW

recert.window.start.duration

integer

Required. The duration value for the start of the renewal window. The value must be at least 1.

recert.window.start.unit

string

Required. The time unit. The only possible value is DAY.

recert.window.end.type

string

Required. The logic for the end of the renewal window. Possible values are:

  • NONE

  • AT_EXPIRATION

  • RELATIVE

Tip:

The values AT_EXPIRATION and RELATIVE apply only when a learner renews an existing certification.

recert.window.end.relative.duration

integer

Required. The duration value for the end of the renewal window. The value must be at least 1.

recert.window.end.relative.unit

string

Required. The time unit. The only possible value is DAY.

Example request body

{
  "title": "Certified Safety Trainer",
  "description": "Annual safety certification for warehouse staff.",
  "lang_code": "english",
  "certification_config": {
    "expiration": {
      "type": "RELATIVE",
      "relative": {
        "duration": 1,
        "unit": "YEAR",
        "snap_to_end": "NONE"
      }
    },
    "recert": {
      "type": "WINDOW",
      "window": {
        "start": {
          "duration": 30,
          "unit": "DAY"
        },
        "end": {
          "type": "RELATIVE",
          "relative": {
            "duration": 7,
            "unit": "DAY"
          }
        }
      }
    }
  }
}

Example calls

  • Go to:

    • Service Learning Plan

    • Grouping Learning Plans

    • PUT /learningplan/v1/learningplans/{lp_id}

  • Enter lp_id

  • Edit the body

  • Click Try

const lpId = 123;
const response = await fetch(`https://yourdomain.docebosaas.com/learningplan/v1/learningplans/${lpId}`, {
  method: 'PUT',
  headers: {
    'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    title: 'Certified Safety Trainer',
    description: 'Annual safety certification for warehouse staff.',
    lang_code: 'english',
    certification_config: {
      expiration: {
        type: 'RELATIVE',
        relative: { duration: 1, unit: 'YEAR', snap_to_end: 'NONE' }
      },
      recert: {
        type: 'WINDOW',
        window: {
          start: { duration: 30, unit: 'DAY' },
          end: { type: 'RELATIVE', relative: { duration: 7, unit: 'DAY' } }
        }
      }
    }
  })
});
const data = await response.json();
console.log(data);
import requests
lp_id = 123
url = f"https://yourdomain.docebosaas.com/learningplan/v1/learningplans/{lp_id}"
headers = {
    "Authorization": "Bearer YOUR_ACCESS_TOKEN",
    "Content-Type": "application/json"
}
payload = {
    "title": "Certified Safety Trainer",
    "description": "Annual safety certification for warehouse staff.",
    "lang_code": "english",
    "certification_config": {
        "expiration": {
            "type": "RELATIVE",
            "relative": {"duration": 1, "unit": "YEAR", "snap_to_end": "NONE"}
        },
        "recert": {
            "type": "WINDOW",
            "window": {
                "start": {"duration": 30, "unit": "DAY"},
                "end": {"type": "RELATIVE", "relative": {"duration": 7, "unit": "DAY"}}
            }
        }
    }
}
response = requests.put(url, headers=headers, json=payload)
print(response.json())
<?php
$lpId = 123;
$curl = curl_init();
curl_setopt_array($curl, [
    CURLOPT_URL => "https://yourdomain.docebosaas.com/learningplan/v1/learningplans/{$lpId}",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => "PUT",
    CURLOPT_POSTFIELDS => json_encode([
        "title" => "Certified Safety Trainer",
        "description" => "Annual safety certification for warehouse staff.",
        "lang_code" => "english",
        "certification_config" => [
            "expiration" => [
                "type" => "RELATIVE",
                "relative" => ["duration" => 1, "unit" => "YEAR", "snap_to_end" => "NONE"]
            ],
            "recert" => [
                "type" => "WINDOW",
                "window" => [
                    "start" => ["duration" => 30, "unit" => "DAY"],
                    "end" => ["type" => "RELATIVE", "relative" => ["duration" => 7, "unit" => "DAY"]]
                ]
            ]
        ]
    ]),
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer YOUR_ACCESS_TOKEN",
        "Content-Type: application/json"
    ],
]);
$response = curl_exec($curl);
curl_close($curl);
echo $response;
  • Method: PUT

  • URL: https://yourdomain.docebosaas.com/learningplan/v1/learningplans/123

  • Headers: Authorization: Bearer YOUR_ACCESS_TOKEN, Content-Type: application/json

  • Body (raw, JSON): same as the example request body above

Response

Returns the updated object.

Delete learning plans or certifications

DELETE /learningplan/v1/learningplans

Permission required: learning-plan/delete.

What it does: Deletes one or more Learning Plans or Certifications by ID.

Parameters (request body)

Parameter

Type

Required

Description

items

array of integers

Yes

The Learning Plan / certification IDs to delete.

Example calls

  • Go to:

    • Service Learning Plan

    • Grouping Learning Plans

    • DELETE /learningplan/v1/learningplans

  • Enter the items array in the body

  • Click Try

const response = await fetch('https://yourdomain.docebosaas.com/learningplan/v1/learningplans', {
  method: 'DELETE',
  headers: {
    'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ items: [123, 124] })
});
const data = await response.json();
console.log(data);
import requests
url = "https://yourdomain.docebosaas.com/learningplan/v1/learningplans"
headers = {
    "Authorization": "Bearer YOUR_ACCESS_TOKEN",
    "Content-Type": "application/json"
}
payload = {"items": [123, 124]}
response = requests.delete(url, headers=headers, json=payload)
print(response.json())
<?php
$curl = curl_init();
curl_setopt_array($curl, [
    CURLOPT_URL => "https://yourdomain.docebosaas.com/learningplan/v1/learningplans",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => "DELETE",
    CURLOPT_POSTFIELDS => json_encode(["items" => [123, 124]]),
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer YOUR_ACCESS_TOKEN",
        "Content-Type: application/json"
    ],
]);
$response = curl_exec($curl);
curl_close($curl);
echo $response;
  • Method: DELETE

  • URL: https://yourdomain.docebosaas.com/learningplan/v1/learningplans

  • Headers: Authorization: Bearer YOUR_ACCESS_TOKEN, Content-Type: application/json

  • Body (raw, JSON): {"items": [123, 124]}

Response

Returns one result for each ID. Each result contains:

  • row_index

  • success

  • output (where output contains the id )

Update the status of multiple learning plans or certifications

PUT /learningplan/v1/learningplans/statuses

What it does: Sets the status of multiple Learning Plans or Certifications in a single call. The status controls whether an item is published or under maintenance.

Parameters (request body)

Parameter

Type

Required

Description

items

array of objects

Yes

The items to update. Each object contains an id (the ID of the Learning Plan or certification) and a status. Use 1 for published and 0 for under maintenance. Both values are required.

Example calls

  • Go to:

    • Service Learning Plan

    • Grouping Learning Plans

    • PUT /learningplan/v1/learningplans/statuses

  • Enter the items array in the body

  • Click Try

const response = await fetch('https://yourdomain.docebosaas.com/learningplan/v1/learningplans/statuses', {
  method: 'PUT',
  headers: {
    'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ items: [{ id: 123, status: 1 }, { id: 124, status: 0 }] })
});
const data = await response.json();
console.log(data);
import requests
url = "https://yourdomain.docebosaas.com/learningplan/v1/learningplans/statuses"
headers = {
    "Authorization": "Bearer YOUR_ACCESS_TOKEN",
    "Content-Type": "application/json"
}
payload = {"items": [{"id": 123, "status": 1}, {"id": 124, "status": 0}]}
response = requests.put(url, headers=headers, json=payload)
print(response.json())
<?php
$curl = curl_init();
curl_setopt_array($curl, [
    CURLOPT_URL => "https://yourdomain.docebosaas.com/learningplan/v1/learningplans/statuses",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => "PUT",
    CURLOPT_POSTFIELDS => json_encode(["items" => [["id" => 123, "status" => 1], ["id" => 124, "status" => 0]]]),
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer YOUR_ACCESS_TOKEN",
        "Content-Type: application/json"
    ],
]);
$response = curl_exec($curl);
curl_close($curl);
echo $response;
  • Method: PUT

  • URL: https://yourdomain.docebosaas.com/learningplan/v1/learningplans/statuses

  • Headers: Authorization: Bearer YOUR_ACCESS_TOKEN, Content-Type: application/json

  • Body (raw, JSON): {"items": [{"id": 123, "status": 1}, {"id": 124, "status": 0}]}

Response

The response contains:

  • success (true if at least one update completed)

  • updated_ids

  • not_updated_ids

  • not_found_ids

List enrollments for a learning plan or certification

GET /learningplan/v1/learningplans/{lp_id}/enrollments

Permission required: learning-plan/view + enrollment/lp/manage.

What it does: Lists the users enrolled in a specific Learning Plan or Certification.

Tip: For certification enrollments, the response also includes a type field, and completed enrollments include an award sub-object plus a previous_award count (for renewed certifications).

Parameters

Parameter

Location

Type

Required

Description

lp_id

path

integer

Yes

The Learning Plan / certification ID.

page

query

integer

No

Page number.

page_size

query

integer

No

Items per page (1–200).

Example calls

  • Go to:

    • Service Learning Plan

    • Grouping Enrollments

    • GET /learningplan/v1/learningplans/{lp_id}/enrollments

  • Enter lp_id

  • Click Try

const lpId = 123;
const response = await fetch(`https://yourdomain.docebosaas.com/learningplan/v1/learningplans/${lpId}/enrollments`, {
  headers: { 'Authorization': 'Bearer YOUR_ACCESS_TOKEN' }
});
const data = await response.json();
console.log(data);
import requests
lp_id = 123
url = f"https://yourdomain.docebosaas.com/learningplan/v1/learningplans/{lp_id}/enrollments"
headers = {"Authorization": "Bearer YOUR_ACCESS_TOKEN"}
response = requests.get(url, headers=headers)
print(response.json())
<?php
$lpId = 123;
$curl = curl_init();
curl_setopt_array($curl, [
    CURLOPT_URL => "https://yourdomain.docebosaas.com/learningplan/v1/learningplans/{$lpId}/enrollments",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => ["Authorization: Bearer YOUR_ACCESS_TOKEN"],
]);
$response = curl_exec($curl);
curl_close($curl);
echo $response;
  • Method: GET

  • URL: https://yourdomain.docebosaas.com/learningplan/v1/learningplans/123/enrollments

  • Headers: Authorization: Bearer YOUR_ACCESS_TOKEN

Response

Returns an items array of enrollments. For certifications, completed items include:

  • award

  • previous_award


Enroll a user in a learning plan or certification

POST /learningplan/v1/learningplans/{lp_id}/enrollments/{user_id}

Permission required: enrollment/lp/manage.

What it does: Enrolls a single user in a Learning Plan or Certification.

Please note: status: "completed" is accepted for standard Learning Plans but rejected for certifications. See Deprecated and changed API calls.

Parameters

Parameter

Location

Type

Required

Description

lp_id

path

integer

Yes

The Learning Plan / certification ID.

user_id

path

integer

Yes

The user to enroll.

status

body

string

No

Initial enrollment status. Not completed for certifications. If you pass completed for a certification, the call returns a 404 error with code 1014, Learning plan not found.

assignment_type

body

string

No

The assignment type of the enrollment. You can pass this value only when the attribute is enabled in the platform advanced settings.

Possible values are:

  • mandatory

  • required

  • recommended

  • optional

validity_start_at

body

string

No

The start of the enrollment validity, in UTC and in the format YYYY-MM-DD hh:mm:ss.

validity_end_at

body

string

No

The end of the enrollment validity, in UTC and in the format YYYY-MM-DD hh:mm:ss.

Example calls

  • Go to:

    • Service Learning Plan

    • Grouping Enrollments

    • POST /learningplan/v1/learningplans/{lp_id}/enrollments/{user_id}

  • Enter lp_id and user_id

  • Click Try

const lpId = 123, userId = 456;
const response = await fetch(`https://yourdomain.docebosaas.com/learningplan/v1/learningplans/${lpId}/enrollments/${userId}`, {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({})
});
const data = await response.json();
console.log(data);
import requests
lp_id, user_id = 123, 456
url = f"https://yourdomain.docebosaas.com/learningplan/v1/learningplans/{lp_id}/enrollments/{user_id}"
headers = {
    "Authorization": "Bearer YOUR_ACCESS_TOKEN",
    "Content-Type": "application/json"
}
response = requests.post(url, headers=headers, json={})
print(response.json())
<?php
$lpId = 123; $userId = 456;
$curl = curl_init();
curl_setopt_array($curl, [
    CURLOPT_URL => "https://yourdomain.docebosaas.com/learningplan/v1/learningplans/{$lpId}/enrollments/{$userId}",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => "POST",
    CURLOPT_POSTFIELDS => json_encode([]),
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer YOUR_ACCESS_TOKEN",
        "Content-Type: application/json"
    ],
]);
$response = curl_exec($curl);
curl_close($curl);
echo $response;
  • Method: POST

  • URL: https://yourdomain.docebosaas.com/learningplan/v1/learningplans/123/enrollments/456

  • Headers: Authorization: Bearer YOUR_ACCESS_TOKEN, Content-Type: application/json

  • Body (raw, JSON): {}

Response

Returns the created enrollment.

Update a user's enrollment

PATCH /learningplan/v1/learningplans/{lp_id}/enrollments/{user_id}

Permission required: enrollment/lp/manage.

What it does: Updates a user's enrollment in a Learning Plan or Certification.

Please note: validity_dates_reset and status: "completed" are accepted for standard Learning Plans but both rejected for certifications (error 1016). A certification is completed only through the award operation, which creates the award and completes the enrollment together, so this call does not allow status: "completed". The validity dates of a certification follow the days of validity configured on the certification when the learner first accesses it, and on every renewal they come from the renewal window of the award, so this call does not allow validity_dates_reset either. See Deprecated and changed API calls.

To mark a user as having completed a certification, issue the award instead:

  • Single user: POST /learningplan/v1/learningplans/{lp_id}/users/{user_id}/award. The body requires completion_date, formatted as YYYY-MM-DD HH:mm:ss in UTC. The date cannot be in the future.

  • Multiple users: POST /learningplan/v1/learningplans/{lp_id}/award/bulk. The body requires items, a list of objects that each contain a user_id (between 1 and 2,000 items), and options.completion_date. The response is either synchronous with per-user results or asynchronous with a job_descriptor.

Both endpoints work only on learning plans of type certification.

Parameters

Parameter

Location

Type

Required

Description

lp_id

path

integer

Yes

The Learning Plan / certification ID.

user_id

path

integer

Yes

The enrolled user.

validity_dates_reset

body

boolean

No

Not accepted for certifications.

validity_start_at

body

string

No

The start of the enrollment validity, in UTC and in the format YYYY-MM-DD hh:mm:ss. Pass it together with validity_end_at.

validity_end_at

body

string

No

The end of the enrollment validity, in UTC and in the format YYYY-MM-DD hh:mm:ss. Pass it together with validity_start_at. If you pass only one of the two, the call returns error 1010.

enrolled_at

body

string

No

The enrollment date.

propagate_to_courses

body

boolean

No

If true, the new enrollment date also applies to the courses. This works only when you pass enrolled_at.

assignment_type

body

string

No

The assignment type of the enrollment. Possible values are mandatory, required, recommended and optional.

status

body

string

No

Not completed for certifications.

Example calls

  • Go to:

    • Service Learning Plan

    • Grouping Enrollments

    • PATCH /learningplans/{id}/enrollments/{user_id}

  • Enter lp_id/user_id

  • Click Try

const lpId = 123, userId = 456;
const response = await fetch(`https://yourdomain.docebosaas.com/learningplan/v1/learningplans/${lpId}/enrollments/${userId}`, {
  method: 'PATCH',
  headers: {
    'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({})
});
const data = await response.json();
console.log(data);
import requests
lp_id, user_id = 123, 456
url = f"https://yourdomain.docebosaas.com/learningplan/v1/learningplans/{lp_id}/enrollments/{user_id}"
headers = {
    "Authorization": "Bearer YOUR_ACCESS_TOKEN",
    "Content-Type": "application/json"
}
response = requests.patch(url, headers=headers, json={})
print(response.json())
<?php
$lpId = 123; $userId = 456;
$curl = curl_init();
curl_setopt_array($curl, [
    CURLOPT_URL => "https://yourdomain.docebosaas.com/learningplan/v1/learningplans/{$lpId}/enrollments/{$userId}",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => "PATCH",
    CURLOPT_POSTFIELDS => json_encode([]),
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer YOUR_ACCESS_TOKEN",
        "Content-Type: application/json"
    ],
]);
$response = curl_exec($curl);
curl_close($curl);
echo $response;
  • Method: PATCH

  • URL: https://yourdomain.docebosaas.com/learningplan/v1/learningplans/123/enrollments/456

  • Headers: Authorization: Bearer YOUR_ACCESS_TOKEN, Content-Type: application/json

  • Body (raw, JSON): {}

Response

Returns the updated enrollment.

Remove a user's enrollment

DELETE /learningplan/v1/learningplans/{lp_id}/enrollments/{user_id}

Permission required: enrollment/lp/manage.

What it does: Removes a user's enrollment from a Learning Plan or Certification.

Please note: For certifications, this removes the enrollment but does not revoke an already-issued certification award.

Parameters

Parameter

Location

Type

Required

Description

lp_id

path

integer

Yes

The Learning Plan / certification ID.

user_id

path

integer

Yes

The enrolled user.

unenroll_from_courses

body

boolean

No

If true, the user is also unenrolled from the courses of the Learning Plan. The user stays enrolled in courses that belong to other Learning Plan enrollments.

keep_in_progress

body

boolean

No

If true, the user is not unenrolled from courses that are in progress. This works only when unenroll_from_courses is true.

keep_completed

body

boolean

No

If true, the user is not unenrolled from courses that are completed. This works only when unenroll_from_courses is true.

Example calls

  • Go to:

    • Service Learning Plan

    • Grouping Enrollments

    • DELETE /learningplans/{id}/enrollments/{user_id}

  • Enter lp_id/user_id

  • Click Try

const lpId = 123, userId = 456;
const response = await fetch(`https://yourdomain.docebosaas.com/learningplan/v1/learningplans/${lpId}/enrollments/${userId}`, {
  method: 'DELETE',
  headers: { 'Authorization': 'Bearer YOUR_ACCESS_TOKEN' }
});
const data = await response.json();
console.log(data);
import requests
lp_id, user_id = 123, 456
url = f"https://yourdomain.docebosaas.com/learningplan/v1/learningplans/{lp_id}/enrollments/{user_id}"
headers = {"Authorization": "Bearer YOUR_ACCESS_TOKEN"}
response = requests.delete(url, headers=headers)
print(response.json())
<?php
$lpId = 123; $userId = 456;
$curl = curl_init();
curl_setopt_array($curl, [
    CURLOPT_URL => "https://yourdomain.docebosaas.com/learningplan/v1/learningplans/{$lpId}/enrollments/{$userId}",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => "DELETE",
    CURLOPT_HTTPHEADER => ["Authorization: Bearer YOUR_ACCESS_TOKEN"],
]);
$response = curl_exec($curl);
curl_close($curl);
echo $response;
  • Method: DELETE

  • URL: https://yourdomain.docebosaas.com/learningplan/v1/learningplans/123/enrollments/456

  • Headers: Authorization: Bearer YOUR_ACCESS_TOKEN

Response

Returns a confirmation of removal. Does not affect any previously issued award record.

Bulk enroll users

POST /learningplan/v1/learningplans/{lp_id}/enrollments/bulk

Permission required: enrollment/lp/manage.

What it does: Enrolls multiple users in a Learning Plan or Certification in one call.

Please note: options.status: "completed" is rejected for certifications, same as the single-user enroll call. See Deprecated and changed API calls.

Parameters (request body)

Parameter

Type

Required

Description

items

object

Yes

The users to enroll. This object contains:

  • user_ids (a list of user IDs)

  • group_ids (a list of group IDs)

  • branches (a list of branches)

Pass at least one of them.

options

object

No

Enrollment options. status: "completed" is not accepted for certifications.

Example calls

  • Go to:

    • Service Learning Plan

    • Grouping Enrollments

    • POST /learningplans/{id}/enrollments/bulk

  • Enter lp_id and body

  • Click Try

const lpId = 123;
const response = await fetch(`https://yourdomain.docebosaas.com/learningplan/v1/learningplans/${lpId}/enrollments/bulk`, {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ items: { user_ids: [456, 457, 458] } })
});
const data = await response.json();
console.log(data);
import requests
lp_id = 123
url = f"https://yourdomain.docebosaas.com/learningplan/v1/learningplans/{lp_id}/enrollments/bulk"
headers = {
    "Authorization": "Bearer YOUR_ACCESS_TOKEN",
    "Content-Type": "application/json"
}
payload = {"items": {"user_ids": [456, 457, 458]}}
response = requests.post(url, headers=headers, json=payload)
print(response.json())
<?php
$lpId = 123;
$curl = curl_init();
curl_setopt_array($curl, [
    CURLOPT_URL => "https://yourdomain.docebosaas.com/learningplan/v1/learningplans/{$lpId}/enrollments/bulk",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => "POST",
    CURLOPT_POSTFIELDS => json_encode(["items" => ["user_ids" => [456, 457, 458]]]),
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer YOUR_ACCESS_TOKEN",
        "Content-Type: application/json"
    ],
]);
$response = curl_exec($curl);
curl_close($curl);
echo $response;
  • Method: POST

  • URL: https://yourdomain.docebosaas.com/learningplan/v1/learningplans/123/enrollments/bulk

  • Headers: Authorization: Bearer YOUR_ACCESS_TOKEN, Content-Type: application/json

  • Body (raw, JSON): {"items": {"user_ids": [456, 457, 458]}}

Response

For a single user, processed synchronously. For more than one user, this is processed as a background job. Check the job status endpoint referenced in Overview of API services and endpoints.

Bulk update enrollments

PATCH /learningplan/v1/learningplans/{lp_id}/enrollments/bulk

Permission required: enrollment/lp/manage.

What it does: Updates multiple users' enrollments in a Learning Plan or Certification in one call.

Please note: options.validity_dates_reset and options.status: "completed" are both rejected for certifications. See Deprecated and changed API calls.

Parameters (request body)

Parameter

Type

Required

Description

items

array of objects

Yes

The enrollments to update. Each object contains the id of a user. Instead of items, you can pass items_by_properties to select enrollments with filters. Pass one of the two, not both.

options

object

Yes

Update options. You must pass at least one option field. Pass validity_start_at and validity_end_at together, because the call returns error 1010 if you pass only one of them. validity_dates_reset and status: "completed" not accepted for certifications.

Example calls

  • Go to:

    • Service Learning Plan

    • Grouping Enrollments

    • PATCH /learningplans/{id}/enrollments/bulk

  • Enter lp_id and body

  • Click Try

const lpId = 123;
const response = await fetch(`https://yourdomain.docebosaas.com/learningplan/v1/learningplans/${lpId}/enrollments/bulk`, {
  method: 'PATCH',
  headers: {
    'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ items: [{ id: 456 }, { id: 457 }], options: { validity_start_at: '2026-11-01 00:00:00', validity_end_at: '2027-12-31 23:59:59' } })
});
const data = await response.json();
console.log(data);
import requests
lp_id = 123
url = f"https://yourdomain.docebosaas.com/learningplan/v1/learningplans/{lp_id}/enrollments/bulk"
headers = {
    "Authorization": "Bearer YOUR_ACCESS_TOKEN",
    "Content-Type": "application/json"
}
payload = {"items": [{"id": 456}, {"id": 457}], "options": {"validity_start_at": "2026-11-01 00:00:00", "validity_end_at": "2027-12-31 23:59:59"}}
response = requests.patch(url, headers=headers, json=payload)
print(response.json())
<?php
$lpId = 123;
$curl = curl_init();
curl_setopt_array($curl, [
    CURLOPT_URL => "https://yourdomain.docebosaas.com/learningplan/v1/learningplans/{$lpId}/enrollments/bulk",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => "PATCH",
    CURLOPT_POSTFIELDS => json_encode(["items" => [["id" => 456], ["id" => 457]], "options" => ["validity_start_at" => "2026-11-01 00:00:00", "validity_end_at" => "2027-12-31 23:59:59"]]),
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer YOUR_ACCESS_TOKEN",
        "Content-Type: application/json"
    ],
]);
$response = curl_exec($curl);
curl_close($curl);
echo $response;
  • Method: PATCH

  • URL: https://yourdomain.docebosaas.com/learningplan/v1/learningplans/123/enrollments/bulk

  • Headers: Authorization: Bearer YOUR_ACCESS_TOKEN, Content-Type: application/json

  • Body (raw, JSON): {"items": [{"id": 456}, {"id": 457}], "options": {"validity_start_at": "2026-11-01 00:00:00", "validity_end_at": "2027-12-31 23:59:59"}}

Response

Processed as a background job for more than one user. Check job status as noted.

Bulk remove enrollments

DELETE /learningplan/v1/learningplans/{lp_id}/enrollments/bulk

Permission required: enrollment/lp/manage.

What it does: Removes multiple users' enrollments from a Learning Plan or Certification in one call.

Please note: Same as the single-user removal: for certifications, this does not revoke previously issued awards.

Parameters (request body)

Parameter

Type

Required

Description

items

array of objects

Yes

The enrollments to remove. Each object contains the id of a user. Instead of items, you can pass items_by_properties to select enrollments with filters. Pass one of the two, not both.

Example calls

  • Go to:

    • Service Learning Plan

    • Grouping Enrollments

    • DELETE /learningplans/{id}/enrollments/bulk

  • Enter lp_id and body

  • Click Try

const lpId = 123;
const response = await fetch(`https://yourdomain.docebosaas.com/learningplan/v1/learningplans/${lpId}/enrollments/bulk`, {
  method: 'DELETE',
  headers: {
    'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ items: [{ id: 456 }, { id: 457 }] })
});
const data = await response.json();
console.log(data);
import requests
lp_id = 123
url = f"https://yourdomain.docebosaas.com/learningplan/v1/learningplans/{lp_id}/enrollments/bulk"
headers = {
    "Authorization": "Bearer YOUR_ACCESS_TOKEN",
    "Content-Type": "application/json"
}
payload = {"items": [{"id": 456}, {"id": 457}]}
response = requests.delete(url, headers=headers, json=payload)
print(response.json())
<?php
$lpId = 123;
$curl = curl_init();
curl_setopt_array($curl, [
    CURLOPT_URL => "https://yourdomain.docebosaas.com/learningplan/v1/learningplans/{$lpId}/enrollments/bulk",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => "DELETE",
    CURLOPT_POSTFIELDS => json_encode(["items" => [["id" => 456], ["id" => 457]]]),
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer YOUR_ACCESS_TOKEN",
        "Content-Type: application/json"
    ],
]);
$response = curl_exec($curl);
curl_close($curl);
echo $response;
  • Method: DELETE

  • URL: https://yourdomain.docebosaas.com/learningplan/v1/learningplans/123/enrollments/bulk

  • Headers: Authorization: Bearer YOUR_ACCESS_TOKEN, Content-Type: application/json

  • Body (raw, JSON): {"items": [{"id": 456}, {"id": 457}]}

Response

Processed as a background job for more than one user.

Issue an award to a user

POST /learningplan/v1/learningplans/{learning_plan_id}/users/{user_id}/award

What it does: Issues an award to a user for a certification. Use this endpoint to record that a user completed a certification, for example when the learner completed the training outside the platform. The learning plan must be a certification ("type": 2).

Parameters

Parameter

Type

Required

Description

learning_plan_id

integer (path)

Yes

The ID of the certification.

user_id

integer (path)

Yes

The ID of the user who receives the award.

completion_date

string (body)

Yes

The completion date of the award, in UTC and in the format YYYY-MM-DD HH:mm:ss. The date cannot be in the future.

Example calls

  • Go to:

    • Service Learning Plan

    • Grouping Awards

    • POST /learningplans/{learning_plan_id}/users/{user_id}/award

  • Enter learning_plan_id, user_id and the body

  • Click Try

const lpId = 123;
const userId = 456;
const response = await fetch(`https://yourdomain.docebosaas.com/learningplan/v1/learningplans/${lpId}/users/${userId}/award`, {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ completion_date: '2026-11-01 10:00:00' })
});
const data = await response.json();
console.log(data);
import requests
lp_id = 123
user_id = 456
url = f"https://yourdomain.docebosaas.com/learningplan/v1/learningplans/{lp_id}/users/{user_id}/award"
headers = {
    "Authorization": "Bearer YOUR_ACCESS_TOKEN",
    "Content-Type": "application/json"
}
payload = {"completion_date": "2026-11-01 10:00:00"}
response = requests.post(url, headers=headers, json=payload)
print(response.json())
<?php
$lpId = 123;
$userId = 456;
$curl = curl_init();
curl_setopt_array($curl, [
    CURLOPT_URL => "https://yourdomain.docebosaas.com/learningplan/v1/learningplans/{$lpId}/users/{$userId}/award",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => "POST",
    CURLOPT_POSTFIELDS => json_encode(["completion_date" => "2026-11-01 10:00:00"]),
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer YOUR_ACCESS_TOKEN",
        "Content-Type: application/json"
    ],
]);
$response = curl_exec($curl);
curl_close($curl);
echo $response;
  • Method: POST

  • URL: https://yourdomain.docebosaas.com/learningplan/v1/learningplans/123/users/456/award

  • Headers: Authorization: Bearer YOUR_ACCESS_TOKEN, Content-Type: application/json

  • Body (raw, JSON): {"completion_date": "2026-11-01 10:00:00"}

Response

The response contains data.success (boolean) and version.

Errors

Code

Description

1000

Generic error.

1001

Invalid parameter.

1002

Missing parameter.

3001

An error occurred while creating the award for the learning plan and the user.

Issue awards in bulk

POST /learningplan/v1/learningplans/{learning_plan_id}/award/bulk

What it does: Issues awards to multiple users for a certification in one call. The items and options objects are both required. The learning plan must be a certification ("type": 2).

Parameters

Parameter

Type

Required

Description

learning_plan_id

integer (path)

Yes

The ID of the certification.

items

array of objects (body)

Yes

The users who receive the award. Each object contains a user_id. You can pass from 1 to 2,000 items.

options.completion_date

string (body)

Yes

The completion date of the awards, in UTC and in the format YYYY-MM-DD HH:mm:ss. The date cannot be in the future.

Example calls

  • Go to:

    • Service Learning Plan

    • Grouping Awards

    • POST /learningplans/{learning_plan_id}/award/bulk

  • Enter learning_plan_id and the body

  • Click Try

const lpId = 123;
const response = await fetch(`https://yourdomain.docebosaas.com/learningplan/v1/learningplans/${lpId}/award/bulk`, {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    items: [{ user_id: 456 }, { user_id: 457 }],
    options: { completion_date: '2026-11-01 10:00:00' }
  })
});
const data = await response.json();
console.log(data);
import requests
lp_id = 123
url = f"https://yourdomain.docebosaas.com/learningplan/v1/learningplans/{lp_id}/award/bulk"
headers = {
    "Authorization": "Bearer YOUR_ACCESS_TOKEN",
    "Content-Type": "application/json"
}
payload = {
    "items": [{"user_id": 456}, {"user_id": 457}],
    "options": {"completion_date": "2026-11-01 10:00:00"}
}
response = requests.post(url, headers=headers, json=payload)
print(response.json())
<?php
$lpId = 123;
$curl = curl_init();
curl_setopt_array($curl, [
    CURLOPT_URL => "https://yourdomain.docebosaas.com/learningplan/v1/learningplans/{$lpId}/award/bulk",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => "POST",
    CURLOPT_POSTFIELDS => json_encode([
        "items" => [["user_id" => 456], ["user_id" => 457]],
        "options" => ["completion_date" => "2026-11-01 10:00:00"]
    ]),
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer YOUR_ACCESS_TOKEN",
        "Content-Type: application/json"
    ],
]);
$response = curl_exec($curl);
curl_close($curl);
echo $response;
  • Method: POST

  • URL: https://yourdomain.docebosaas.com/learningplan/v1/learningplans/123/award/bulk

  • Headers: Authorization: Bearer YOUR_ACCESS_TOKEN, Content-Type: application/json

  • Body (raw, JSON): {"items": [{"user_id": 456}, {"user_id": 457}], "options": {"completion_date": "2026-11-01 10:00:00"}}

Response

The call is processed synchronously or as a background job.

A synchronous response contains:

  • data.errors (boolean)

  • data.items, where each item has:

    • id

    • success

    • error_code

    • message

A background job response contains data.job_descriptor (with id and name). Check the job status endpoint referenced in Overview of API services and endpoints.

Errors

Code

Description

1001

Invalid parameter.

1002

Missing parameter.

1003

Error while creating the background job.

1004

The processing requires more operations than the maximum allowed.

Update the dates of an award

PATCH /learningplan/v1/awards/{award_id}/dates

What it does: Updates the completion date and the renewal window of one award.

Parameters

Parameter

Type

Required

Description

award_id

integer (path)

Yes

The ID of the award. Use the award.id value returned in List certifications to renew to find it.

completion_date

string (body)

No

The new completion date of the award, in UTC.

renewal_window

object (body)

No

The renewal window of the award. If you pass this object, you must include date_start.

renewal_window.date_start

string or null (body)

Yes, if you pass renewal_window

The start of the renewal window, as a UTC date. Pass null to remove the renewal window.

renewal_window.date_end

string or null (body)

No

The end of the renewal window, as a UTC date. The window ends at 23:59:59 on that date. You cannot set this value when date_start is null.

Example calls

  • Go to:

    • Service Learning Plan

    • Grouping Awards

    • PATCH /awards/{award_id}/dates

  • Enter award_id and the body

  • Click Try

const awardId = 789;
const response = await fetch(`https://yourdomain.docebosaas.com/learningplan/v1/awards/${awardId}/dates`, {
  method: 'PATCH',
  headers: {
    'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ completion_date: '2026-11-01 10:00:00' })
});
const data = await response.json();
console.log(data);
import requests
award_id = 789
url = f"https://yourdomain.docebosaas.com/learningplan/v1/awards/{award_id}/dates"
headers = {
    "Authorization": "Bearer YOUR_ACCESS_TOKEN",
    "Content-Type": "application/json"
}
payload = {"completion_date": "2026-11-01 10:00:00"}
response = requests.patch(url, headers=headers, json=payload)
print(response.json())
<?php
$awardId = 789;
$curl = curl_init();
curl_setopt_array($curl, [
    CURLOPT_URL => "https://yourdomain.docebosaas.com/learningplan/v1/awards/{$awardId}/dates",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => "PATCH",
    CURLOPT_POSTFIELDS => json_encode(["completion_date" => "2026-11-01 10:00:00"]),
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer YOUR_ACCESS_TOKEN",
        "Content-Type: application/json"
    ],
]);
$response = curl_exec($curl);
curl_close($curl);
echo $response;
  • Method: PATCH

  • URL: https://yourdomain.docebosaas.com/learningplan/v1/awards/789/dates

  • Headers: Authorization: Bearer YOUR_ACCESS_TOKEN, Content-Type: application/json

  • Body (raw, JSON): {"completion_date": "2026-11-01 10:00:00"}

Response

The response contains data.success (boolean).

Errors

Code

Description

1000

Award not found.

1001

Invalid parameter.

1002

Missing parameter.

1003

Data parsing error.

Update the dates of multiple awards

PATCH /learningplan/v1/learningplans/{learning_plan_id}/awards/dates/bulk

What it does: Updates the completion date, the expiration date and the renewal window of multiple awards of a certification in one call. The options object is required, and it must contain at least one of its fields.

Parameters

Parameter

Type

Required

Description

learning_plan_id

integer (path)

Yes

The ID of the certification.

items

array of objects (body)

Yes

The awards to update. Each object contains an award_id. You can pass from 1 to 2,000 items.

options.completion_date

string (body)

No

The new completion date, in UTC. The value cannot be null.

options.expiration_date

string or null (body)

No

The new expiration date, as a UTC date. Pass null to remove the expiration date.

options.renewal_window.date_start

string or null (body)

Yes, if you pass renewal_window

The start of the renewal window, in UTC. Pass null to remove the renewal window.

options.renewal_window.date_end

string or null (body)

No

The end of the renewal window, in UTC. This value cannot be set when date_start is null.

Example calls

  • Go to:

    • Service Learning Plan

    • Grouping Awards

    • PATCH /learningplans/{learning_plan_id}/awards/dates/bulk

  • Enter learning_plan_id and the body

  • Click Try

const lpId = 123;
const response = await fetch(`https://yourdomain.docebosaas.com/learningplan/v1/learningplans/${lpId}/awards/dates/bulk`, {
  method: 'PATCH',
  headers: {
    'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    items: [{ award_id: 789 }, { award_id: 790 }],
    options: {
      completion_date: '2026-11-01 10:00:00',
      expiration_date: '2027-11-01'
    }
  })
});
const data = await response.json();
console.log(data);
import requests
lp_id = 123
url = f"https://yourdomain.docebosaas.com/learningplan/v1/learningplans/{lp_id}/awards/dates/bulk"
headers = {
    "Authorization": "Bearer YOUR_ACCESS_TOKEN",
    "Content-Type": "application/json"
}
payload = {
    "items": [{"award_id": 789}, {"award_id": 790}],
    "options": {
        "completion_date": "2026-11-01 10:00:00",
        "expiration_date": "2027-11-01"
    }
}
response = requests.patch(url, headers=headers, json=payload)
print(response.json())
<?php
$lpId = 123;
$curl = curl_init();
curl_setopt_array($curl, [
    CURLOPT_URL => "https://yourdomain.docebosaas.com/learningplan/v1/learningplans/{$lpId}/awards/dates/bulk",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => "PATCH",
    CURLOPT_POSTFIELDS => json_encode([
        "items" => [["award_id" => 789], ["award_id" => 790]],
        "options" => [
            "completion_date" => "2026-11-01 10:00:00",
            "expiration_date" => "2027-11-01"
        ]
    ]),
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer YOUR_ACCESS_TOKEN",
        "Content-Type: application/json"
    ],
]);
$response = curl_exec($curl);
curl_close($curl);
echo $response;
  • Method: PATCH

  • URL: https://yourdomain.docebosaas.com/learningplan/v1/learningplans/123/awards/dates/bulk

  • Headers: Authorization: Bearer YOUR_ACCESS_TOKEN, Content-Type: application/json

  • Body (raw, JSON): {"items": [{"award_id": 789}, {"award_id": 790}], "options": {"completion_date": "2026-11-01 10:00:00", "expiration_date": "2027-11-01"}}

Response

The call is processed synchronously or as a background job.

A synchronous response contains:

  • data.errors (boolean)

  • data.items, where each item has:

    • award_id

    • success

    • error_code

    • error_message

A background job response contains data.job_descriptor. Check the job status endpoint referenced in Overview of API services and endpoints.

Errors

Code

Description

1000

Generic error.

1001

Invalid parameter.

1002

Missing parameter.

1003

Error while creating the background job.

1004

The processing requires more operations than the maximum allowed.

1005

Invalid learning plan ID.

1014

Learning plan not found.

For an individual item, the possible error codes are 1000 (something went wrong), 1404 (invalid item) and 1403 (permission denied).

List certifications to renew

GET /learningplan/v1/awards/to_renew

What it does: Returns the certifications that are eligible for renewal, including both new certifications and legacy certifications. This is the data behind the Certifications to Renew widget.

Parameters (query string)

Parameter

Type

Required

Description

status

string

No

Filters by award status.

Possible values are:

  • valid

  • expired

  • expiring

  • in_renewal

sort_attr

string

No

The field to sort by. Default expiration_date.

sort_dir

string

No

The sort direction. Default asc.

page

integer

No

The page number.

page_size

integer

No

The number of items per page.

Example calls

  • Go to:

    • Service Learning Plan

    • Grouping Awards

    • GET /awards/to_renew

  • Enter the query parameters

  • Click Try

const response = await fetch('https://yourdomain.docebosaas.com/learningplan/v1/awards/to_renew?status=expiring&page=1&page_size=10', {
  method: 'GET',
  headers: {
    'Authorization': 'Bearer YOUR_ACCESS_TOKEN'
  }
});
const data = await response.json();
console.log(data);
import requests
url = "https://yourdomain.docebosaas.com/learningplan/v1/awards/to_renew"
headers = {"Authorization": "Bearer YOUR_ACCESS_TOKEN"}
params = {"status": "expiring", "page": 1, "page_size": 10}
response = requests.get(url, headers=headers, params=params)
print(response.json())
<?php
$curl = curl_init();
curl_setopt_array($curl, [
    CURLOPT_URL => "https://yourdomain.docebosaas.com/learningplan/v1/awards/to_renew?status=expiring&page=1&page_size=10",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => "GET",
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer YOUR_ACCESS_TOKEN"
    ],
]);
$response = curl_exec($curl);
curl_close($curl);
echo $response;
  • Method: GET

  • URL: https://yourdomain.docebosaas.com/learningplan/v1/awards/to_renew?status=expiring&page=1&page_size=10

  • Headers: Authorization: Bearer YOUR_ACCESS_TOKEN

Response

Each item in the response has the following fields:

  • id

  • type (legacy_certification or new_certification)

  • title

  • language

  • assigned_courses_count

  • duration_minutes

  • enrollment_status

  • enrollment_date

  • enrollment_validity_date_start

  • enrollment_validity_date_end

  • cover_img_url

  • can_enter

  • can_enter_reason

Legacy certifications also return:

  • expiration_date

  • award_date

  • in_renew

New certifications return an award object with:

  • id

  • status (valid, expiring or expired)

  • expiration_date

  • award_date

  • in_renew

  • renew_date

  • renewal_mode (anytime or window)

  • renewal_window_date_start

  • renewal_window_date_end

The response also contains the paging fields:

  • count

  • has_more_data

  • current_page

  • current_page_size

  • total_page_count

  • total_count

  • sort