Skool All-in-One API avatar

Skool All-in-One API

Under maintenance

Pricing

from $5.00 / 1,000 results

Go to Apify Store
Skool All-in-One API

Skool All-in-One API

Under maintenance

The most complete Skool API on Apify. Read AND write posts, comments, members and more. Automatic authentication with cookie caching. Perfect for AI agents and community automation.

Pricing

from $5.00 / 1,000 results

Rating

5.0

(1)

Developer

Cristian Tala S.

Cristian Tala S.

Maintained by Community

Actor stats

2

Bookmarked

21

Total users

11

Monthly active users

6.1 days

Issues response

15 hours ago

Last modified

Share

The most complete Skool automation on Apify. Full read AND write access to posts, comments, members, and more. The only Skool actor with write capabilities.

What's new in 0.2.0 (Apr 2026): Expected errors (bad credentials, missing params, not-found, rate-limit, etc.) are now returned as structured failure payloads in the dataset without marking the run as FAILED. This keeps your integrations clean and only flags real bugs. See the Error Handling section.

What makes this different

  • Read AND Write — Create posts, reply to comments, approve members. Not just scraping.
  • Fast cookie-based auth — Login once (~10s), then reuse cookies for all calls (~2s each).
  • Nested comments — Full comment trees with replies, not flat lists.
  • User mentions — Tag users with [@Name](obj://user/{id}).
  • AI-agent friendly — Clean action:operation format, perfect for n8n, OpenClaw, Claude, and other agents.

How much does it cost?

ScenarioEstimated cost
Login (once every ~3.5 days)~$0.02 (Playwright)
List 1 page of posts (~32 posts)~$0.005
Get comments on a post~$0.005
Create a post~$0.01 (write fee) + ~$0.005
Reply to a comment~$0.01 (write fee) + ~$0.005
Approve 10 pending members~$0.10 (write fees) + ~$0.005

Platform compute costs (~$0.002/run) included. Write operations have premium pricing.

Step 1: Login once — get cookies

{
"action": "auth:login",
"email": "your@email.com",
"password": "your-password",
"groupSlug": "your-community"
}

Output:

{
"success": true,
"cookies": "auth_token=eyJ...; client_id=abc...; aws-waf-token=xyz...",
"expiresAt": "2026-03-30T06:00:00.000Z",
"expiresInDays": 3.5,
"note": "Pass this cookies string in subsequent calls to skip Playwright login."
}

Step 2: Use cookies for all operations (fast, ~2s each)

{
"action": "posts:list",
"cookies": "auth_token=eyJ...; client_id=abc...; aws-waf-token=xyz...",
"groupSlug": "your-community",
"params": { "page": 1 }
}

Step 3: When cookies expire (~3.5 days) → login again

If you get an error about expired auth, simply run auth:login again.

Alternative: email + password every time (slower)

You can skip Step 1 and pass email + password directly in any action. This uses Playwright every time (~10s instead of ~2s), but it's simpler for one-off operations.

{
"action": "posts:list",
"email": "your@email.com",
"password": "your-password",
"groupSlug": "your-community",
"params": { "page": 1 }
}

Input Reference

FieldRequiredDescription
actionAlwaysWhat to do: auth:login, posts:list, posts:createComment, etc.
groupSlugAlwaysCommunity slug from URL: skool.com/{slug}
cookiesOption ACookie string from auth:login. Fast, no browser.
emailOption BSkool email. Uses Playwright, slower. Required for auth:login.
passwordOption BSkool password. Required for auth:login.
paramsVariesAction-specific parameters (see below).

Actions Reference

Authentication

ActionAuthDescription
auth:loginemail + passwordLogin via Playwright, returns cookies for reuse. Run once every ~3.5 days.

Posts (read)

ActionParamsDescription
posts:listpage? (default 1), sortType?List posts from community feed
posts:getpostIdGet single post by ID
posts:getCommentspostIdGet comment tree with nested replies

Posts (write — $0.01 per operation)

ActionParamsDescription
posts:createtitle, content, labelId?Create new post
posts:updatepostId, title?, content?Edit post or comment
posts:deletepostIdDelete post or comment
posts:pinpostIdPin post to top
posts:unpinpostIdUnpin post
posts:votepostId, vote ("up" or "")Like or unlike
posts:createCommentcontent, rootId, parentIdReply to post or comment

Members (read)

ActionParamsDescription
members:listpage?List active members
members:pendingList pending approval requests

Members (write — $0.01 per operation)

ActionParamsDescription
members:approvememberIdApprove pending member
members:rejectmemberIdReject pending member
members:banmemberIdBan member

Content Format

Posts and comments use plain text, NOT HTML.

CORRECT: "Hello world! Great post."
WRONG: "<p>Hello world! Great post.</p>"

Mentioning Users

Tag users in posts and comments:

[@Display Name](obj://user/{userId})

Example: Hey [@John Smith](obj://user/abc123def456...)! Welcome.

Get user IDs from members:list.

Important: Posts = Comments

In Skool, posts and comments are the same object.

  • Reply to a post: rootId = postId, parentId = postId
  • Reply to a comment (nested): rootId = postId, parentId = commentId
  • Edit a comment: use posts:update with the comment's ID
  • Delete a comment: use posts:delete with the comment's ID

There is no comments: namespace. Everything is posts:.

Example Workflows

Auto-approve pending members

1. auth:login → save cookies
2. members:pending → get list of pending members
3. For each: members:approve with memberId

Reply to unanswered posts

1. auth:login → save cookies
2. posts:list → filter by commentCount === 0
3. For each: posts:createComment with rootId = postId, parentId = postId

Create post with user mention

{
"action": "posts:create",
"cookies": "...",
"groupSlug": "my-community",
"params": {
"title": "Weekly Update",
"content": "Great work this week [@John Smith](obj://user/abc123...)! Keep it up.",
"labelId": "category-id"
}
}

Get full comment thread for a post

{
"action": "posts:getComments",
"cookies": "...",
"groupSlug": "my-community",
"params": { "postId": "32-char-hex-post-id" }
}

Returns nested tree:

[
{
"id": "comment-1",
"content": "Great post!",
"replies": [
{ "id": "reply-1", "content": "Thanks!", "replies": [] }
]
}
]

Output

Post object

{
"id": "32-char-hex",
"title": "Post Title",
"content": "Plain text content",
"author": { "id": "...", "firstName": "John", "lastName": "Smith", "slug": "john-smith" },
"createdAt": "2026-03-26T18:00:00Z",
"likes": 5,
"commentCount": 12,
"isPinned": false,
"url": "https://www.skool.com/community/post-slug"
}

auth:login output

{
"success": true,
"cookies": "auth_token=...; client_id=...; aws-waf-token=...",
"expiresAt": "2026-03-30T06:00:00Z",
"expiresInDays": 3.5
}

Error Handling

Starting in v0.2.0, the actor distinguishes between recoverable/expected errors (bad credentials, resource not found, rate limit, etc.) and unhandled bugs.

  • Expected errors: the run completes with status SUCCEEDED in Apify and pushes a structured failure payload to the dataset. Your integration can inspect the first item to decide next action.
  • Unhandled bugs: the run fails hard (Apify FAILED status) so they are visible to the maintainer and can be fixed.

This change means that a caller passing wrong credentials, a bad postId, or hitting a rate limit is no longer charged with a "failed" run in the actor's public stats. The error is delivered cleanly to your dataset.

Failure payload shape (dataset)

{
"success": false,
"action": "posts:createComment",
"error": "post not found: 3bc910b1",
"errorCode": "NOT_FOUND",
"errorCategory": "not_found",
"statusCode": 404,
"retryable": false,
"hint": "Verify the ID provided in params. If it was valid before, the resource may have been deleted."
}

Error categories

errorCategoryMeaningTypical retryableWhat to do
input_validationMissing/bad params (no postId, no action, etc.)falseFix the actor input and rerun
auth_errorLogin failed, captcha, bad password, AUTH_ERROR, WAF_EXPIREDtrueRe-run auth:login to get fresh cookies
not_foundNotFoundError from Skool (post/member not found)falseVerify the ID; resource may have been deleted
rate_limited429 from SkooltrueBack off and retry after a few minutes
skool_api_error4xx from Skool other than above (e.g. "cannot update to same role", missing labelId)usually falseInspect error and fix params; if 5xx, retry later
scraping_errorBuildIdStaleError when Skool dashboard HTML changedtrueRe-run auth:login to refresh buildId

Recognising a failure in your caller

const items = await fetchDatasetItems(runId);
const first = items[0];
if (first.success === false) {
console.error(`[${first.errorCategory}/${first.errorCode}] ${first.error}`);
if (first.retryable) {
// back off, refresh auth, or retry — based on errorCategory
} else {
// surface to user, adjust input
}
return;
}
// success path

Common errors → how to fix

Error message / errorCodeCauseSolution
INPUT_VALIDATION "Missing required params.postId"Missing fieldAdd the field in params
AUTH_ERROR "Login failed — still on login page after 30s"Wrong password, WAF challenge, or Skool rate-limited the loginVerify credentials; try again from a browser first
WAF_EXPIREDCookies older than ~3.5 daysRe-run auth:login
BUILDID_STALESkool deployed a new dashboardRe-run auth:login
NOT_FOUNDInvalid postId / memberIdDouble-check the ID source
RATE_LIMITHit 20-30 writes/min ceilingWait 60-120s, then retry
SKOOL_API_ERROR (400) "cannot update to same role"Member already has that roleNo-op: skip
SKOOL_API_ERROR (422) "must select category"Community requires labelIdPass labelId in params

Integration Examples

n8n Workflow

  1. HTTP Request nodeauth:login → save cookies to variable
  2. HTTP Request nodeposts:list with cookies → process posts
  3. IF node → filter unanswered posts
  4. HTTP Request nodeposts:createComment with cookies

Apify API (JavaScript)

// Login once
const loginRun = await fetch('https://api.apify.com/v2/acts/cristiantala~skool-all-in-one-api/runs?token=YOUR_TOKEN', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ action: 'auth:login', email: '...', password: '...', groupSlug: '...' })
}).then(r => r.json());
// Get cookies from dataset
const items = await fetch(`https://api.apify.com/v2/actor-runs/${loginRun.data.id}/dataset/items?token=YOUR_TOKEN`).then(r => r.json());
const cookies = items[0].cookies;
// Use cookies for fast operations
const listRun = await fetch('https://api.apify.com/v2/acts/cristiantala~skool-all-in-one-api/runs?token=YOUR_TOKEN', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ action: 'posts:list', cookies, groupSlug: '...', params: { page: 1 } })
}).then(r => r.json());

Roadmap

  • Posts CRUD (create, read, update, delete)
  • Comments with nesting (reply to posts and comments)
  • Members (list, pending, approve, reject, ban)
  • User mentions
  • Cookie-based fast auth
  • Courses (classroom) — read and create lessons
  • Events — list, create, RSVP
  • Analytics — engagement, revenue, member growth
  • Chat / DMs
  • Search
  • File uploads
  • "Send email to all members" toggle

Technical Details

  • Built on skool-js TypeScript library
  • Reads use Next.js SSR data endpoints (fast, no browser)
  • Writes use api2.skool.com REST endpoints
  • Playwright only for auth:login (cookie extraction)
  • Rate limiter: 60 reads/min, 30 writes/min
  • Auto-retry on transient errors with exponential backoff