REST API reference

Skool API

15 endpoints for Skool. Each one is a POST with a JSON body, called with your API key.

Base URL
https://cotlet.dev/api/v1/skool
Connects with
Your own Skool account (admin or moderator for approvals and stats)
Integration page
Skool
Skool Endpoints
Endpoint Access Description
list_groups read Skool groups you belong to, with your role and member count.
list_members read Members of a group with name, role, level and join date, newest first.
list_membership_requests read Pending requests to join, with each applicant's Membership Questions answers. Admins and moderators only.
list_posts read Posts in the community feed, newest first, with author, category, likes and comment count.
get_post read Full post with title, body, attachments and the comment tree.
list_courses read Courses in the Classroom with their modules, unlock rule (open, level or paid) and URL.
list_conversations read Your Skool Chat inbox: who, unread count and last message preview.
get_conversation read Messages in one Skool Chat conversation, oldest first.
get_group_stats read Total, new and churned members and monthly recurring revenue for a period. Admins only.
approve_membership_request write Let an applicant into the group. Your AutoDM, if set, goes out as usual.
decline_membership_request write Decline an applicant's request to join.
create_post write Publish a post to the community feed in a category, as you.
comment_on_post write Comment on a post, or reply to a comment, as you.
send_message write Send a direct message in Skool Chat to a member, starting a conversation if needed.
pin_post write Pin a post to the top of the feed (up to 3) or to a Classroom page (up to 12). Admins only.

POST https://cotlet.dev/api/v1/skool/list_groups

Returns every Skool group your account belongs to, both groups you own and groups you joined. Use the group field from each item as the group parameter of the other endpoints. Member count is the number Skool shows on the group page.

Parameters

No parameters.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/skool/list_groups \
  -H "Authorization: Bearer $COTLET_API_KEY"
Python
result = client.call("skool", "list_groups")
Node.js
const result = await cotlet.call('skool', 'list_groups');
CLI
cotlet call skool list_groups

Example response

{
  "groups": [
    {
      "group": "yourgroup",
      "name": "Landing Page Lab",
      "role": "admin",
      "members": 1284,
      "price": "$49/month",
      "url": "https://www.skool.com/yourgroup"
    },
    {
      "group": "creator-club",
      "name": "Creator Club",
      "role": "member",
      "members": 9310,
      "price": "free",
      "url": "https://www.skool.com/creator-club"
    }
  ]
}

POST https://cotlet.dev/api/v1/skool/list_members

Lists members of one group, newest first. Filter by role or by join date to find this week's new members. Level is the Skool gamification level (1 to 9) and points are the likes that count toward it. Pages hold up to 100 members; pass next_cursor back as cursor for the next page.

Parameters

Parameters: list_members
NameTypeDescription
group required string Group URL name, e.g. 'yourgroup' for skool.com/yourgroup.
joined_since date Only members who joined on or after this date.
role enum all, admin, moderator or member. Default: all.
limit integer 1 to 100. Default: 50.
cursor string Next page cursor from the previous call.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/skool/list_members \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"group":"yourgroup"}'
Python
result = client.call("skool", "list_members", {"group":"yourgroup"})
Node.js
const result = await cotlet.call('skool', 'list_members', {"group":"yourgroup"});
CLI
cotlet call skool list_members --data '{"group":"yourgroup"}'

Example response

{
  "members": [
    {
      "member_id": "m_8c41d2",
      "name": "Ana Lopez",
      "role": "member",
      "level": 2,
      "points": 14,
      "joined_at": "2026-10-01T18:21:00Z",
      "profile_url": "https://www.skool.com/@ana-lopez"
    }
  ],
  "next_cursor": "eyJvZmZzZXQiOjUwfQ"
}

POST https://cotlet.dev/api/v1/skool/list_membership_requests

Lists pending requests to join a private group, oldest first, with the answers each applicant gave to your Membership Questions. Only admins and moderators see requests; for other roles the call fails with a permission error. Pass request_id to approve_membership_request or decline_membership_request.

Parameters

