Raw API passthrough

madtea api makes a raw call against the forge’s REST API and prints the response. It is the last-resort escape hatch: prefer a first-class command (issue list, pr create, labels set, …) every time, because those carry the safety, confirmation, and output handling that a raw call does not. Reach for api only when no built-in command covers the endpoint you need — and when that happens, it’s worth filing an issue so the gap gets a real command.

The call still rides madtea’s credential rails: the token is injected from your configured backend, never written into a URL or argv, so a raw call leaks nothing the same way git remote -v would.

Synopsis

madtea api <endpoint> [json-body] [flags]
  • <endpoint> — the API path, given without the /api/v1 prefix (madtea prepends it). A leading / is optional: repos/... and /repos/... both work. {owner} and {repo} placeholders are expanded from the current repository’s config.
  • [json-body] — an optional positional JSON string used as the request body (one of the body-input modes below).

Endpoint and method

The path is relative to /api/v1, so /repos/{owner}/{repo}/issues becomes a request to /api/v1/repos/<owner>/<repo>/issues.

  • --raw skips the /api/v1 prefix, for endpoints that live outside it — /swagger.json, /api/forgejo/..., /api/packages/....
  • The HTTP method is set with -X / --method (default GET). A legacy form where the method is the first positional argument (madtea api POST /repos/...) is still accepted, but -X is preferred.

Request body

There are four mutually exclusive ways to supply the request body:

  1. -f / --field key=value — build JSON from key/value pairs. Values are auto-typed: true/false become booleans and numeric strings become numbers. Repeat the flag for multiple fields.
  2. -d / --data — a raw JSON string, curl-style.
  3. A positional JSON argument — the [json-body] after the endpoint.
  4. --input <file> — read the body from a file, or --input - to read it from stdin.

Separately, -F / --file-field key=@path loads a field’s value from a file (@- reads from stdin), for building a JSON body that includes file contents.

Output filtering

Two mutually exclusive ways to shape the output before it’s printed:

  • --jq / -q — apply a jq expression to the JSON response. No external jq binary is required; the jq engine is built in.
  • --template / -t — format the response with a Go text/template expression. Two template functions are available:
    • json — marshal a value to compact JSON, e.g. {{json .}}.
    • join — join a string slice with a separator, e.g. {{join .names ", "}}.

Pagination

--paginate follows Link headers (rel="next") and fetches every page automatically:

  • JSON array responses are concatenated into a single array.
  • JSON object responses are emitted one per line (ndjson).
  • Any --jq / --template filter is applied after all pages are fetched.

Examples

madtea api /repos/{owner}/{repo}/issues
madtea api -X POST /repos/{owner}/{repo}/issues -f title=Bug -f body="It broke"
madtea api -X PATCH /repos/{owner}/{repo}/issues/8 -f state=closed
madtea api -X POST /repos/{owner}/{repo}/issues -d '{"title":"Bug"}'
madtea api -X POST /repos/{owner}/{repo}/issues --input body.json
madtea api --raw /swagger.json
madtea api /repos/{owner}/{repo}/issues --jq '.[].title'
madtea api /repos/{owner}/{repo}/issues -q '.[] | select(.state=="open") | .number'
madtea api --paginate /repos/{owner}/{repo}/issues --jq '.[].title'
madtea api /repos/{owner}/{repo}/issues --template '{{range .}}{{.title}}{{"\n"}}{{end}}'
madtea api /repos/{owner}/{repo}/issues -t '{{range .}}#{{.number}}: {{.title}}{{"\n"}}{{end}}'

Notes

  • -H / --header is reserved for a future release and is not yet supported — the service layer rejects a non-empty header, so don’t rely on custom headers today.
  • Because api is a deliberate escape hatch, it prints a reminder to stderr on every call and, when it recognizes the endpoint, points you at the first-class command that covers it.

When to use it

Use api only when madtea has no command for what you need: a niche endpoint, a brand-new forge feature, or an ad-hoc query during debugging. For everything with a first-class command, use that command — you get confirmation prompts, safe body edits, typed output, and the rest of madtea’s guarantees that a raw call bypasses.

Canonical source: docs/guides/raw-api.md in the madtea repo.