Discovery API¶
Public API for browsing learning content. Returns aggregated data optimized for UI consumption.
Base URL: {base-url}/discovery
Authentication: Not required
Overview¶
The Discovery API provides read-only access to learning content with pre-aggregated counts and nested data. It's designed for:
- Landing pages and content catalogs
- Filter bars and faceted navigation
- Mixed-content feeds (domains, trails, concepts together)
Endpoints¶
| Endpoint | Purpose |
|---|---|
GET /domains |
List domains with nested trails |
GET /trails |
List trails with nested concepts |
GET /concepts |
List concepts with nested sparks |
GET /sparks |
List sparks |
GET /all |
Unified feed with mixed content types |
GET /facets |
Filter options with counts |
GET /health |
Health check |
GET /domains¶
Returns domains with their trails and aggregated statistics.
When to Use¶
- Homepage "Explore by Domain" section
- Domain catalog page
- Top-level navigation
Parameters¶
| Parameter | Type | Default | Description |
|---|---|---|---|
page |
integer | 1 | Page number |
per_page |
integer | 20 | Items per page |
trail_limit |
integer | 5 | Max trails per domain |
Response¶
{
"data": [
{
"id": "uuid",
"slug": "machine-learning",
"name": "Machine Learning",
"description": "Fundamentals of ML...",
"icon": "brain",
"color": "#4F46E5",
"trail_count": 12,
"concept_count": 45,
"spark_count": 180,
"estimated_mins": 2400,
"trails": [
{
"id": "uuid",
"slug": "neural-networks",
"title": "Neural Networks",
"estimated_mins": 180
}
]
}
],
"meta": { ... }
}
Key Fields¶
| Field | Description |
|---|---|
trail_count |
Total trails in this domain |
concept_count |
Total concepts across all trails |
spark_count |
Total sparks across all concepts |
estimated_mins |
Total learning time in minutes |
trails |
Preview of trails (limited by trail_limit) |
GET /trails¶
Returns trails with their concepts and statistics.
When to Use¶
- Domain detail page showing trails
- "Learning Paths" catalog
- Trail cards in listings
Parameters¶
| Parameter | Type | Default | Description |
|---|---|---|---|
page |
integer | 1 | Page number |
per_page |
integer | 20 | Items per page |
domain |
string | - | Filter by domain slug |
difficulty |
enum | - | Filter: beginner, intermediate, advanced, expert |
concept_limit |
integer | 5 | Max concepts per trail |
Response¶
{
"data": [
{
"id": "uuid",
"slug": "neural-networks",
"title": "Neural Networks Fundamentals",
"description": "Learn the building blocks...",
"difficulty_level": "intermediate",
"concept_count": 8,
"spark_count": 32,
"estimated_mins": 180,
"concepts": [
{
"id": "uuid",
"slug": "backpropagation",
"title": "Backpropagation",
"estimated_mins": 25
}
]
}
],
"meta": { ... }
}
Key Fields¶
| Field | Description |
|---|---|
difficulty_level |
Trail difficulty rating |
concept_count |
Number of concepts in trail |
spark_count |
Total sparks in trail |
concepts |
Preview of concepts (limited by concept_limit) |
GET /concepts¶
Returns concepts with their sparks and statistics.
When to Use¶
- Trail detail page showing concepts
- Concept catalog
- "What you'll learn" sections
Parameters¶
| Parameter | Type | Default | Description |
|---|---|---|---|
page |
integer | 1 | Page number |
per_page |
integer | 20 | Items per page |
trail |
string | - | Filter by trail slug |
spark_limit |
integer | 3 | Max sparks per concept |
Response¶
{
"data": [
{
"id": "uuid",
"slug": "backpropagation",
"title": "Backpropagation",
"description": "Understanding gradient flow...",
"order_index": 3,
"spark_count": 4,
"estimated_mins": 25,
"sparks": [
{
"id": "uuid",
"slug": "chain-rule-basics",
"title": "Chain Rule Basics",
"summary": "How derivatives flow...",
"difficulty": "intermediate",
"estimated_mins": 7
}
]
}
],
"meta": { ... }
}
Key Fields¶
| Field | Description |
|---|---|
order_index |
Position within trail |
spark_count |
Number of sparks in concept |
sparks |
Preview of sparks (limited by spark_limit) |
GET /sparks¶
Returns sparks (atomic learning units).
When to Use¶
- "Quick Start" sections
- Spark catalogs
- Search result displays
Parameters¶
| Parameter | Type | Default | Description |
|---|---|---|---|
page |
integer | 1 | Page number |
per_page |
integer | 20 | Items per page |
concept |
string | - | Filter by concept slug |
difficulty |
enum | - | Filter: beginner, intermediate, advanced, expert |
Response¶
{
"data": [
{
"id": "uuid",
"slug": "chain-rule-basics",
"title": "Chain Rule Basics",
"summary": "How derivatives flow through computation graphs",
"difficulty": "intermediate",
"estimated_mins": 7
}
],
"meta": { ... }
}
GET /all¶
Unified discovery endpoint returning mixed content types (domains, trails, concepts) with type discrimination.
When to Use¶
- "Deep Dive" sections showing trails and concepts together
- Mixed-content feeds
- Unified search results display
- Filter bar implementations
Parameters¶
| Parameter | Type | Default | Description |
|---|---|---|---|
page |
integer | 1 | Page number |
per_page |
integer | 20 | Items per page |
types |
string | all | Comma-separated: domain,trail,concept |
domain |
string | - | Filter by domain slug |
track |
string | - | Filter by trail slug (alias: "track") |
difficulty |
enum | - | Filter: beginner, intermediate, advanced, expert |
q |
string | - | Text search query |
include_facets |
boolean | false | Include filter counts |
nested_limit |
integer | 3 | Nested items per entity (0-10) |
Response¶
{
"data": [
{
"type": "DOMAIN",
"id": "uuid",
"slug": "machine-learning",
"name": "Machine Learning",
"description": "...",
"trail_count": 12,
"concept_count": 45,
"spark_count": 180,
"estimated_mins": 2400
},
{
"type": "TRAIL",
"id": "uuid",
"slug": "neural-networks",
"title": "Neural Networks",
"description": "...",
"difficulty_level": "intermediate",
"concept_count": 8,
"spark_count": 32,
"estimated_mins": 180,
"concepts": [...]
},
{
"type": "CONCEPT",
"id": "uuid",
"slug": "backpropagation",
"title": "Backpropagation",
"description": "...",
"spark_count": 4,
"estimated_mins": 25,
"sparks": [...]
}
],
"meta": { ... },
"facets": { ... }
}
Type Discrimination¶
Each item includes a type field to identify its entity type:
| Type | Entity | Name Field |
|---|---|---|
DOMAIN |
Domain | name |
TRAIL |
Trail | title |
CONCEPT |
Concept | title |
Proportional Distribution¶
Results are distributed proportionally across types: - Domains: ~10% of page - Trails: ~25% of page - Concepts: ~65% of page
This ensures balanced representation when browsing mixed content.
Filtering Behavior¶
| Filter | Effect |
|---|---|
domain=ml |
Shows only content within that domain |
track=neural-nets |
Shows only concepts within that trail |
difficulty=beginner |
Filters trails only (domains/concepts excluded) |
types=trail,concept |
Excludes domains from results |
GET /facets¶
Returns available filter options with item counts.
When to Use¶
- Filter bar dropdowns
- Sidebar filter panels
- "Refine results" UI
Parameters¶
| Parameter | Type | Default | Description |
|---|---|---|---|
domain |
string | - | Scope facets to domain |
track |
string | - | Scope facets to trail |
difficulty |
enum | - | Scope facets to difficulty |
Response¶
{
"domains": [
{ "slug": "machine-learning", "name": "Machine Learning", "count": 45 },
{ "slug": "data-science", "name": "Data Science", "count": 32 }
],
"tracks": [
{ "slug": "neural-networks", "name": "Neural Networks", "count": 28 },
{ "slug": "deep-learning", "name": "Deep Learning", "count": 35 }
],
"difficulties": [
{ "level": "beginner", "count": 15 },
{ "level": "intermediate", "count": 42 },
{ "level": "advanced", "count": 23 },
{ "level": "expert", "count": 8 }
],
"types": [
{ "type": "DOMAIN", "count": 5 },
{ "type": "TRAIL", "count": 18 },
{ "type": "CONCEPT", "count": 65 }
]
}
Facet Fields¶
| Facet | Description |
|---|---|
domains |
Available domains with content count |
tracks |
Available trails (tracks) with content count |
difficulties |
Difficulty levels with trail count |
types |
Entity types with total count |
GET /health¶
Health check endpoint.
Response¶
Common Patterns¶
Building a Filter Bar¶
- Call
GET /facetsto populate dropdowns - User selects filters
- Call
GET /allwith selected filters - Use
include_facets=trueto update counts dynamically
Deep Dive Section (Trails + Concepts)¶
Domain Landing Page¶
Paginating Mixed Results¶
The /all endpoint maintains proportional distribution across pages. Page 2 continues from where each type left off:
- Page 1: 2 domains, 5 trails, 13 concepts
- Page 2: 2 domains, 5 trails, 13 concepts (next batch)
- When a type is exhausted, its slots are redistributed
Notes¶
- All endpoints are public (no authentication required)
- Results are sorted alphabetically within each type
- Use
nested_limit=0to exclude nested items for lighter responses - Counts in facets reflect the total matching items, not just the current page