Parameters: list_membership_requests
NameTypeDescription
group required string Group URL name, e.g. 'yourgroup' for skool.com/yourgroup.
limit integer 1 to 100. Default: 50.
cursor string Next page cursor from the previous call.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/skool/list_membership_requests \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"group":"yourgroup"}'
Python
result = client.call("skool", "list_membership_requests", {"group":"yourgroup"})
Node.js
const result = await cotlet.call('skool', 'list_membership_requests', {"group":"yourgroup"});
CLI
cotlet call skool list_membership_requests --data '{"group":"yourgroup"}'

Example response

{
  "requests": [
    {
      "request_id": "r_51e0aa",
      "name": "Tom Becker",
      "requested_at": "2026-10-03T07:45:00Z",
      "answers": [
        {
          "question": "What are you building?",
          "answer": "A SaaS for dental clinics, launching in November."
        }
      ]
    }
  ],
  "next_cursor": null
}

List posts

read

POST https://cotlet.dev/api/v1/skool/list_posts

Lists posts in the community feed, newest first, the same order as the feed with the Newest sort. Filter by category or by creation time to see what came in since your last check. Body is a short preview; get_post returns the full text and comments.

Parameters

Parameters: list_posts
NameTypeDescription
group required string Group URL name, e.g. 'yourgroup' for skool.com/yourgroup.
category string Only posts in this category.
since datetime Only posts created after this time.
limit integer 1 to 50. Default: 20.
cursor string Next page cursor from the previous call.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/skool/list_posts \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"group":"yourgroup"}'
Python
result = client.call("skool", "list_posts", {"group":"yourgroup"})
Node.js
const result = await cotlet.call('skool', 'list_posts', {"group":"yourgroup"});
CLI
cotlet call skool list_posts --data '{"group":"yourgroup"}'

Example response

{
  "posts": [
    {
      "post_id": "a3f9c2e1b7d84c06",
      "title": "Week 12 challenge: ship one landing page",
      "author": "You",
      "category": "Announcements",
      "likes": 23,
      "comments": 7,
      "pinned": true,
      "created_at": "2026-10-03T07:00:00Z",
      "preview": "Post your link below by Sunday..."
    }
  ],
  "next_cursor": "eyJvZmZzZXQiOjIwfQ"
}

Get post

read

POST https://cotlet.dev/api/v1/skool/get_post

Returns one post with its full body, attachments (images, files, links) and the whole comment tree, replies nested under their parent comment. Use it before replying so your agent sees the full discussion.

Parameters

Parameters: get_post
NameTypeDescription
group required string Group URL name, e.g. 'yourgroup' for skool.com/yourgroup.
post_id required string Post ID from list_posts.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/skool/get_post \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"group":"yourgroup","post_id":"post_8c41d2"}'
Python
result = client.call("skool", "get_post", {"group":"yourgroup","post_id":"post_8c41d2"})
Node.js
const result = await cotlet.call('skool', 'get_post', {"group":"yourgroup","post_id":"post_8c41d2"});
CLI
cotlet call skool get_post --data '{"group":"yourgroup","post_id":"post_8c41d2"}'

Example response

{
  "post_id": "a3f9c2e1b7d84c06",
  "title": "Week 12 challenge: ship one landing page",
  "body": "Post your link below by Sunday. Best three get a live review on Thursday's call.",
  "author": {
    "member_id": "m_0001",
    "name": "You"
  },
  "attachments": [],
  "comments": [
    {
      "comment_id": "c_77ab",
      "author": "Ana Lopez",
      "body": "Here's mine: ana.dev/launch",
      "likes": 3,
      "replies": [
        {
          "comment_id": "c_77b0",
          "author": "You",
          "body": "Love the headline!"
        }
      ]
    }
  ]
}

POST https://cotlet.dev/api/v1/skool/list_courses

Lists courses in the group's Classroom with their modules in order. Unlock rule says who can open each course: open to all members, unlocked at a level, or paid. Use the module URLs in welcome messages.

Parameters

