Skip to main content
Course endpoints sit under /api/brands/{brand}/courses/ with brandAccess middleware. Authenticate with EF-Access-Key.

List Courses

GET /api/brands/{brand}/courses
per_page
number
Results per page (1–100, default: 25)
q
string
Search by title, description, slug, or instructor name
sort
string
newest, oldest, created_at, updated_at
cURL
curl https://app.elasticfunnels.io/api/brands/{brand_id}/courses \
  -H "EF-Access-Key: your_api_key_here"
{
  "current_page": 1,
  "data": [
    {
      "id": 1,
      "title": "Gut Health Masterclass",
      "slug": "gut-health",
      "status": "published",
      "delivery_type": "module",
      "language_code": "en",
      "instructor_name": "Dr. Jane Smith",
      "domain_id": 7,
      "modules_count": 6,
      "enrollments_count": 124
    }
  ],
  "per_page": 25,
  "total": 3,
  "last_page": 1
}

List Courses (Unpaginated)

GET /api/brands/{brand}/courses/all
Returns { id, title } for all courses — useful for dropdowns.

Get Course

GET /api/brands/{brand}/courses/{course}
{
  "id": 1,
  "title": "Gut Health Masterclass",
  "slug": "gut-health",
  "status": "published",
  "delivery_type": "module",
  "language_code": "en",
  "description": "Learn how to improve your gut health...",
  "instructor_name": "Dr. Jane Smith",
  "instructor_photo": "https://cdn.elasticfunnels.io/42/assets/media/instructor.jpg",
  "logo": null,
  "cover": "https://cdn.elasticfunnels.io/42/assets/media/cover.jpg",
  "domain_id": 7,
  "domain": { "id": 7, "domain": "courses.mybrand.com" },
  "show_module_titles": true,
  "allow_comments": false,
  "details_page_id": null,
  "module_page_id": 101,
  "content_page_id": 102,
  "enrollment_email_template_id": null,
  "enrollments_count": 124
}

Create Course

POST /api/brands/{brand}/courses
title
string
required
Course title (max 255)
language_code
string
required
Language code (e.g. en, pt)
description
string
required
Course description
status
string
required
draft or published
delivery_type
string
required
embedded (content lives inline on a page) or module (dedicated course pages on a domain)
domain_id
number
Required when delivery_type is module. Must be an existing brand domain.
slug
string
Required when delivery_type is module. Must be unique per brand_id + domain_id.
instructor_name
string
Instructor display name (max 255)
instructor_photo
file | string
Instructor photo — upload as file (multipart) or provide as URL string
Course logo — upload as file or URL string
cover
file | string
Cover image — upload as file or URL string
show_module_titles
boolean
Show module titles in the course outline
allow_comments
boolean
Enable commenting on content
category_name
string
Course category name (max 255)
details_page_id
number
Page ID for the course details/landing page
module_page_id
number
Page ID for module listing
content_page_id
number
Page ID for content viewing
enrollment_email_template_id
number
Email template ID to send upon enrollment
cURL
curl -X POST https://app.elasticfunnels.io/api/brands/{brand_id}/courses \
  -H "EF-Access-Key: your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Gut Health Masterclass",
    "language_code": "en",
    "description": "Learn how to improve your gut health naturally.",
    "status": "draft",
    "delivery_type": "module",
    "domain_id": 7,
    "slug": "gut-health",
    "instructor_name": "Dr. Jane Smith"
  }'
{
  "course": {
    "id": 1,
    "title": "Gut Health Masterclass",
    "slug": "gut-health",
    "status": "draft",
    "brand_id": 42,
    "created_at": "2024-12-11T10:00:00.000000Z"
  }
}

Update Course

PUT /api/brands/{brand}/courses/{course}
Same body as Create. title, language_code, description, status, and delivery_type are required.

Delete Course

DELETE /api/brands/{brand}/courses/{course}
{ "success": true }

Copy Course to Another Brand

POST /api/brands/{brand}/courses/copy
id
number
required
Source course ID
brand_id
number
required
Target brand ID
name
string
required
Title for the copied course in the target brand
{
  "course_id": 5
}

Enrollments

List Enrollments

GET /api/brands/{brand}/courses/{course}/enrollments
{
  "data": [
    {
      "id": "es-enroll-abc123",
      "email": "student@example.com",
      "name": "Jane Student",
      "user_id": 99,
      "notes": null,
      "created_at": "2024-12-01T00:00:00Z",
      "completed_content_ids": [10, 11],
      "progress_percent": 33,
      "last_content_id": 11,
      "last_module_id": 2
    }
  ]
}

Get Enrollment

GET /api/brands/{brand}/courses/{course}/enrollments/{enrollment}
enrollment
string
required
Elasticsearch document ID for the enrollment
{
  "data": { /* same enrollment object */ }
}

Enroll Student

POST /api/brands/{brand}/courses/{course}/enrollments
email
string
required
Student email address. Returns 422 if already enrolled.
name
string
Student display name (max 255)
cURL
curl -X POST https://app.elasticfunnels.io/api/brands/{brand_id}/courses/1/enrollments \
  -H "EF-Access-Key: your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"email": "student@example.com", "name": "Jane Student"}'
{
  "data": {
    "id": "es-enroll-abc123",
    "email": "student@example.com",
    "name": "Jane Student",
    "created_at": "2024-12-11T10:00:00Z"
  }
}

Update Enrollment Notes

PUT /api/brands/{brand}/courses/{course}/enrollments/{enrollment}
notes
string
Internal notes about the enrollment (max 10,000 chars)

Complete Content Item

Mark a specific content item as completed for an enrolled student.
POST /api/brands/{brand}/courses/{course}/enrollments/{enrollment}/complete
content_id
number
required
The course content item ID to mark as complete
{
  "data": {
    "completed_content_ids": [10, 11, 12],
    "progress_percent": 50,
    "last_content_id": 12
  }
}
This endpoint is idempotent — marking an already-completed item again does not create duplicates.

Remove Enrollment

DELETE /api/brands/{brand}/courses/{course}/enrollments/{enrollment}
{ "success": true }

Modules

List Modules

GET /api/brands/{brand}/courses/{course}/modules
{
  "data": [
    {
      "id": 3,
      "title": "Module 1: Introduction",
      "description": "Overview of gut health fundamentals.",
      "order": 1,
      "contents": [
        { "id": 10, "title": "What is Gut Flora?", "type": "video", "order": 1 },
        { "id": 11, "title": "The Gut-Brain Axis", "type": "text", "order": 2 }
      ]
    }
  ]
}

List Modules (Unpaginated)

GET /api/brands/{brand}/courses/{course}/modules/all
Returns { id, title } array — cached.

Create Module

POST /api/brands/{brand}/courses/{course}/modules
title
string
required
Module title (max 255)
description
string
required
Module description

Update Module

PUT /api/brands/{brand}/courses/{course}/modules/{module}

Delete Module

DELETE /api/brands/{brand}/courses/{course}/modules/{module}

Reorder Modules

POST /api/brands/{brand}/courses/{course}/modules/order
order
object
required
Map of { "<module_id>": <integer order>, ... }

Notes

  • Enrollment IDs are Elasticsearch document IDs (strings), not numeric database IDs
  • File uploads (logo, cover, instructor_photo) are stored on BunnyCDN — you can provide a URL string instead of uploading a file
  • The copy endpoint replicates the course’s modules and all content to the target brand
  • progress_percent is recalculated automatically when content is marked complete