For example, given this /login request to our server:
POST /login
Authorization: Basic Zm9vQGJhci5leGFtcGxlOmJhego=
Depending on the user's second factor, the server could send back a response like this: { "error": { "code": "TOTP_REQUIRED" } }
Then, depending on the error code, our UI could prompt for the second factor and we could send a new /login request: POST /login
Authorization: Basic Zm9vQGJhci5leGFtcGxlOmJhego=
{ "totp": "123456" }
This flow can work for any type of second factor, not just TOTP. It also works for good and bad passwords, and doesn't leak any information (well, other than the fact the user exists, but that road introduces a lot of other UX issues.)