Parameters: list_courses
NameTypeDescription
group required string Group URL name, e.g. 'yourgroup' for skool.com/yourgroup.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/skool/list_courses \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"group":"yourgroup"}'
Python
result = client.call("skool", "list_courses", {"group":"yourgroup"})
Node.js
const result = await cotlet.call('skool', 'list_courses', {"group":"yourgroup"});
CLI
cotlet call skool list_courses --data '{"group":"yourgroup"}'

Example response

{
  "courses": [
    {
      "course_id": "co_12",
      "title": "Start Here",
      "unlock": "open",
      "modules": [
        {
          "title": "Welcome",
          "url": "https://www.skool.com/yourgroup/classroom/co_12?md=1"
        },
        {
          "title": "Your first week",
          "url": "https://www.skool.com/yourgroup/classroom/co_12?md=2"
        }
      ]
    },
    {
      "course_id": "co_19",
      "title": "Advanced Funnels",
      "unlock": "level 3",
      "modules": []
    }
  ]
}

POST https://cotlet.dev/api/v1/skool/list_conversations

Lists your Skool Chat conversations, most recent first, with the other person, unread count and a preview of the last message. Set unread_only to see only what needs an answer.

Parameters

Parameters: list_conversations
NameTypeDescription
unread_only boolean Only conversations with unread messages.
limit integer 1 to 50. Default: 20.
cursor string Next page cursor from the previous call.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/skool/list_conversations \
  -H "Authorization: Bearer $COTLET_API_KEY"
Python
result = client.call("skool", "list_conversations")
Node.js
const result = await cotlet.call('skool', 'list_conversations');
CLI
cotlet call skool list_conversations

Example response

{
  "conversations": [
    {
      "conversation_id": "cv_93f1",
      "with": {
        "member_id": "m_8c41d2",
        "name": "Ana Lopez"
      },
      "unread": 2,
      "last_message": "Is the Thursday call recorded?",
      "updated_at": "2026-10-02T16:02:00Z"
    }
  ],
  "next_cursor": null
}

POST https://cotlet.dev/api/v1/skool/get_conversation

Returns the messages of one Skool Chat conversation, oldest first, so your agent reads the thread in order before answering.

Parameters

Parameters: get_conversation
NameTypeDescription
conversation_id required string Conversation ID from list_conversations.
limit integer 1 to 100. Default: 50.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/skool/get_conversation \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"conversation_id":"conversation_8c41d2"}'
Python
result = client.call("skool", "get_conversation", {"conversation_id":"conversation_8c41d2"})
Node.js
const result = await cotlet.call('skool', 'get_conversation', {"conversation_id":"conversation_8c41d2"});
CLI
cotlet call skool get_conversation --data '{"conversation_id":"conversation_8c41d2"}'

Example response

{
  "conversation_id": "cv_93f1",
  "with": {
    "member_id": "m_8c41d2",
    "name": "Ana Lopez"
  },
  "messages": [
    {
      "from": "Ana Lopez",
      "body": "Hi! Quick question.",
      "sent_at": "2026-10-02T16:01:00Z"
    },
    {
      "from": "Ana Lopez",
      "body": "Is the Thursday call recorded?",
      "sent_at": "2026-10-02T16:02:00Z"
    }
  ]
}

POST https://cotlet.dev/api/v1/skool/get_group_stats

Returns membership and revenue numbers for a period, the same figures as the group's admin dashboard: total members, new joins, churned members and monthly recurring revenue. Admins only.

Parameters

Parameters: get_group_stats
NameTypeDescription
group required string Group URL name, e.g. 'yourgroup' for skool.com/yourgroup.
period enum 7d, 30d or 90d. Default: 30d.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/skool/get_group_stats \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"group":"yourgroup"}'
Python
result = client.call("skool", "get_group_stats", {"group":"yourgroup"})
Node.js
const result = await cotlet.call('skool', 'get_group_stats', {"group":"yourgroup"});
CLI
cotlet call skool get_group_stats --data '{"group":"yourgroup"}'

Example response

{
  "group": "yourgroup",
  "period": "30d",
  "members_total": 1284,
  "members_new": 96,
  "members_churned": 31,
  "mrr": {
    "amount": 41230,
    "currency": "USD"
  }
}

