Install
openclaw skills install skool-all-in-one-apiFull read AND write access to Skool communities. Use when user asks to manage Skool members (approve, reject, list pending), read or create posts, reply to comments, mention users, or automate community management. The only Skool tool with write capabilities.
openclaw skills install skool-all-in-one-apiFull read AND write access to Skool communities via Apify.
.env file with APIFY_TOKENmcpc CLI toolPosts and comments are the SAME object in Skool.
posts:getComments — NOT comments:listposts:createComment — NOT comments:createcomments: namespace. Everything is posts:.Content is PLAIN TEXT, not HTML.
Hello world<p>Hello world</p>User mentions: [@Display Name](obj://user/{userId})
Copy this checklist and track progress:
Task Progress:
- [ ] Step 1: Determine action needed
- [ ] Step 2: Login (auth:login) or use existing cookies
- [ ] Step 3: Execute the action
- [ ] Step 4: Present results
Select the action based on user needs:
| User Need | Action | Params |
|---|---|---|
| Authentication | ||
| Login to Skool | auth:login | email, password, groupSlug |
| Posts | ||
| List posts | posts:list | page?, sortType? |
| Filter posts (date, unanswered) | posts:filter | since?, until?, notAnsweredBy?, maxPosts? |
| Get single post | posts:get | postId |
| Create post | posts:create | title, content (plain text), labelId? |
| Edit post or comment | posts:update | postId, title?, content? |
| Delete post or comment | posts:delete | postId |
| Pin/unpin post | posts:pin / posts:unpin | postId |
| Like/unlike | posts:vote | postId, vote ("up" or "") |
| Comments | ||
| Get comments (nested tree) | posts:getComments | postId |
| Reply to post | posts:createComment | content, rootId=postId, parentId=postId |
| Reply to comment (nested) | posts:createComment | content, rootId=postId, parentId=commentId |
| Members | ||
| List members | members:list | page? |
| List pending applications | members:pending | (none) |
| Approve member | members:approve | memberId (use member.memberId, NOT member.id) |
| Reject member | members:reject | memberId |
| Ban member | members:ban | memberId |
| Events | ||
| List calendar events | events:list | (none) |
| List upcoming events | events:upcoming | (none) |
Recommended flow (fast):
auth:login once to get cookies# Login and get cookies
export $(grep APIFY_TOKEN .env | xargs)
RESULT=$(curl -s -X POST "https://api.apify.com/v2/acts/cristiantala~skool-all-in-one-api/runs?token=$APIFY_TOKEN&waitForFinish=120" \
-H "Content-Type: application/json" \
-d '{
"action": "auth:login",
"email": "USER_EMAIL",
"password": "USER_PASSWORD",
"groupSlug": "GROUP_SLUG"
}')
RUN_ID=$(echo $RESULT | jq -r '.data.id')
COOKIES=$(curl -s "https://api.apify.com/v2/actor-runs/$RUN_ID/dataset/items?token=$APIFY_TOKEN" | jq -r '.[0].cookies')
echo "Cookies saved. Valid for ~3.5 days."
With cookies (fast, ~2s):
export $(grep APIFY_TOKEN .env | xargs)
curl -s -X POST "https://api.apify.com/v2/acts/cristiantala~skool-all-in-one-api/runs?token=$APIFY_TOKEN&waitForFinish=120" \
-H "Content-Type: application/json" \
-d '{
"action": "ACTION_NAME",
"cookies": "COOKIES_FROM_LOGIN",
"groupSlug": "GROUP_SLUG",
"params": { PARAMS_HERE }
}'
With email+password (slower, ~10s, uses Playwright):
export $(grep APIFY_TOKEN .env | xargs)
curl -s -X POST "https://api.apify.com/v2/acts/cristiantala~skool-all-in-one-api/runs?token=$APIFY_TOKEN&waitForFinish=120" \
-H "Content-Type: application/json" \
-d '{
"action": "ACTION_NAME",
"email": "USER_EMAIL",
"password": "USER_PASSWORD",
"groupSlug": "GROUP_SLUG",
"params": { PARAMS_HERE }
}'
Get results from dataset:
RUN_ID=$(echo $RESULT | jq -r '.data.id')
curl -s "https://api.apify.com/v2/actor-runs/$RUN_ID/dataset/items?token=$APIFY_TOKEN" | jq .
Format results based on the action:
To find which posts the user hasn't replied to, you need their Skool user ID.
1. auth:login → save cookies
2. members:list → find the user by name/email → get their "id" field (this is the user ID, NOT memberId)
3. posts:filter with params:
{
"since": "2026-03-20T00:00:00Z",
"notAnsweredBy": "USER_ID_FROM_STEP_2",
"maxPosts": 50
}
4. Show the filtered posts — these are posts the user has NOT replied to
How to get USER_ID: Run members:list and find the user by firstName/lastName. The id field (NOT memberId) is what you pass to notAnsweredBy.
Alternative — just get posts with 0 comments:
1. auth:login → save cookies
2. posts:list with params: { "page": 1 }
3. Filter results where commentCount === 0
1. auth:login → save cookies
2. members:pending → get list with application answers
3. For each member to approve: members:approve with params: { "memberId": member.memberId }
IMPORTANT: Use member.memberId (membership ID), NOT member.id (user ID)
1. auth:login → save cookies
2. posts:createComment with params:
- content: "Great point [@Name](obj://user/{userId})! I agree with your analysis."
- rootId: "post-id"
- parentId: "post-id" (same as rootId for top-level comment)
1. posts:getComments → find the comment ID
2. posts:createComment with params:
- content: "Thanks for sharing!"
- rootId: "original-post-id" (ALWAYS the root post, never a comment)
- parentId: "comment-id" (the comment you're replying to)
memberId field (membership ID), NOT id (user account ID). They are different.[@Name](obj://user/{userId}) format. Get userId from members:list.cristiantala~skool-all-in-one-apig2VGrINIS7pb8t2bs