API リファレンス
Deliverable units
Management API: PUT /sites/{id}/deliverables/{deliverableId}/units, POST /sites/{id}/deliverables/{deliverableId}/units/reorder, PATCH /sites/{id}/deliverable-units/{unitId}, …
Replace tree
/sites/{id}/deliverables/{deliverableId}/unitsReplace the whole chapter/unit tree of a deliverable (PUT semantics): units with an id are updated, units without an id are created, units missing from the payload are deleted along with learner progress on them. Two levels only: top-level nodes may have children; children cannot. For a flat download bundle just pass units without children. Unit files (primaryAssetId / attachmentAssetIds) must be protected files: upload them with media.upload (visibility "protected", up to 40 MB as base64 or 100 MB by url) or media.request_upload + media.confirm_upload (up to 5 GB), or reuse a product file from media.list (assetKind "product"). Protected files are only served to buyers through signed short-lived links; public files are rejected because anyone with the link could open them. Errors: FORBIDDEN, DELIVERABLE_NOT_FOUND, UNIT_TREE_INVALID (details.reason), ASSET_NOT_FOUND (details.assetIds: not in the media library, in the trash or an older version), ASSET_NOT_ALLOWED (details.assetIds: public files; unit files must be protected files), VALIDATION.
Parameters
idstring · pathrequiredWebsite id. Get it from sites.list or from sites.create.
deliverableIdstring · pathrequiredDeliverable id. Get it from deliverables.list.
Request body
unitsobject[]requiredunits[].idstringunits[].kindstringrequiredunits[].titlestring | nullunits[].descriptionstring | nullunits[].primaryAssetIdstring | nullunits[].attachmentAssetIdsstring[]units[].embedobject | nullunits[].embed.provider"youtube" | "vimeo" | "loom"requiredunits[].embed.idstringrequiredunits[].bodyanyunits[].isPreviewbooleanunits[].visibility"VISIBLE" | "HIDDEN"units[].releaseAtstring | nullunits[].releaseAfterDaysinteger | nullunits[].allowDownloadbooleanunits[].countsTowardCompletionbooleanunits[].isPrerequisitebooleanunits[].childrenobject[]units[].children[].idstringunits[].children[].kindstringrequiredunits[].children[].titlestring | nullunits[].children[].descriptionstring | nullunits[].children[].primaryAssetIdstring | nullunits[].children[].attachmentAssetIdsstring[]units[].children[].embedobject | nullunits[].children[].bodyanyunits[].children[].isPreviewbooleanunits[].children[].visibility"VISIBLE" | "HIDDEN"units[].children[].releaseAtstring | nullunits[].children[].releaseAfterDaysinteger | nullunits[].children[].allowDownloadbooleanunits[].children[].countsTowardCompletionbooleanunits[].children[].isPrerequisiteboolean
Response 200
idstringrequiredtitlestringrequireddescriptionstring | nullrequiredcoverAssetIdstring | nullrequiredstructure"COURSE" | "DOWNLOAD"requiredCOURSE has chapters and tracks progress; DOWNLOAD is a flat file list (no progress, new units allow download by default). Access rules are identical.
status"ACTIVE" | "ARCHIVED"requiredgrantsstring[]requiredCommercial feature keys (e.g. ["premium"]) granted when a buyer purchases or is granted this deliverable; matched by ContentCollection.accessPolicy and entitlements.check.
authorIdsstring[]requiredAuthors/instructors shown on the sales page and the learner page, in order. Ids come from the site's shared author list (also used by posts; managed in the console under Posts › Settings).
unitCountintegerrequiredLeaf units only; chapters are not counted.
productIdsstring[]requiredProducts that grant this deliverable on purchase (see products.update deliverables).
createdAtstringrequiredupdatedAtstringrequiredsettingsobjectrequiredsettings.completionRuleobjectrequiredsettings.completionRule.type"all_units"requiredsettings.certificateobjectrequiredWhen enabled, a certificate (serial + issue date) is issued the first time a learner completes the deliverable; learners fetch it with Customer API GET /deliverables/:id/certificate. The PDF is generated on download from the current settings, course title, learner name and site branding (logo, brand colour), so edits apply to every certificate; only the serial and issue date are fixed. Send every certificate field when updating it. Use deliverables.certificate_preview to see it.
settings.certificate.enabledbooleanrequiredsettings.certificate.titlestring | nullrequiredCertificate heading; null = the site-language default ("Certificate of Completion").
settings.certificate.signatureNamestring | nullrequiredSigner's name or organisation; null = no signature block.
settings.certificate.signatureTitlestring | nullrequiredSigner's title printed under the name, e.g. "Lead instructor".
settings.certificate.signatureAssetIdstring | nullrequiredSignature image: a public image asset id (same rule as coverAssetId); printed above the signature line.
settings.certificate.showLogobooleanrequiredPrint the site's brand logo (site settings) at the top; icon logos are skipped.
settings.certificate.notestring | nullrequiredOne line printed under the course title, e.g. "12 hours of instruction".
settings.certificate.backgroundAssetIdstring | nullrequiredBackground image: a public image asset id (same rule as coverAssetId), centred and cropped to fill an A4 landscape page (recommended 3508 × 2480 px). When set, the default border is not drawn; text positions stay fixed, so keep the centre of the design clear.
settings.certificate.backgroundOverlaybooleanrequiredLay a semi-transparent white layer over the background image so text stays readable on busy designs; no effect without a background image.
settings.commentsobjectrequiredsettings.comments.enabledbooleanrequiredsettings.comments.threadedbooleanrequiredsettings.comments.requireReviewbooleanrequiredsettings.comments.reactionsbooleanrequiredsettings.requireSequentialbooleanrequiredLearners must complete each unit before opening the next (free-preview units are exempt). Locked units come back with access.reason prerequisite.
settings.mediaCompletionPercentintegerrequiredShare of a video/audio unit a learner must actually watch for it to count as completed (50-100, step 5, default 90). Measured from the segments played, so skipping to the end does not count; 100 keeps a 2-second tolerance at the end. Custom players that only report positionSeconds are measured by the furthest position. Raising it never un-completes learners.
fieldDataobject | nullrequiredunitsobject[]requiredFlat list ordered by chapter then unit; use parentId to rebuild the tree.
units[].idstringrequiredunits[].parentIdstring | nullrequiredChapter id for units inside a chapter; null for top-level chapters or flat units.
units[].orderintegerrequiredunits[].kindstringrequiredOpen string. Known values: video, audio, file, text, quiz; "chapter" for grouping rows. Unknown kinds render as a download card.
units[].titlestring | nullrequiredunits[].descriptionstring | nullrequiredunits[].primaryAssetIdstring | nullrequiredMedia-library asset (private products bucket). Upload with media.upload first.
units[].attachmentAssetIdsstring[]requiredunits[].fileUrlstring | nullrequiredOnly for Kanorio template sample media (not a media-library asset). Real files are referenced by primaryAssetId.
units[].embedobject | nullrequiredExternal video embed (youtube/vimeo/loom). Not protected by Kanorio; use for FREE sites that cannot host video.
units[].embed.providerstringrequiredunits[].embed.idstringrequiredunits[].bodyanyrequiredtext units: { markdown }. quiz units: { questions: [{ id, type: "single" | "multiple" | "true_false", prompt, options: [{ id, text, correct: boolean }], explanation? }], settings: { passingPercent (0-100, default 70), maxAttempts (1-99 or null = unlimited), showAnswers: "never" | "after_pass" | "always" } }; validated on write (UNIT_TREE_INVALID quiz_body_invalid). Learners never see correct/explanation; the server grades Customer API POST /units/:id/quiz.
units[].isPreviewbooleanrequiredFree preview: anonymous visitors can open it.
units[].visibility"VISIBLE" | "HIDDEN"requiredunits[].releaseAtstring | nullrequiredAbsolute unlock time.
units[].releaseAfterDaysinteger | nullrequiredUnlock N days after the learner's entitlement started.
units[].allowDownloadbooleanrequiredunits[].countsTowardCompletionbooleanrequiredfalse = bonus unit: not counted in percent or completion, never locked by requireSequential and never a gate for later units.
units[].isPrerequisitebooleanrequiredUnits after this one stay locked until the learner completes it, even when requireSequential is off.
productsobject[]requiredProducts (variants) that grant this deliverable; tierId null = every variant. Access duration is pricingTiers[].accessDays on the product.
products[].productIdstringrequiredproducts[].tierIdstring | nullrequiredchangesobjectrequiredchanges.createdintegerrequiredchanges.updatedintegerrequiredchanges.deletedintegerrequired
Errors
FORBIDDEN403DELIVERABLE_NOT_FOUND404UNIT_TREE_INVALID422 · details.reasonASSET_NOT_FOUND404 · details.assetIds: not in the media library, in the trash or an older versionASSET_NOT_ALLOWED422 · details.assetIds: public files; unit files must be protected filesVALIDATION400
MCP tool deliverable_units_replace_tree
curl -X PUT "https://app.kanorio.com/api/v1/sites/{id}/deliverables/{deliverableId}/units" \
-H "Authorization: Bearer $KANORIO_TOKEN" \
-H "Content-Type: application/json" \
-d '{"units":[{"kind":"chapter","title":"Week 1 · Getting started","children":[{"kind":"video","title":"Welcome and course overview","primaryAssetId":"asset_example01","isPreview":true},{"kind":"text","title":"Set up your workspace","body":{"markdown":"## Install\n\n1. Download the starter kit…"},"releaseAfterDays":2}]}]}'{
"id": "dlv_example01",
"title": "Sourdough Fundamentals",
"description": "Six-week video course with downloadable recipe cards.",
"coverAssetId": "asset_example01",
"structure": "COURSE",
"status": "ACTIVE",
"grants": [
"premium"
],
"authorIds": [
"author_headbaker01"
],
"unitCount": 3,
"productIds": [
"prod_example01"
],
"createdAt": "2026-10-01T02:30:00.000Z",
"updatedAt": "2026-10-06T08:00:00.000Z",
"settings": {
"completionRule": {
"type": "all_units"
},
"certificate": {
"enabled": false,
"title": null,
"signatureName": null,
"signatureTitle": null,
"signatureAssetId": null,
"showLogo": true,
"note": null,
"backgroundAssetId": null,
"backgroundOverlay": false
},
"comments": {
"enabled": false,
"threaded": true,
"requireReview": true,
"reactions": false
},
"requireSequential": false,
"mediaCompletionPercent": 90
},
"fieldData": null,
"units": [
{
"id": "unit_chapter01",
"parentId": null,
"order": 0,
"kind": "chapter",
"title": "Week 1 · Getting started",
"description": null,
"primaryAssetId": null,
"attachmentAssetIds": [],
"fileUrl": null,
"embed": null,
"body": null,
"isPreview": false,
"visibility": "VISIBLE",
"releaseAt": null,
"releaseAfterDays": null,
"allowDownload": false,
"countsTowardCompletion": true,
"isPrerequisite": false
},
{
"id": "unit_video01",
"parentId": "unit_chapter01",
"order": 0,
"kind": "video",
"title": "Welcome and course overview",
"description": "What you will build in six weeks.",
"primaryAssetId": "asset_example01",
"attachmentAssetIds": [],
"fileUrl": null,
"embed": null,
"body": null,
"isPreview": true,
"visibility": "VISIBLE",
"releaseAt": null,
"releaseAfterDays": null,
"allowDownload": false,
"countsTowardCompletion": true,
"isPrerequisite": false
},
{
"id": "unit_text01",
"parentId": "unit_chapter01",
"order": 1,
"kind": "text",
"title": "Set up your workspace",
"description": null,
"primaryAssetId": null,
"attachmentAssetIds": [],
"fileUrl": null,
"embed": null,
"body": {
"markdown": "## Install\n\n1. Download the starter kit…"
},
"isPreview": false,
"visibility": "VISIBLE",
"releaseAt": null,
"releaseAfterDays": 2,
"allowDownload": false,
"countsTowardCompletion": true,
"isPrerequisite": false
}
],
"products": [
{
"productId": "prod_example01",
"tierId": null
}
],
"changes": {
"created": 3,
"updated": 0,
"deleted": 0
}
}Reorder deliverable units
/sites/{id}/deliverables/{deliverableId}/units/reorderReorder sibling units: pass every id of one level (top level when parentId is null) in the new order. Errors: FORBIDDEN, DELIVERABLE_NOT_FOUND, UNIT_TREE_INVALID.
Parameters
idstring · pathrequiredWebsite id. Get it from sites.list or from sites.create.
deliverableIdstring · pathrequiredDeliverable id. Get it from deliverables.list.
Request body
parentIdstring | nullrequiredChapter id, or null for the top level.
orderedIdsstring[]required
Response 200
countintegerrequired
Errors
FORBIDDEN403DELIVERABLE_NOT_FOUND404UNIT_TREE_INVALID422
MCP tool deliverable_units_reorder
curl -X POST "https://app.kanorio.com/api/v1/sites/{id}/deliverables/{deliverableId}/units/reorder" \
-H "Authorization: Bearer $KANORIO_TOKEN" \
-H "Content-Type: application/json" \
-d '{"parentId":"unit_chapter01","orderedIds":["unit_text01","unit_video01"]}'{
"count": 2
}Update a deliverable unit
/sites/{id}/deliverable-units/{unitId}Update one unit in place (title, file, preview flag, unlock schedule, completion rules) without touching the tree. Every unit is available to everyone who has the deliverable; to sell extra content to a higher plan, put it in a separate deliverable and link it only to that plan (products.update deliverables[].tierId). Files must be protected files (see deliverable_units.replace_tree). Errors: FORBIDDEN, DELIVERABLE_NOT_FOUND, ASSET_NOT_FOUND (details.assetIds: not in the media library, in the trash or an older version), ASSET_NOT_ALLOWED (details.assetIds: public files; unit files must be protected files), VALIDATION.
Parameters
idstring · pathrequiredWebsite id. Get it from sites.list or from sites.create.
unitIdstring · pathrequiredUnit id. Get it from deliverables.get.
Request body
kindstringtitlestring | nulldescriptionstring | nullprimaryAssetIdstring | nullattachmentAssetIdsstring[]embedobject | nullembed.provider"youtube" | "vimeo" | "loom"requiredembed.idstringrequiredbodyanyisPreviewbooleanvisibility"VISIBLE" | "HIDDEN"releaseAtstring | nullreleaseAfterDaysinteger | nullallowDownloadbooleancountsTowardCompletionbooleanisPrerequisiteboolean
Response 200
idstringrequiredparentIdstring | nullrequiredChapter id for units inside a chapter; null for top-level chapters or flat units.
orderintegerrequiredkindstringrequiredOpen string. Known values: video, audio, file, text, quiz; "chapter" for grouping rows. Unknown kinds render as a download card.
titlestring | nullrequireddescriptionstring | nullrequiredprimaryAssetIdstring | nullrequiredMedia-library asset (private products bucket). Upload with media.upload first.
attachmentAssetIdsstring[]requiredfileUrlstring | nullrequiredOnly for Kanorio template sample media (not a media-library asset). Real files are referenced by primaryAssetId.
embedobject | nullrequiredExternal video embed (youtube/vimeo/loom). Not protected by Kanorio; use for FREE sites that cannot host video.
embed.providerstringrequiredembed.idstringrequiredbodyanyrequiredtext units: { markdown }. quiz units: { questions: [{ id, type: "single" | "multiple" | "true_false", prompt, options: [{ id, text, correct: boolean }], explanation? }], settings: { passingPercent (0-100, default 70), maxAttempts (1-99 or null = unlimited), showAnswers: "never" | "after_pass" | "always" } }; validated on write (UNIT_TREE_INVALID quiz_body_invalid). Learners never see correct/explanation; the server grades Customer API POST /units/:id/quiz.
isPreviewbooleanrequiredFree preview: anonymous visitors can open it.
visibility"VISIBLE" | "HIDDEN"requiredreleaseAtstring | nullrequiredAbsolute unlock time.
releaseAfterDaysinteger | nullrequiredUnlock N days after the learner's entitlement started.
allowDownloadbooleanrequiredcountsTowardCompletionbooleanrequiredfalse = bonus unit: not counted in percent or completion, never locked by requireSequential and never a gate for later units.
isPrerequisitebooleanrequiredUnits after this one stay locked until the learner completes it, even when requireSequential is off.
Errors
FORBIDDEN403DELIVERABLE_NOT_FOUND404ASSET_NOT_FOUND404 · details.assetIds: not in the media library, in the trash or an older versionASSET_NOT_ALLOWED422 · details.assetIds: public files; unit files must be protected filesVALIDATION400
MCP tool deliverable_units_update
curl -X PATCH "https://app.kanorio.com/api/v1/sites/{id}/deliverable-units/{unitId}" \
-H "Authorization: Bearer $KANORIO_TOKEN" \
-H "Content-Type: application/json" \
-d '{"title":"Welcome!","isPreview":true}'{
"id": "unit_video01",
"parentId": "unit_chapter01",
"order": 0,
"kind": "video",
"title": "Welcome!",
"description": "What you will build in six weeks.",
"primaryAssetId": "asset_example01",
"attachmentAssetIds": [],
"fileUrl": null,
"embed": null,
"body": null,
"isPreview": true,
"visibility": "VISIBLE",
"releaseAt": null,
"releaseAfterDays": null,
"allowDownload": false,
"countsTowardCompletion": true,
"isPrerequisite": false
}Deliverable unit insights
/sites/{id}/deliverables/{deliverableId}/unit-insightsPer-unit viewing and learning figures for one course: reached and completed learners, plays, viewers, watched seconds, average share watched, quick-exit rate (left within 15 seconds), stall rate, share of playback at 1.5x or faster, last play, quiz pass rate and the most-missed question; plus ranked symptoms (drop, rewatch, quick_exit, stall, fast, quiz). Pass unitId to also get that unit's 100-bucket retention curve (share of learners who watched each bucket, null under 5 learners), rewatch and seek curves and seek hotspots. Cumulative figures ignore the period; plays, viewers, watched seconds, rates and curves other than retention are for the period. Errors: FORBIDDEN, DELIVERABLE_NOT_FOUND, UNIT_NOT_FOUND, VALIDATION.
Parameters
idstring · pathrequiredWebsite id. Get it from sites.list or from sites.create.
deliverableIdstring · pathrequiredDeliverable id. Get it from deliverables.list.
unitIdstring · queryAlso return the retention curve of this unit (must belong to the course).
daysinteger · queryNumber of calendar days ending today in the website's timezone (1 to 365, defaults to 30). Ignored when from and to are provided.
fromstring · queryStart calendar date (YYYY-MM-DD) in the website's timezone, inclusive. Must be paired with to.
tostring · queryEnd calendar date (YYYY-MM-DD) in the website's timezone, inclusive, up to today. Must be paired with from.
Response 200
rangeobjectrequiredrange.fromstringrequiredFirst calendar date of the period (website timezone).
range.tostringrequiredLast calendar date of the period (website timezone).
range.timezonestringrequiredunitsobject[]requiredunits[].unitIdstringrequiredunits[].titlestringrequiredunits[].kindstringrequiredunits[].reachedintegerrequiredCumulative learners who opened the unit.
units[].completedintegerrequiredCumulative learners who completed the unit.
units[].playsintegerrequiredPlayback sessions in the period.
units[].viewersintegerrequiredDistinct learners who played in the period.
units[].watchedSecondsintegerrequiredunits[].avgCoveredPercentnumber | nullrequiredMedia: mean share watched per learner (cumulative), 0-100; otherwise null.
units[].quickExitRatenumberrequiredShare of period plays that ended within 15 seconds, 0-1.
units[].stallRatenumberrequiredShare of period plays with at least one stall, 0-1.
units[].fastSharenumberrequiredShare of period playback at 1.5x or faster, 0-1.
units[].lastPlayedAtstring | nullrequiredunits[].quizobject | nullrequiredQuiz units only (cumulative).
units[].quiz.passRatenumber | nullrequired0-1; null until someone has attempted.
units[].quiz.avgScorenumber | nullrequiredunits[].quiz.avgAttemptsnumber | nullrequiredunits[].quiz.worstQuestionobject | nullrequiredsymptomsobject[]requiredsymptoms[].unitIdstringrequiredsymptoms[].unitTitlestringrequiredsymptoms[].kind"drop" | "rewatch" | "quick_exit" | "stall" | "fast" | "quiz"requiredsymptoms[].severitynumberrequired0-1, higher is worse; already sorted.
symptoms[].valuenumberrequiredThe figure behind the symptom (rate or count).
symptoms[].questionIdstringsymptoms[].questionPromptstringretentionobject | nullrequiredOnly with unitId.
retention.unitIdstringrequiredretention.titlestringrequiredretention.durationnumber | nullrequiredretention.retentionnumber[] | nullrequired100 buckets across the file: share of learners who watched that part (cumulative, 0-1); null when fewer than 5 learners watched.
retention.rewatchinteger[]required100 buckets: period plays that rewatched that part.
retention.seeksinteger[]required100 buckets: period seeks that landed in that part.
retention.sampleintegerrequiredretention.seekHotspotsinteger[]requiredUp to three bucket indexes most often jumped to.
Errors
FORBIDDEN403DELIVERABLE_NOT_FOUND404UNIT_NOT_FOUND404VALIDATION400
MCP tool deliverable_units_insights
curl -X GET "https://app.kanorio.com/api/v1/sites/{id}/deliverables/{deliverableId}/unit-insights?unitId=unit_video01&days=30" \
-H "Authorization: Bearer $KANORIO_TOKEN"{
"range": {
"from": "2026-09-07",
"to": "2026-10-06",
"timezone": "Asia/Taipei"
},
"units": [
{
"unitId": "unit_video01",
"title": "Welcome",
"kind": "video",
"reached": 47,
"completed": 38,
"plays": 71,
"viewers": 44,
"watchedSeconds": 36900,
"avgCoveredPercent": 86,
"quickExitRate": 0.08,
"stallRate": 0.03,
"fastShare": 0.21,
"lastPlayedAt": "2026-10-06T08:00:00.000Z",
"quiz": null
},
{
"unitId": "unit_text01",
"title": "Reading list",
"kind": "text",
"reached": 31,
"completed": 24,
"plays": 0,
"viewers": 0,
"watchedSeconds": 0,
"avgCoveredPercent": null,
"quickExitRate": 0,
"stallRate": 0,
"fastShare": 0,
"lastPlayedAt": null,
"quiz": null
}
],
"symptoms": [
{
"unitId": "unit_text01",
"unitTitle": "Reading list",
"kind": "drop",
"severity": 0.34,
"value": 0.34
}
],
"retention": {
"unitId": "unit_video01",
"title": "Welcome",
"duration": 612,
"retention": [
1,
0.99,
0.99,
0.98,
0.98,
0.97,
0.96,
0.96,
0.95,
0.94,
0.94,
0.93,
0.93,
0.92,
0.91,
0.91,
0.9,
0.89,
0.89,
0.88,
0.88,
0.87,
0.86,
0.86,
0.85,
0.84,
0.84,
0.83,
0.83,
0.82,
0.81,
0.81,
0.8,
0.79,
0.79,
0.78,
0.78,
0.77,
0.76,
0.76,
0.75,
0.74,
0.74,
0.73,
0.73,
0.72,
0.71,
0.71,
0.7,
0.69,
0.69,
0.68,
0.68,
0.67,
0.66,
0.66,
0.65,
0.64,
0.64,
0.63,
0.63,
0.62,
0.61,
0.61,
0.6,
0.59,
0.59,
0.58,
0.57,
0.57,
0.56,
0.56,
0.55,
0.54,
0.54,
0.53,
0.53,
0.52,
0.51,
0.51,
0.5,
0.49,
0.49,
0.48,
0.48,
0.47,
0.46,
0.46,
0.45,
0.44,
0.44,
0.43,
0.43,
0.42,
0.41,
0.41,
0.4,
0.39,
0.39,
0.38
],
"rewatch": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
6,
6,
6,
6,
6,
6,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
],
"seeks": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
9,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
],
"sample": 44,
"seekHotspots": [
42
]
}
}