POST https://cotlet.dev/api/v1/skool/approve_membership_request

Approves one pending request, so the applicant becomes a member. Your AutoDM, if you set one, goes out as usual. By default you confirm each call; you can switch that off for this tool.

Parameters

Parameters: approve_membership_request
NameTypeDescription
group required string Group URL name, e.g. 'yourgroup' for skool.com/yourgroup.
request_id required string Request ID from list_membership_requests.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/skool/approve_membership_request \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"group":"yourgroup","request_id":"r_51e0aa"}'
Python
result = client.call("skool", "approve_membership_request", {"group":"yourgroup","request_id":"r_51e0aa"})
Node.js
const result = await cotlet.call('skool', 'approve_membership_request', {"group":"yourgroup","request_id":"r_51e0aa"});
CLI
cotlet call skool approve_membership_request --data '{"group":"yourgroup","request_id":"r_51e0aa"}'

Example response

{
  "request_id": "r_51e0aa",
  "status": "approved",
  "member_id": "m_9d02f7"
}

POST https://cotlet.dev/api/v1/skool/decline_membership_request

Declines one pending request. The applicant is not notified with a reason. By default you confirm each call; you can switch that off for this tool.

Parameters

Parameters: decline_membership_request
NameTypeDescription
group required string Group URL name, e.g. 'yourgroup' for skool.com/yourgroup.
request_id required string Request ID from list_membership_requests.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/skool/decline_membership_request \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"group":"yourgroup","request_id":"request_8c41d2"}'
Python
result = client.call("skool", "decline_membership_request", {"group":"yourgroup","request_id":"request_8c41d2"})
Node.js
const result = await cotlet.call('skool', 'decline_membership_request', {"group":"yourgroup","request_id":"request_8c41d2"});
CLI
cotlet call skool decline_membership_request --data '{"group":"yourgroup","request_id":"request_8c41d2"}'

Example response

{
  "request_id": "r_51e0aa",
  "status": "declined"
}

Create post

write Confirm

POST https://cotlet.dev/api/v1/skool/create_post

Publishes a post to the feed in a given category, under your name. Links and images go in the body as URLs. Admin-only categories need an admin account. By default you confirm each post; you can switch that off for this tool.

Parameters

Parameters: create_post
NameTypeDescription
group required string Group URL name, e.g. 'yourgroup' for skool.com/yourgroup.
title required string Post title.
body required string Post text. Links and images by URL.
category required string Category name. Admin-only categories need an admin account.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/skool/create_post \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"group":"yourgroup","title":"Week 12 challenge: ship one landing page","body":"Post your link below by Sunday. Best three get a live review on Thursday'\''s call.","category":"Announcements"}'
Python
result = client.call("skool", "create_post", {"group":"yourgroup","title":"Week 12 challenge: ship one landing page","body":"Post your link below by Sunday. Best three get a live review on Thursday's call.","category":"Announcements"})
Node.js
const result = await cotlet.call('skool', 'create_post', {"group":"yourgroup","title":"Week 12 challenge: ship one landing page","body":"Post your link below by Sunday. Best three get a live review on Thursday's call.","category":"Announcements"});
CLI
cotlet call skool create_post --data '{"group":"yourgroup","title":"Week 12 challenge: ship one landing page","body":"Post your link below by Sunday. Best three get a live review on Thursday'\''s call.","category":"Announcements"}'

Example response

{
  "post_id": "a3f9c2e1b7d84c06",
  "status": "published",
  "category": "Announcements",
  "url": "https://www.skool.com/yourgroup/week-12-challenge-ship-one-landing-page",
  "created_at": "2026-10-03T09:00:00+02:00"
}

Comment on post

write Confirm

POST https://cotlet.dev/api/v1/skool/comment_on_post

Adds a comment to a post, or a reply under an existing comment when parent_comment_id is set. The comment appears under your name. By default you confirm each comment; you can switch that off for this tool.

Parameters

