| Availability |
Odoo Online
Odoo.sh
On Premise
|
| Odoo Apps Dependencies |
•
eLearning (website_slides)
• Website (website) • Discuss (mail) |
| Lines of code | 213 |
| Technical Name |
website_slides_headless |
| License | LGPL-3 |
| Website | https://www.deepskill.space |
| Availability |
Odoo Online
Odoo.sh
On Premise
|
| Odoo Apps Dependencies |
•
eLearning (website_slides)
• Website (website) • Discuss (mail) |
| Lines of code | 213 |
| Technical Name |
website_slides_headless |
| License | LGPL-3 |
| Website | https://www.deepskill.space |
Website Slides Headless API
Power your Next.js, Nuxt, or mobile frontend with Odoo eLearning data via REST
Odoo's eLearning module ships HTML routes built for Odoo's own templates. Headless frontends need JSON. This module adds a clean, versioned REST API on top of website_slides — public catalog endpoints for anonymous visitors, authenticated endpoints for enrolled learners.
Why not call call_kw directly?
Odoo's generic ORM RPC respects record rules. A Portal user calling
slide.slide.search_read for a channel they are not enrolled in
only sees preview slides — the rest of the index is hidden by
rule_slide_slide_public_user. This module replicates what
Odoo's own UI does internally: fetches with sudo() after
validating that the channel is website-published, then returns the full
public index.
Key Features
Public catalog
Anonymous visitors see the full course index — no login required, no service user credentials to leak.
Authenticated content
Enrolled users fetch slide content and quiz payloads over HTTPS with their own Odoo session cookie.
Versioned routes
All endpoints live under /slides/api/v1/ so you can evolve
the contract without breaking clients.
API Contract
Four endpoints, all returning JSON. Errors return
{"error": {"code": "<slug>", "message": "<text>"}}
with an appropriate HTTP status (401, 403, 404).
1. Channel index (public)
GET /slides/api/v1/channels/<id>/slides
Honors visibility: public and link are
visible to all, connected hides from anonymous, members
hides from non-enrolled. Returns the slide index in display order.
Example response:
{
"channel_id": 41,
"slides": [
{
"id": 947,
"name": "Fundamentos",
"slide_type": "pdf",
"slide_category": "document",
"is_category": true,
"is_preview": true,
"completion_time": 0.3,
"sequence": 0
},
{
"id": 948,
"name": "Introducción al Backtracking y el Ejemplo del Laberinto",
"slide_type": "vimeo_video",
"slide_category": "video",
"is_category": false,
"is_preview": false,
"completion_time": 0.1167,
"sequence": 1
},
{
"id": 1140,
"name": "Evaluación Fundamentos del Backtracking",
"slide_type": "quiz",
"slide_category": "quiz",
"is_category": false,
"is_preview": false,
"completion_time": 0.0,
"sequence": 3
}
]
}
2. Slide content (member-only)
GET /slides/api/v1/slides/<id>/content
Returns full payload including html_content,
embed_code, url, resources and
a download_url when the slide has a binary attached.
Requires the caller to be enrolled in the channel.
Example response:
{
"id": 948,
"name": "Introducción al Backtracking y el Ejemplo del Laberinto",
"slide_type": "vimeo_video",
"slide_category": "video",
"is_preview": false,
"url": "https://vimeo.com/123456789",
"embed_code": "<iframe src=\"https://player.vimeo.com/video/123456789\" ...></iframe>",
"html_content": false,
"download_url": false,
"completion_time": 0.1167,
"channel_id": 41,
"has_questions": false,
"resources": [
{
"id": 22,
"name": "Slides PDF",
"resource_type": "file",
"file_name": "backtracking-intro.pdf",
"link": false,
"sequence": 1
}
]
}
3. Quiz payload (member-only)
GET /slides/api/v1/slides/<id>/quiz
Returns questions with all answers (including is_correct).
Designed for client-side scoring; pair with Odoo's own quiz submission
endpoint to record progress.
Example response:
{
"slide_id": 1140,
"questions": [
{
"id": 412,
"question": "¿Cuál es la complejidad temporal del peor caso del backtracking puro?",
"sequence": 1,
"answers": [
{"id": 1601, "text": "O(n)", "is_correct": false},
{"id": 1602, "text": "O(n log n)", "is_correct": false},
{"id": 1603, "text": "O(2^n)", "is_correct": true},
{"id": 1604, "text": "O(n!)", "is_correct": false}
]
}
]
}
4. Slide download (member-only)
GET /slides/api/v1/slides/<id>/download
Streams the slide's binary inline so a native iframe (or Next.js
<object>) can render it without going through Odoo's
embed viewer. Member-only.
Example response (headers):
HTTP/1.1 200 OK
Content-Type: application/pdf
Content-Length: 184523
Content-Disposition: inline; filename="Fundamentos.pdf"
Cache-Control: private, max-age=300
<binary stream>
Authentication
The catalog endpoint is public — no header, no cookie,
no token. The other three endpoints rely on Odoo's standard
session cookie: log in via
/web/session/authenticate (JSON-RPC) and forward the
session_id cookie on subsequent requests.
There is no API key system — intentionally; the module reuses
Odoo's own auth so users, ACLs, channel membership and audit trail all
stay consistent with the back-office.
Technical Details
- Transport:
type='http'+make_json_response()— real REST with HTTP verbs, no JSON-RPC envelope. - Permissions: public endpoints use
sudo()internally after validatingwebsite_published. Authenticated endpoints honor channel membership. - Dependencies:
website_slides(Community). - License: LGPL-3.
Made with care by Deep Skill.
Please log in to comment on this module