Skip to main content
When an endpoint or tool fails, returns the wrong thing, or lacks something you need, your agent can report it in one call. The StefanBrain team reads every report and replies on it. The reply comes back to the agent through the API and its next MCP connection.
  • Sending and reading reports is free. It never uses the API wallet or the plan pool.
  • On REST, an API key with any scope can send and read reports, and so can any OAuth token.
  • Each account can send 60 reports in any rolling hour.

When to send a report

Report a problem when:
  • An endpoint or tool failed, or returned the wrong result.
  • An error did not say how to fix the request.
  • The docs were missing, wrong, or unclear.
  • You needed something the API does not do.
  • A call was too slow, timed out, or hit a rate limit sooner than you expected.
Send one report per problem as soon as you hit it, while you still have the request, the error code, and the id. The team answers each report on its own.

Report fields

Send a JSON object with a summary. Every other field is optional, but each one you include helps the team reproduce the problem.

How intake handles imperfect reports

Intake fixes what it can instead of refusing, so a stuck agent is not stopped by its own report. The report’s adjustments array lists every change.
  • Text over its field’s limit is trimmed.
  • An unknown category is filed as other. Common words map to a category: error becomes bug, documentation becomes docs, and slow becomes performance.
  • An unknown impact is left empty. Common words map here too, such as blocking to blocked and workaround to worked_around.
  • In category and impact, case does not matter, and spaces or hyphens count as underscores. Worked around is filed as worked_around.
  • A value that looks like a credential is replaced with [redacted:<kind>].
On REST, intake also accepts a looser body:
  • A value that is not a string, such as a number or an object, is stored as its JSON text.
  • Fields intake does not recognize are kept with the report. If their JSON is over 4,000 characters, they are dropped instead, so put long text in details.
REST intake also reads these alternative field names: The only refusal is a report with no summary and no details. It returns 400 invalid_feedback, and the message shows a valid body.

Limits and cost

  • Reports never use the API wallet or the plan pool, so an account with an empty wallet or a spent plan pool can still send one.
  • On REST, each report counts as one request against your rate limits. Reading reports does not.
  • On MCP, each send_feedback or list_feedback call counts as one request.
  • An account can send 60 reports in any rolling hour. The next one returns 429 feedback_rate_limited with a Retry-After header in seconds. Wait that long, or combine what is left into one report.

Send a report over REST

POST /api/developers/v1/feedback stores the report and returns 201:
The response is the stored report plus guidance, which says where the reply will appear:
Keep the fb_ id to read the reply.

Send a report with the SDK

Since SDK 0.5.0, client.feedback sends reports and reads the team’s replies.
client.feedback.send takes the report fields in camelCase: errorCode and requestId send error_code and request_id. It is never retried automatically, because a retry could file the report twice. If a send fails without a response, check client.feedback.list before you send the report again. client.feedback.list({ status, limit }) and client.feedback.get(feedbackId) are reads, so the SDK retries them like other reads.

Send a report with the CLI

Since CLI 0.5.0, sb feedback sends reports and reads the team’s replies. By default, it prints JSON on stdout, like other sb commands.
sb feedback send also takes --details, --suggestion, --tool, --error-code, --request-id, and --agent. For a longer report, put the JSON body in a file and pass --input report.json, or --input - to read standard input. The file uses the REST field names, and flags override its fields. The CLI skips any other field and warns on stderr. If sb feedback send fails after a server error or a timeout, the report may already be filed. Check sb feedback list before you run it again. Add --pretty for readable text instead of JSON.

Send a report over MCP

The StefanBrain MCP server instructions tell your assistant to call send_feedback when a tool or endpoint fails, returns the wrong thing, or lacks something it needs. send_feedback takes the same fields as the REST body, and summary is required. category and impact accept any text and are mapped the same way as on REST.
It returns the same receipt as the REST endpoint. list_feedback returns your reports with the team’s replies. It takes an optional status and a limit from 1 to 50, 20 by default:

Read the team’s reply

Each report starts as open. A reply from the team sets one of the other statuses: The reply reaches your agent in three ways:
  • REST, SDK, and CLI: GET /api/developers/v1/feedback/{feedback_id} returns one report with reply and replied_at. GET /api/developers/v1/feedback lists your reports, newest first, and accepts status and limit (1–100, default 20).
  • MCP tool: list_feedback returns the same reports.
  • MCP connection: the next connection’s server instructions end with up to 3 replies to this account’s reports from the last 14 days, newest first. Each reply is shortened to 300 characters there; list_feedback shows the full text.
A report belongs to the account that sent it. Any key or OAuth token on that account can read it, and other accounts get 404 feedback_not_found.

Keep secrets out of reports

Never put API keys, OAuth tokens, or passwords in a report. Intake replaces values that look like credentials, such as stefan_sk_ keys, bearer tokens, and JWTs, and notes each one in adjustments. It cannot recognize every secret, such as a short password. Each report also carries your account email and plan, and your client’s name and version or user agent. It names the API key, by name and last four characters, or the OAuth connector.

Errors

On MCP, send_feedback returns failures as a tool error with isError: true. A blank summary with no details gets an invalid-input message that shows a valid body. A rate limit says how many milliseconds to wait. Authentication, scope, and request-limit failures use the shared codes in Errors and retries. The generated REST reference has the exact request and response schemas.