But now doing serde_json::json!(response)["success"] equals to null. What am I doing wrong? Making a struct to map the response is too complicated because the response can differ a lot depending on success/error/...
You don't need to serialize and deserialize the response object (generally if you find yourself doing that, you're holding your screwdriver wrong). You can just use its methods.
Error handling is actually a difficult problem to solve when the REST API needs to support a wide variety of user agents. The common solution, as in the case of hCaptcha, is to forego the REST best practices and return errors encoded in the "application layer" of an HTTP 200 response. Because this allows the application to parse the response, even if the agent would normally discard the response body on some non-200 response codes. (This was mostly only necessary for JSONP, but the practice continues regardless.)
It's still problematic because REST itself gives agents the tools to handle errors without parsing JSON at all. Some services will give integrations a choice of APIs instead of just a one-size-fits-all least common denominator API. I know this doesn't apply here, but I wanted to point it out as a questionable decision made by the service provider.