Skip to main content

Courses

A course is an online course in your workspace: its lessons, its look, its settings, and its certificate template. The Courses API lives at /players. It lists and creates courses, reads and updates one course, and publishes or unpublishes it. Lessons, header links, the certificate, the paywall, comments, and analytics have their own routes under the course.

Overview​

A course created through the API starts as draft. List Courses returns the Course Object. Create, publish, and unpublish return that object plus preview_url. Update Course also returns draft_version and draft_updated_at. Get Course returns the Course Detail.

Lessons are the ordered curriculum. Header links are the items in the course header. The certificate is the template printed when a learner earns a certificate. The paywall links existing Easycart products to the course. Comments are the live question threads. Analytics are the live numbers for students, visits, lesson completion, and certificates. Lessons and header links are separate collections, each with its own ids. A paywall row is addressed by the Easycart product UUID. A comment id is the comment UUID.

Endpoints​

MethodEndpointDescription
POST/playersCreate a course
GET/playersList courses
GET/players/{id}Get a course
PATCH/players/{id}Update a course
PATCH/players/{id}/stylesUpdate styles
PATCH/players/{id}/layoutUpdate layout
PATCH/players/{id}/settingsUpdate settings
POST/players/{id}/publishPublish a course
POST/players/{id}/unpublishUnpublish a course

Lesson routes are under Lessons. Header-link routes are under Header links. Certificate routes are under Certificate. Paywall routes are under Paywall. Comment routes are under Comments. Analytics routes are under Analytics. HTTP paths stay /players/{id}/files, /players/{id}/header-links, /players/{id}/certificate, /players/{id}/products, /players/{id}/comments, /players/{id}/files/comment-counts, /players/{playerId}/files/{fileId}/comments, and /players/{id}/analytics.

Course Object​

Every field is present. A missing timestamp is null, not an omitted key.

FieldTypeDescription
idstringImmutable identifier (UUID)
slugstringURL label. It can change. The API does not address a course by its slug.
namestringDisplay name. Maximum 255 characters. Always the live name.
statusstringdraft or published
created_atstring|nullISO 8601 timestamp (UTC)
updated_atstring|nullISO 8601 timestamp (UTC)
published_atstring|nullWhen the course was published, or null while it is a draft
has_draftbooleantrue when a published course has saved edits that publish has not applied yet. false after publish or unpublish. See Draft, preview, and publish.

Course Detail​

Get Course returns the Course Object plus the fields below. Every include key is present.

FieldTypeDescription
public_urlstringLive visitor URL, https://app.easy.tools/players/{slug}. Returned for a draft and for a published course.
preview_urlstringSigned preview link, minted for this response and lasting one hour. See Preview.
draft_versionintegerCurrent draft counter. See Draft version.
draft_updated_atstring|nullWhen the draft was last saved. On a course with status draft, this is the course's updated_at. On a published course it is when the pending edits were last saved, or null when there are none, including right after publish.
stylesobject|nullStyles Object when include contains styles, otherwise null
layoutobject|nullLayout Object when include contains layout, otherwise null
settingsobject|nullSettings Object when include contains settings, otherwise null
filesarray|nullEvery Lesson Object, in order, when include contains files. Otherwise null. This is the whole curriculum, not a page. An empty curriculum is [].
header_linksarray|nullEvery Header Link Object, in order, when include contains header_links. Otherwise null. This is the whole collection, not a page. An empty collection is [].
certificateobject|nullCertificate Object when include contains certificate, otherwise null. When no template has been saved, these are the starting values.
productsarray|nullEvery Product Link Object when include contains products. Otherwise null. This is the live paywall, the whole collection, not a page. Zero links is [].

Draft, preview, and publish​

Updates to the styles, layout, settings, and certificate, and creates, updates, deletes, and reorders of lessons and header links, are draft writes. What they change depends on status:

  • draft course. Visitors cannot see the course, so a write changes the course itself. Nothing is left pending: has_draft is false after the write, and draft_updated_at is the course's updated_at. A deleted lesson or header link is gone for good.
  • published course. A write saves pending edits. Visitors keep seeing the live course until you publish. has_draft is true while pending edits exist. A deleted lesson or header link stays on the live course until you publish.

Reads of the course, its certificate template, its lessons, and its header links include pending edits when there are any. Some changes are never pending: a rename with Update Course and every paywall write change the live course immediately, and publish does not change them. Comment and analytics reads are always the live course.

Publish Course makes the course public, then applies the pending edits. Unpublish Course makes the course private at once, then folds the pending edits into the course. After either call has_draft is false.

Draft version​

Every draft write sends draft_version, the integer from Get Course. It is 1 before anything has been saved. A successful write returns the next integer and draft_updated_at. Omitting draft_version, or sending a value below 1, is 422. A value that is not the current counter is 409:

{
"error": {
"code": "CONFLICT",
"message": "The draft was edited elsewhere. GET the draft and retry with the current draft_version."
}
}

Read the course and retry with the draft_version from that response.

Create Course, Publish Course, and Unpublish Course do not send draft_version and do not return it. Publish and unpublish never reset the counter, but each increases it by 1 when it applies pending edits. A write that still sends the value read before that call gets 409, so read the course again after publish or unpublish before the next draft write. Paywall writes do not use draft_version.

