Entitlement walls: what a blocked tool returns and why
A wall is the answer when a call is not on your plan or has hit a cap. It is a normal tool result, not an error: the call returns { "entitlement": { ... } } in place of the usual output. Free and paid covers what each plan includes; this page covers the wall itself.
When a wall appears
| Wall | Code | Tool | What lifts it |
|---|---|---|---|
| Research on Free | PAYMENT_REQUIRED | start_research_run | A paid plan |
| Research pacing | RATE_LIMITED | start_research_run | Waiting: one run per minute per user |
| Project cap | PAYMENT_REQUIRED | create_project | A paid plan, or reusing one of your 3 free projects |
| Daily brief cap | RATE_LIMITED | generate_article_brief | The 24-hour window resetting, or a paid plan (no brief cap) |
| Lint cap | RATE_LIMITED | lint_draft | The 24-hour window resetting; Free allows 10, paid plans 50 |
| Idea checks, day | RATE_LIMITED | check_idea | Midnight UTC |
| Idea checks, month | RATE_LIMITED | check_idea | The 1st of the month, or a plan with a larger allowance |
| Idea check pacing | RATE_LIMITED | check_idea | Waiting: two checks per minute |
| Idea expansions | RATE_LIMITED | expand_idea | The 24-hour window resetting; 20 a day on every plan |
| Feedback | RATE_LIMITED | send_feedback | The daily reset; 10 a day on every plan |
FEATURE_LOCKED is part of the schema, but no tool returns it today. No feature is reserved for Pro or Master over Starter. A paid organization that has spent its research credits gets a plain error from start_research_run, not a wall.
The payload, field by field
This is the free lint cap, as your agent would receive it:
{
"entitlement": {
"error_code": "RATE_LIMITED",
"tool": "lint_draft",
"reason": "You have used today's 10 draft verifications. The cap resets at 2026-10-27T09:14:00.000Z.",
"remaining": 0,
"reset_at": "2026-10-27T09:14:00.000Z",
"upgrade_url": "https://app.varynforge.com/pricing?ref=mcp&utm_source=mcp&utm_medium=tool_wall&utm_campaign=lint_draft",
"upgrade_rationale": "You're out of free draft verifications for today. The free tier covers 10/day; Starter raises it to 50/day.",
"what_unlocks": "Starter ($75/mo) raises the cap to 50/day.",
"alternative_free_actions": [
"get_lint_rubric (self-check the draft against the thresholds before resubmitting)",
"update_article_status (move the article manually if you are confident)"
]
}
}
error_code(string):PAYMENT_REQUIREDwhen the plan does not include the call,RATE_LIMITEDwhen a cap or pacing limit is spent.tool(string): the tool that was blocked.reason(string): what happened, in plain words, with the numbers.remaining(integer or null):0on a rate limit,nullon a payment wall.reset_at(ISO timestamp or null): when the cap frees up.nullon a payment wall.upgrade_url(string): the pricing page, tagged with the tool that walled.upgrade_rationale(string): a sentence usually written for you, the operator; the pacing and feedback walls address the agent instead.what_unlocks(string): what another plan changes, or that nothing does.alternative_free_actions(array of strings): tools that still work right now, each with a short note. It can be empty.
What your agent does with a wall
- It reads
upgrade_rationaleto you as written. That sentence is meant for you, so the agent does not paraphrase it. - It offers the
alternative_free_actions, so the session keeps moving. - It asks before it hands you
upgrade_url. - It does not retry or loop. The wall is the answer. On a pacing wall it waits until
reset_atbefore it calls again. - It does not file the wall with
send_feedback. A wall works as designed.
On the brief cap, an article brief that never existed is queued and forges on its own at the reset; a channel brief or a regeneration is not queued, so retry after reset_at. The reason says which. Drafting and verification covers how the agent paces lint_draft.
The same wall in the web app
The app enforces the same caps without the payload; the two per-minute pacing limits apply over MCP only. A queued brief shows when it forges, and the lint and idea caps say the daily limit is reached. Starting a research run without a plan opens a dialog that points to your plan settings. Compare plans on the pricing page.
Markdown version of this page, for your agent.