How to properly handle errors in REST API responses?

I need advice on the right way to handle errors in my REST API. I’m building a new API from scratch and want to get this right from the start. Currently using XML format but will add JSON support later.

Right now I’m dealing with cases like when users try to create resources but hit their storage limits. I already use standard HTTP codes like 401 for auth issues, 403 for permissions, and 404 for bad URLs. But looking at the 400-417 status codes, none seem perfect for business logic errors.

My first thought was to send 200 OK with error details in the XML response body, but that feels wrong and inconsistent since I use status codes for other errors.

What approaches work best in practice? I want to make it easy for client developers to handle errors properly. Any examples of good patterns would be helpful.

Just use 400 for business logic errors and call it a day. Don’t overthink the exact status code - most clients only care if it’s 4xx or 5xx anyway. What matters is having clear error messages in the response body with codes like “STORAGE_FULL” so developers know exactly what went wrong.

Been through this redesigning our API last year. I went with 409 Conflict for business logic violations like storage limits - it makes sense since you’re basically saying the request conflicts with the current resource state. Works great for quota/limit scenarios. The key thing is keeping your error responses consistent no matter what status code you use. I built a standard error format with a machine-readable code, human message, and optional details field. Clients can write proper error handling without having to guess what broke. Biggest time-saver was documenting every possible error with examples. Developers love knowing exactly what errors they’ll hit and how to handle them. Also throw correlation IDs in your error responses - makes debugging production issues way easier.

Hit this exact problem building our company’s API three years ago. For business logic errors like storage limits, 422 Unprocessable Entity is perfect. It’s made for requests that are well-formed but can’t be processed due to business rules. Key is staying consistent across your entire API. I always return the same error structure no matter what - 400, 422, or 500. Makes client integration way smoother since developers only handle one error format. What really helped was adding specific error codes in the response body. Like “STORAGE_LIMIT_EXCEEDED” or “QUOTA_REACHED”. Client apps can handle different business errors properly without parsing error messages. HTTP status gives them the error category, internal code gives the specifics. Definitely skip 200 with error details in the body - you’re right it feels wrong. HTTP status codes exist for a reason, and most libraries and monitoring tools need them for proper error handling.