Skip to content

Rate limits

Limits are applied per credential, not per IP address, because AI agents tend to burst and people often share a network. The credential is your token, or your connection if you signed in to connect; a connection counts as a single bucket no matter how often it refreshes in the background.

Surface Per minute Per hour
Most endpoints 120 3,000
Search (/v1/search) 30 600
The member directory (/v1/members, /v1/members/progress, /v1/members/{id}, /v1/invitations, /v1/reporting-lines) 30 600
Learning queues (/v1/me/learning-queue, /v1/people/{id}/learning-queue) 20 300
Drafting an announcement 60 600
Planning or previewing an announcement 10 60
Sending or withdrawing an announcement 5 30
Creating a document or adding a YouTube video 10 100
Assigning or unassigning a lesson 10 60
Sending a pop quiz 5 30
Other training changes (obligations, retraining, a retraining policy) 30 300
Creating a lesson, changing what it teaches or its settings, writing its material again, or splitting it 5 30
Other lesson changes (sharing, tagging, closing, reopening, deleting) 30 300
Publishing a document’s, guide’s, video’s or audio recording’s draft 5 30
Other content changes (titles, drafts, sharing, tags, what a team holds) 30 300
Filing an issue 10 60
Previewing or deleting resources 30 300
Deciding a content review 5 30
Deciding an issue 10 40
Managing people (inviting, a role, deactivating, reactivating, removing, a reporting line) 10 60

These are generous for interactive use. They exist to stop a runaway loop, not to throttle normal work.

Each of the member directory reads hands back names, addresses and, for an organization admin, phone numbers a page at a time, so the cost that matters is how fast a credential could copy the whole directory. They are held to a lower limit than the other reads, and the same numbers apply to the MCP tools list_members, get_member, list_pending_invitations, list_member_progress and list_reporting_lines. The budget is per route and per tool, counted separately, and not one pool across them.

A learning queue is not stored: every request works it out from the person’s roles, duties, mastery and obligations, and every page of it is worked out again, so it is held to a lower limit than the other reads. The same numbers apply to the MCP tools get_my_learning_queue and get_user_learning_queue.

Assigning a lesson and sending a pop quiz reach people by email and text, and each has questions written for every person it reaches; unassigning can take a lesson and its progress back from hundreds of people at once. So they are held lower than the rest of the training changes, with the same numbers for the MCP tools assign_training, unassign_training and create_pop_quiz.

Creating or reworking a lesson has a model summarize its sources, plan its quiz and write its material, and a split writes material for every lesson it makes, so those lesson changes are held as low as sending a pop quiz, with the same numbers for the MCP tools create_lesson, update_lesson, update_lesson_content, generate_lesson_content, split_lesson and apply_lesson_split.

Publishing a draft has the resource read again from the start, chunked, embedded and its knowledge extracted, before the people trained on it can be retrained, so publishing is held as low as creating a lesson, with the same numbers for the MCP tool publish_draft.

Filing an issue calls no model, but each one lands in front of your reviewers, and one assigned to someone notifies them. A person files a few at a sitting, so it is held well below the other changes, with the same numbers for the MCP tool create_issue.

Previewing or deleting resources asks the same questions the library asks before a delete, and is held to the same numbers as the other content changes. The same numbers apply to the MCP tools preview_content_deletion and delete_content, counted per tool.

Approving a content review publishes the submission, which can retrain people and spend a model run when the knowledge base has moved, and each decision emails the person who submitted it. A reviewer decides a handful at a sitting, so deciding a review is held as low as publishing a draft, with the same numbers for the MCP tools approve_content_review, reject_content_review and request_content_review_changes.

Deciding an issue dismisses, reopens, assigns, merges or resolves one, and a new assignment notifies the person or role it names. Each of those calls, and each of the MCP tools dismiss_issue, reopen_issue, assign_issue, merge_issue, select_issue and resolve_content_gap, is held to 10 a minute and 40 an hour.

Inviting someone sends an email or a text, and deactivating or removing someone ends their access, so managing people is held to the same numbers. Each route and each of invite_member, set_member_role, deactivate_member, reactivate_member, remove_member and set_member_manager has its own budget.

The announcement limits are lower because those acts cost something: planning and previewing each spend a model call, and sending or withdrawing reaches real people. The same numbers apply to the MCP tools, counted per tool call and not per request, so send_announcement is held to five calls a minute however the requests are made. The MCP endpoint takes one JSON-RPC message per request and refuses a batch.

When you exceed a limit, the API responds with HTTP 429 Too Many Requests and a Retry-After header telling you how many seconds to wait. Respect it:

async function withRetry(makeRequest, maxRetries = 5) {
for (let attempt = 0; attempt <= maxRetries; attempt++) {
const res = await makeRequest();
if (res.status !== 429) return res;
const wait = Number(res.headers.get('Retry-After') ?? 5);
await new Promise((r) => setTimeout(r, wait * 1000));
}
throw new Error('Still rate-limited after the maximum number of retries');
}