Automated tests for the inputs you didn't think of.

unexpectedd reads your API's code, generates the edge cases, malformed payloads and abuse scenarios your tests skipped, runs them against a sandboxed copy of your app, and turns every real break into a failing test you can commit.

Now onboarding design partners. Python and FastAPI first.

Example run: unexpectedd sends five values for quantity to POST /cart/items. Four are rejected correctly. A quantity of minus three is accepted and the cart total becomes negative 87 dollars, so unexpectedd reports it with a failing test.

The bugs that pass code review

Your tests check the cases you imagined. These are the ones that ship. Every row below is the kind of finding unexpectedd is built to produce: the exact input, and what your API did with it.

KindInput it triedWhat happened
Boundariesquantity = -3Order total went negative
Malformed payloads{"email": null}500 error with a stack trace in the response body
AuthorizationUser B requests GET /invoices/41, owned by user A200, full invoice returned
State sequencesDelete the account, then reuse its old tokenToken still accepted
Encodingname = "Zoƫ\u0000"Row saved, silently missing from search
ConcurrencyTwo POST /coupons/redeem calls 5 ms apartSingle-use coupon redeemed twice

How it works

A language model decides what is worth trying. A property-based engine does the trying. You only see what it can reproduce.

  1. Read

    Point it at your repository. It reads your routes, Pydantic models, validators, auth dependencies and OpenAPI schema.

  2. Hypothesize

    Claude works out the rules your API should never break: totals stay positive, users only see their own data, deleted means gone.

  3. Search

    Hypothesis generates thousands of inputs and request sequences against an in-process copy of your app, then shrinks each failure to its smallest form.

  4. Report

    Each confirmed break comes back as a failing pytest, the file and line behind it, and a plain-English explanation. In CI, as a pull request.

Built to be safe to run

  • It tests your app, not your servers. By default it boots your app in-process with a test client. Staging URLs work only after you prove you own the domain.
  • No finding without a reproduction. If it can't write a test that fails, it doesn't report it. Noise is the reason teams turn testing tools off.
  • Nothing lands without your review. It never pushes to your branches. New tests arrive as a pull request you can read, change or close.

Get early access

We're opening early access to a small group of teams that run Python APIs in production. Join the waitlist and we'll email you when your spot opens.