API · v1 newlege.co.il ↗
v1.0 · Stable

Newlege API Documentation

Programmatic access to your academy — students, courses, enrollments, and transactions. Built for backends, automations, and AI agents.

Introduction

The Newlege Public API lets you read and write your academy's data from any system you control: backends, scripts, automation tools, or AI agents like Claude and ChatGPT.

Every request is scoped to a single academy through its API key. The API can never return data belonging to another academy — isolation is enforced at the database layer.

Base URL
https://cuabhknytckerifjaple.supabase.co/functions/v1/public-api/v1

Authentication

All requests must include a bearer token in the Authorization header. Generate keys in the dashboard under Settings → Integrations → Public API. The plaintext token is shown once on creation — store it in a secret manager.

Keys look like nl_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.

curl https://cuabhknytckerifjaple.supabase.co/functions/v1/public-api/v1/me \
  -H "Authorization: Bearer nl_live_..."

Scopes

Each key carries a list of scopes. Endpoints reject requests whose key lacks the required scope with HTTP 403.

ScopeGrants
students:readList and read students
students:writeInvite new students (creates user + sends email)
courses:readList/read courses, chapters and lessons
courses:writeCreate courses, chapters and lessons
enrollments:readList enrollments
enrollments:writeEnroll a student in a course
transactions:readList billing transactions

Rate limits

Default limit: 60 requests per minute per key. Every response includes X-RateLimit-Limit and X-RateLimit-Remaining. Exceeding the limit returns HTTP 429 with error code rate_limited.

Errors

Errors use a stable envelope:

{
  "error": {
    "code": "forbidden_scope",
    "message": "Missing required scope: students:read"
  },
  "request_id": "b3a1..."
}
CodeHTTPMeaning
unauthorized401Missing, invalid, expired, or revoked key
forbidden_scope403Key lacks the scope required by the endpoint
not_found404Resource does not exist in this academy
validation_error400Request body or query parameters are invalid
rate_limited429Exceeded the per-minute limit for this key
internal500Unexpected server error — retry with backoff

Pagination

List endpoints accept limit (max 100, default 50) and cursor. The response includes pagination.next_cursor when more results exist. Pass that value back as cursor to fetch the next page.

curl "https://cuabhknytckerifjaple.supabase.co/functions/v1/public-api/v1/students?limit=25&cursor=2025-06-01T10:00:00Z" \
  -H "Authorization: Bearer nl_live_..."

GET /me

Returns the academy associated with the current key, plus the key's scopes. Useful for health checks and key validation.

curl https://cuabhknytckerifjaple.supabase.co/functions/v1/public-api/v1/me \
  -H "Authorization: Bearer nl_live_..."
{
  "data": {
    "academy_id": "f2e486a9-...",
    "academy_name": "Itai Barak Academy",
    "academy_slug": "itai-barak",
    "plan": "premium",
    "scopes": ["students:read", "courses:read"]
  },
  "request_id": "..."
}

Students

List students — GET /students

Requires students:read. Returns members of the academy with the student role.

curl https://cuabhknytckerifjaple.supabase.co/functions/v1/public-api/v1/students \
  -H "Authorization: Bearer nl_live_..."
{
  "data": [
    {
      "id": "8c1d...",
      "email": "student@example.com",
      "full_name": "John Doe",
      "phone": "+972501234567",
      "status": "active",
      "created_at": "2025-06-01T10:00:00Z"
    }
  ],
  "pagination": { "has_more": false, "next_cursor": null },
  "request_id": "..."
}

Get student — GET /students/{id}

curl https://cuabhknytckerifjaple.supabase.co/functions/v1/public-api/v1/students/8c1d... \
  -H "Authorization: Bearer nl_live_..."

Invite student — POST /students

Requires students:write. Creates a new user (if needed), adds them to the academy as a pending member, optionally enrolls them in one or more courses, and sends a branded email with a password-setup or join-confirmation link.

FieldTypeRequiredDescription
emailstringyesStudent's email address
full_namestringyesDisplay name (max 120 chars)
phonestringnoPhone in international format
course_idsuuid[]noCourses to enroll the student into (must belong to your academy)
expires_atISO 8601noOptional access expiry for the enrollments
send_emailbooleannoSend invitation email. Default: true
curl -X POST https://cuabhknytckerifjaple.supabase.co/functions/v1/public-api/v1/students \
  -H "Authorization: Bearer nl_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "email": "new.student@example.com",
    "full_name": "Dana Cohen",
    "phone": "+972501234567",
    "course_ids": ["COURSE_UUID_1"],
    "send_email": true
  }'
{
  "data": {
    "id": "8c1d...",
    "email": "new.student@example.com",
    "full_name": "Dana Cohen",
    "phone": "+972501234567",
    "status": "pending",
    "is_new_user": true,
    "enrolled_course_ids": ["COURSE_UUID_1"],
    "invitation_link": "https://your-academy.newlege.co.il/student/auth?type=set-password&token_hash=..."
  },
  "request_id": "..."
}

Returns plan_limit_reached (HTTP 403) when the academy has reached its student quota for its current plan.

