# Refusals

Everything this server turns down, and what to do about it. An agent that can
enumerate the ways a call fails can plan around them; one that cannot will retry
into a cap.

## The shape of a refusal

> **Gotcha** — **A refused tool call is HTTP 200** with `result.isError: true` and the reason in
> the text. If you branch on status codes you will read every refusal as a success.
> Authentication is the exception: no token, or a bad one, is a real `401` with
> `WWW-Authenticate`.

Refusals are written to be acted on rather than logged — each says what was wrong
and what would fix it. They are also recorded: `get_activity` shows the refusal
text alongside the call, which is the fastest answer to "why did my agent stop".

## Authentication

| when                                        | what it says                           | what to do                                                                                                                            |
| ------------------------------------------- | -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| No `Authorization` header                   | missing bearer token                   | Send `Authorization: Bearer mxt_…` or complete the OAuth flow. This one is a real HTTP 401 with `WWW-Authenticate`, not a tool error. |
| A token we do not know, or one you replaced | unknown or revoked token               | Minting a new token revokes the previous one. Use the newest, or mint again at [/connect](/connect).                                  |
| The account's access was withdrawn          | this account's access has been revoked | Not a token problem — the account is closed. Contact support.                                                                         |

## Plan

| when                                        | what it says                                 | what to do                                                                                                                                 |
| ------------------------------------------- | -------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| The trial ended and no subscription started | the refusal names the price and where to pay | Relay it to your user; it is a message, not an error to retry. `get_plan` and `get_activity` keep answering so they can see what they had. |

## Caps

| when                                     | what it says                                                                                                               | what to do                                                                                                            |
| ---------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
| Too many calls today                     | daily cap reached: N calls per day. It resets at UTC midnight.                                                             | Stop for the day. Read `get_plan.usage` BEFORE a long paging walk — every page is one call.                           |
| Too many DISTINCT corpus questions today | corpus query cap reached: N distinct corpus questions per day. Repeating a question you already asked today is still free. | Re-asking something you already asked costs nothing. Sweeping with ever-changing arguments is the pattern this stops. |

## Reach — the feed gate

| when                                                                                                       | what it says                      | what to do                                                                                                                                                                               |
| ---------------------------------------------------------------------------------------------------------- | --------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `get_job` / `get_buyer` / `get_buyer_quality` / `get_job_score` on a posting this corpus has not shown you | this posting is not in your feed… | Run `search_jobs` with a filter that finds it, or `save_search` — saving also back-fills recent matches. An id from a scraped list or a competitor's export will not resolve, by design. |

## Arguments

| when                                        | what it says                                                                                | what to do                                                                                                       |
| ------------------------------------------- | ------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
| `search_jobs` with nothing to search on     | pass query, phrase or filters — search\_jobs never returns the whole corpus                 | At least one is required. `get_prefilter_catalog` for field names, or see the [filter reference](/docs/filters). |
| An empty or whitespace-only `skill`         | skill must not be empty — this tool has no all-of-corpus form                               | Name a skill, however broad. An argument meaning "no constraint" is not allowed to mean "everything".            |
| A value outside its range                   | the argument, then what it accepts — e.g. `limit: Input should be less than or equal to 50` | The bound is in the tool's `inputSchema`; read it rather than probing. Nothing is silently clamped.              |
| An argument the tool does not take          | `<tool> has no argument 'x'. It takes: …`                                                   | Usually a typo. The accepted names are listed in the message.                                                    |
| A cursor from a different search            | this cursor belongs to a different search…                                                  | Paging on it would mix two result sets. Drop the cursor to restart, or re-send the original search unchanged.    |
| A filter naming a field that does not exist | unknown field — not in the job attribute catalog                                            | Refused rather than ignored, so a typo cannot silently widen your filter.                                        |
| A webhook we will not call                  | webhook\_url must be https / resolves to a private address / has no host                    | https only, and it must not resolve to a private, loopback or reserved address.                                  |

## Answers that look like errors and are not

| when                                            | what it says                                                     | what to do                                                                                                                                     |
| ----------------------------------------------- | ---------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| Fewer than five freelancers match               | `insufficient_data: true`, with the k-floor                      | Not a failure. A statistic over fewer than five describes an individual. Widen the skill or drop the country.                                  |
| A filter that is valid and cannot match         | `warnings: … cannot match: the highest value in the corpus is N` | Still valid — bounds are observed values, not limits. But a saved search built on it fires forever without ever telling you it was the filter. |
| `delete_saved_search` on something already gone | `deleted: false`, with a note                                    | An answer, not an error.                                                                                                                       |
