Normally you should attempt to find all the corner cases and present the errors to the user -- before processing the request. If you can't do this, it's time to rethink how your api works. A good api is simple to use and simple to write.
It also simplifies your business logic in that all the possible user defined idiocies are caught before your business logic actually processes the request.
Some frameworks do this better than others. And rather than documentation, I tend to prefer comprehensive error messages.
One example of a 500 error is a null pointer error. Was it a bad request or a logic error? One is your problem the other is not. Just returning a 400 hides that issue. Validating the payload before processing it simplifies the issue for everyone involved.
A 500 error should be your problem with a stack trace in the log. A 400 error should provide enough description to tell the user it's theirs and how to fix it.
Just marking recoding a 500 to a 400 because of a null pointer error would get noticed on a code review and marked up on a code review.
It also simplifies your business logic in that all the possible user defined idiocies are caught before your business logic actually processes the request.
Some frameworks do this better than others. And rather than documentation, I tend to prefer comprehensive error messages.