Parameters: comment_on_post
NameTypeDescription
group required string Group URL name, e.g. 'yourgroup' for skool.com/yourgroup.
post_id required string Post ID from list_posts.
body required string Comment text.
parent_comment_id string Reply under this comment instead of the post.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/skool/comment_on_post \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"group":"yourgroup","post_id":"a3f9c2e1b7d84c06","body":"Good question, Lena. Module 2 of Pricing covers exactly this: start with a fixed project fee, not hourly. What is the project scope?"}'
Python
result = client.call("skool", "comment_on_post", {"group":"yourgroup","post_id":"a3f9c2e1b7d84c06","body":"Good question, Lena. Module 2 of Pricing covers exactly this: start with a fixed project fee, not hourly. What is the project scope?"})
Node.js
const result = await cotlet.call('skool', 'comment_on_post', {"group":"yourgroup","post_id":"a3f9c2e1b7d84c06","body":"Good question, Lena. Module 2 of Pricing covers exactly this: start with a fixed project fee, not hourly. What is the project scope?"});
CLI
cotlet call skool comment_on_post --data '{"group":"yourgroup","post_id":"a3f9c2e1b7d84c06","body":"Good question, Lena. Module 2 of Pricing covers exactly this: start with a fixed project fee, not hourly. What is the project scope?"}'

Example response

{
  "comment_id": "c_77c4",
  "post_id": "a3f9c2e1b7d84c06",
  "parent_comment_id": null,
  "status": "published"
}

Send message

write Confirm

POST https://cotlet.dev/api/v1/skool/send_message

Sends a direct message in Skool Chat to one member and starts a conversation if there is none yet. Messages go out under your name; by default you confirm each one, and you can switch that off for this tool.

Parameters

Parameters: send_message
NameTypeDescription
member_id required string Member ID from list_members or list_conversations.
body required string Message text.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/skool/send_message \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"member_id":"m_8c41d2","body":"Welcome, Ana! You mentioned your first client launch. Start with the Welcome lesson here: https://www.skool.com/yourgroup/classroom/co_12?md=1"}'
Python
result = client.call("skool", "send_message", {"member_id":"m_8c41d2","body":"Welcome, Ana! You mentioned your first client launch. Start with the Welcome lesson here: https://www.skool.com/yourgroup/classroom/co_12?md=1"})
Node.js
const result = await cotlet.call('skool', 'send_message', {"member_id":"m_8c41d2","body":"Welcome, Ana! You mentioned your first client launch. Start with the Welcome lesson here: https://www.skool.com/yourgroup/classroom/co_12?md=1"});
CLI
cotlet call skool send_message --data '{"member_id":"m_8c41d2","body":"Welcome, Ana! You mentioned your first client launch. Start with the Welcome lesson here: https://www.skool.com/yourgroup/classroom/co_12?md=1"}'

Example response

{
  "conversation_id": "cv_93f1",
  "message_id": "msg_4410",
  "status": "sent",
  "sent_at": "2026-10-03T09:05:00+02:00"
}

Pin post

write

POST https://cotlet.dev/api/v1/skool/pin_post

Pins a post to the top of the feed, where Skool allows up to 3 pinned posts, or to a Classroom page, which allows up to 12. Set pinned to false to unpin. Admins only. pin_post runs without asking first: pinning sends nothing to anyone and is undone with one call.

Parameters

Parameters: pin_post
NameTypeDescription
group required string Group URL name, e.g. 'yourgroup' for skool.com/yourgroup.
post_id required string Post ID from list_posts.
pinned boolean false unpins. Default: true.
course_page_id string Pin to this Classroom page instead of the feed.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/skool/pin_post \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"group":"yourgroup","post_id":"post_8c41d2"}'
Python
result = client.call("skool", "pin_post", {"group":"yourgroup","post_id":"post_8c41d2"})
Node.js
const result = await cotlet.call('skool', 'pin_post', {"group":"yourgroup","post_id":"post_8c41d2"});
CLI
cotlet call skool pin_post --data '{"group":"yourgroup","post_id":"post_8c41d2"}'

Example response

{
  "post_id": "a3f9c2e1b7d84c06",
  "pinned": true,
  "location": "feed"
}