Preview​

preview_url is a signed link to the course as it would look with its pending edits. It is minted for that response, is not saved, and lasts one hour. Get Course, create, each draft write that returns a body, publish, and unpublish each mint a new one. Paywall writes do not. On one object, preview_url is a field of data. A reorder returns a list, so preview_url, draft_version, and draft_updated_at sit beside data. Delete is 204 with no body.

The link has the shape https://app.easy.tools/players/{id}/preview?expires={unix time}&signature={signature}, where {id} is the course UUID. It uses the same origin as public_url.

public_url is the live visitor link, https://app.easy.tools/players/{slug}. Only Get Course returns it, for a draft and for a published course.

List Courses, the lesson and header-link lists and gets, the paywall list, and the comment and analytics reads have no preview_url.

Include​

include on Get Course is a comma-separated list of styles, layout, settings, files, header_links, certificate, and products. Spaces around a token are ignored. A token outside that list returns 422. Leave a token out and that key is null. Requested products is the live paywall, the whole collection, not a page.

Identifiers​

A course id, a lesson id, a header link id, and a comment id are UUIDs. The course id is {id} or {playerId} in the path. A lesson or header link id is the {id} beside it. On a lesson thread, the lesson id is {fileId}. A paywall {productId} is an Easycart product UUID. A student id is 32 hexadecimal characters, and a certificate id is a short URL-safe id; neither is a UUID. See Paywall, Comments, and Analytics.

A course id that is missing or not a UUID returns 404. A lesson or header link id that is missing, that is not on that course, or that is not a UUID returns 404. On a comment read, a heading or a lesson that is not on the live course returns 404. A file filter that is not a UUID returns 422. A product that Easycart resolves and that is not linked to the course returns 404 on update and disconnect. A product UUID that Easycart does not resolve returns 422. The 404 body is:

{
"error": {
"code": "RESOURCE_NOT_FOUND",
"message": "Resource not found"
}
}

Updates​

Update Course and the styles, layout, settings, and certificate updates change only the keys you send. A nested object, such as layout.header or certificate.content, merges the same way. Omit a key to leave the stored value. These are draft writes and do not publish. name is the exception: a rename changes the live course immediately, also on a published course.

Create Course accepts the same section objects. { "name" } alone still creates a draft and keeps the starting values. Sections on that request are saved on the new course, which is a draft and not visible to visitors. Read a section from Get Course or from that section's route.

Do not send files, header_links, or products on create or update. Lessons, header links, and the paywall have their own routes.

Where a field can be cleared, the object table says null clears it. On every other field, null returns 422.

Styles Object​

Colors and the theme are strings. A new course starts with the values in the table.

FieldTypeDescription
themestringTheme name. Starts as light.
font_familystringFont name. Starts as Inter.
main_colorstringAccent color. Starts as #F6083D.
background_colorstringPage background. Starts as #f9fafb.
text_colorstringBody text color. Starts as #0e0f11.
header_colorstringHeader color. Starts as #fff.
heading_colorstringHeading color. Starts as #3c404b.
border_colorstringBorder color. Starts as #e0e3e6.

Layout Object​

Navigation labels start in the account's language. The English starting values are in the table. page_title and icon_url start the same for every account.

FieldTypeDescription
page_titlestringBrowser title. Starts as Easyplayer.
icon_urlstringFavicon address. Starts as /assets/easyplayer.png.
sidebar_titlestringSidebar heading. On an English account, starts as Files list:.
previous_labelstringPrevious control. On an English account, starts as Previous file.
next_labelstringNext control. On an English account, starts as Next file.
mark_done_labelstringMark-done control. On an English account, starts as Mark as done.
finished_labelstringFinished label. On an English account, starts as Lesson finished.
headerobjectHeader Object
footerobjectFooter Object

Header Object​

FieldTypeDescription
is_visiblebooleanWhether the header is shown. Starts true.
logo_urlstringLogo address. Starts as /assets/easyplayer.png.
FieldTypeDescription
is_visiblebooleanWhether the footer is shown. Starts true.
textstringFooter text. Starts as "".
policy_urlstringPrivacy policy address. Starts as /policy.
terms_urlstringTerms address. Starts as /terms.

Settings Object​

FieldTypeDescription
release_atstring|nullWhen the course opens, as an ISO 8601 timestamp with a Z suffix. null means it is open, and null clears a stored time. Starts null.
before_release_urlstring|nullAddress used before release_at. null clears it. Starts null.
webhook_urlstringWhere course webhooks are sent. A public https URL, at most 1024 characters. "" clears it. Any other value, including null, an http URL, or a private or link-local address, returns 422. Starts as "".
webhooksobjectWebhooks Object

Webhooks Object​

Each flag turns on one webhook. Omit a flag to leave it unchanged.

FieldTypeDescription
lesson_finishedbooleanA learner marked a lesson finished. Starts true.
lesson_unfinishedbooleanA learner cleared that mark. Starts true.
lesson_viewedbooleanA learner opened a lesson. Starts false.
certificate_issuedbooleanA certificate was issued. Starts false.
course_finishedbooleanA learner finished the course. Starts false.

Status​

StatusMeaning
draftNot published. published_at is null.
publishedPublished. published_at is the publish time.