Skip to main content
The Moonbounce Decisions API scores content against a decision you describe in code, records every answer, and learns from the feedback you send back. This page takes you from a key to an evaluation and its feedback in about ten minutes, with curl and with TypeScript. You need curl 7.76 or later, jq, uuidgen (built into macOS; uuid-runtime on Debian and Ubuntu) and, for the TypeScript part, Bun or Node 20+.
This isn’t a public API. Access is by invitation: join the waitlist at app.moonbounce.ai and sign up once you’re granted access. The API is in early access and unstable: names and shapes change often, breaking changes are expected, and there are no compatibility guarantees.

1. Your key and the base URL

Once you have access, a team admin creates API keys on the team’s Keys page (app.moonbounce.ai/team/keys). For this guide, make a Test key with all three scopes (decisions:evaluate, decisions:feedback and decisions:develop): a test key keeps these calls out of your production data. The full value is shown once. Keep it out of files and your shell history:
Every call goes to the same base URL and sends the key as a bearer token:
The full reference is the OpenAPI document at $MOONBOUNCE_API_URL/openapi.json; every operation there takes Authorization: Bearer <key> except GET /health and POST /v1/specs/hash.

2. Describe the decision

A decision is a small JSON spec of named nodes: features are indicators an engine detects in your content, an aggregator (combine) turns their answers into one score, calibrate maps that score onto the probability that target is true, and output names the node whose value is the decision’s score. This one decides whether a support message needs a person:
Keep this file in your repository: your code is the source of truth for the decision. Its structure hash identifies this exact set of features and how they combine. Hashing needs no key and stores nothing:
Reordering keys or reformatting the file doesn’t change the hash; changing a prompt does.

3. Evaluate an item

POST /v1/evaluate scores one item. Send the spec inline (it is registered the first time the API sees it), a decision_id of your choosing, the content as subject parts, your own item_id, and the cut points that turn the score into an outcome. Send an Idempotency-Key on every POST and keep it: if the call times out, send it again with the same key, and you get the first answer instead of a second evaluation:
The response carries the outcome, the full-precision score, every node’s value and the hashes that produced them:
"weights": "default" uses the starting weights every spec gets before any feedback: a combine is the plain mean of its answers, and calibrate passes the score through. The response says so with version.weights_fitted: false and calibrated: false. A json part ({"type": "json", "name": "order", "data": {...}}) can sit next to the text in subject. Read any evaluation back by its id:

4. Send feedback

When your app or a person learns the right answer, send it back. A claim says what was true: outcome (one of your cut points’ outcomes), target (whether the target statement held), verdict (approve or reject of our answer), or feature (the right value of one feature). Feedback is about one evaluation, or about the latest evaluation of an item in your key’s environment ({"decision_id", "item_id"}; seed examples don’t count). A verdict claim needs evaluation_id:
source says who judged. Use owner when you, the decision’s owner, or someone you trust decided the case: owner feedback is what previews and suggestions learn from. app_native (your app’s own approve or reject feedback) and app_resolution (your process settled the case) are stored too, but count only as weak feedback: they never decide a case’s right answer, though their reasons can reach the suggestion writer. The API answers 201 with the feedback id.

5. The same in TypeScript

No SDK is needed: the API is plain JSON over HTTPS.
Save it as quickstart.mts in the folder that holds decision.json and run bun quickstart.mts or npx tsx quickstart.mts (the .mts extension makes it a module, which top-level await needs).

6. Connect your coding agent (MCP)

The same operations are MCP tools at $MOONBOUNCE_API_URL/mcp, with the same key. In Claude Code, install the Moonbounce plugin, or sign in without it; Connect your agent covers both options. Neither sign-in option needs a key. Signed-in admins and members can run real and dry-run evaluations and read them in Production, attributed to them. Test needs an env:test key; unattended agents and backends use keys. For Claude Code, put this in your repository’s .mcp.json and start claude from a shell where both variables are exported:
To check the connection without an agent, list the tools:

Errors, retries and limits

Every error under /v1 has one shape: {"error": {"type", "message", "reason"?, "param"?, "details"?}}, and every response carries a Request-Id header. When you report a problem, quote it and email support@moonbounce.ai. param names the field at fault when there is one; reason is set where you can act on it, and the OpenAPI document lists them (ErrorReason).
  • Retries. Retry 429 RATE_LIMITED and 503, and a timeout, with the same Idempotency-Key, after Retry-After when it is set. If the first attempt was stored, its result comes back with Idempotent-Replayed: true and nothing runs twice; if it failed before it was stored, the retry runs it. A key is remembered for 24 hours and is scoped to your organization and the key’s environment, across every operation, so use a fresh one per request.
  • Time. An evaluation answers within 10 seconds or fails, with a 503 you can retry with the same key, or a 502 when an engine answer the score depends on is missing; Prefer: wait=<whole seconds> shortens that budget (it never lengthens it). The response is sent only after the evaluation is stored.
  • Limits. Request bodies up to 1 MB; up to 64 subject parts and 64 context parts per item; up to 64 nodes per spec. Rate limits apply per key and per client IP, counted per Cloudflare location (currently 600 requests a minute per key and 300 per IP); a 429 says how long to wait in Retry-After. Evaluate, seeds, previews and suggestions also count against your team’s rate and daily work budget (Rate limits).
  • One decision per call. Chain decisions in your own code.

Next

  • Build the mental model behind these calls: How Moonbounce works.
  • Seed a decision with a dozen labeled examples so previews have cases to replay: POST /v1/decisions/{id}/seeds.
  • Pin the structure: POST /v1/decisions/{id}/structures once, then evaluate with "structure": "<hash>" instead of the inline spec.
  • Ask for a suggested improvement and preview it against your past cases: POST /v1/decisions/{id}/suggestions and POST /v1/decisions/{id}/previews. Both see only your key’s environment, so with this guide’s test key they learn from the test cases and seeds you sent, and their suggestions are never accepted. Use a production key to improve a live decision.