Courses

List courses — GET /courses

curl https://cuabhknytckerifjaple.supabase.co/functions/v1/public-api/v1/courses \
  -H "Authorization: Bearer nl_live_..."

Get course — GET /courses/{id}

curl https://cuabhknytckerifjaple.supabase.co/functions/v1/public-api/v1/courses/COURSE_ID \
  -H "Authorization: Bearer nl_live_..."

Create course — POST /courses

Requires courses:write. New courses are created as drafts by default (hidden from students).

FieldTypeRequiredDescription
titlestringyesCourse title
descriptionstringnoMarketing description
slugstringnoURL slug (auto-generated if omitted)
pricenumbernoDefault 0
payment_typestringno'one_time' (default) or 'subscription'
is_publishedbooleannoDefault false — keep drafts hidden from students
curl -X POST https://cuabhknytckerifjaple.supabase.co/functions/v1/public-api/v1/courses \
  -H "Authorization: Bearer nl_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Mastering Public Speaking",
    "description": "From stage fright to standing ovation in 8 weeks.",
    "price": 499,
    "payment_type": "one_time"
  }'

Chapters

Chapters group lessons inside a course. Position is auto-assigned to the next available index if omitted.

List chapters — GET /courses/{course_id}/chapters

curl https://cuabhknytckerifjaple.supabase.co/functions/v1/public-api/v1/courses/COURSE_ID/chapters \
  -H "Authorization: Bearer nl_live_..."

Create chapter — POST /courses/{course_id}/chapters

Requires courses:write.

curl -X POST https://cuabhknytckerifjaple.supabase.co/functions/v1/public-api/v1/courses/COURSE_ID/chapters \
  -H "Authorization: Bearer nl_live_..." \
  -H "Content-Type: application/json" \
  -d '{ "title": "Week 1 — Foundations" }'
{
  "data": {
    "id": "ch_uuid",
    "course_id": "COURSE_ID",
    "title": "Week 1 — Foundations",
    "position": 0,
    "created_at": "2026-06-15T10:00:00Z"
  },
  "request_id": "..."
}

Lessons

Lessons live inside a chapter. Each lesson has a content_type describing how to render it.

List lessons — GET /chapters/{chapter_id}/lessons

curl https://cuabhknytckerifjaple.supabase.co/functions/v1/public-api/v1/chapters/CHAPTER_ID/lessons \
  -H "Authorization: Bearer nl_live_..."

Create lesson — POST /chapters/{chapter_id}/lessons

FieldTypeRequiredDescription
titlestringyesLesson title
content_typeenumyesvideo | text | file | audio | embed | live
content_urlstringnoURL of the video / file / embed
content_textstringnoHTML/markdown body for text lessons
descriptionstringnoShort description shown in the player
positionnumbernoOrder within the chapter (auto-appended if omitted)
duration_secondsnumbernoLesson length in seconds
is_free_giftbooleannoFree preview / gift lesson
curl -X POST https://cuabhknytckerifjaple.supabase.co/functions/v1/public-api/v1/chapters/CHAPTER_ID/lessons \
  -H "Authorization: Bearer nl_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Intro video",
    "content_type": "video",
    "content_url": "https://vimeo.com/123456789",
    "duration_seconds": 540
  }'

Enrollments

List — GET /enrollments

Optional filters: course_id, student_id.

curl "https://cuabhknytckerifjaple.supabase.co/functions/v1/public-api/v1/enrollments?course_id=COURSE_ID" \
  -H "Authorization: Bearer nl_live_..."

Create — POST /enrollments

Grants a student access to a course. Both must already exist in this academy.

curl -X POST https://cuabhknytckerifjaple.supabase.co/functions/v1/public-api/v1/enrollments \
  -H "Authorization: Bearer nl_live_..." \
  -H "Content-Type: application/json" \
  -d '{ "student_id": "STUDENT_UUID", "course_id": "COURSE_UUID" }'

Transactions

List — GET /transactions

curl https://cuabhknytckerifjaple.supabase.co/functions/v1/public-api/v1/transactions \
  -H "Authorization: Bearer nl_live_..."

Use with Claude / GPT

Both Claude Projects and OpenAI's custom GPTs support adding HTTP tools. Configure a tool that calls the endpoints above using your API key in the Authorization header. Once added, you can ask the model things like "list my newest 10 students" or "enroll user X in course Y" in natural language.

A native MCP server is coming in Phase 2 — it will expose every endpoint as a typed MCP tool so Claude Desktop and Cursor can use it without manual configuration.

Use with Zapier / Make / n8n

Use the generic HTTP / Webhook action. Set the URL to one of the endpoints above, add the Authorization: Bearer nl_live_... header, and for POSTs send JSON. Example trigger: "When a row is added in Google Sheets → POST /enrollments".

Changelog

v1.1 — Write endpoints: POST /students (invite), POST /courses, POST /courses/{id}/chapters, POST /chapters/{id}/lessons. New scope courses:write.

v1.0 — Initial release. Endpoints: /me, /students, /courses, /enrollments, /transactions.