First of all, I’d suggest you use a common error response for all API requests that result in errors. It’s not a matter of different response bodies for the same 403… but the same parseable response body that provides context of the specific 403 error. I have the following schema:
“description”: “A common error response”,
“description”: “The HTTP response status code”,
“description”: “A descriptive message, optionally i18N translated”,
“description”: “An application internal string, typically a number but possibly containing other characters. This is provided to aid in helping determine the cause of the problem if needed”,
“description”: “A message to find out more info about the specific error response, typically a link to a web page that details the code property and why this exact response may have occurred.”,
With the above schema, you can return a status of 403, but have an internal code like 403-1, 403-2, etc… that allow you to offer different 403 responses. In addition, the more_info property allows you to provide either a string of text with details… or possibly better, an actual web page link to your site where you have detailed help to responses, maybe even conditions as to why the specific response may occur. As this response is only parsed by a developer, it ensures a) that they can build an object in any language from the schema and readily parse the response body into the object regardless of error, b) you can define any number of internal custom error responses, contextual based for each resource if need be and c) you give developers learning how to use your API the optional link to more info as to what the specific possible reasons are for a given error response.
As for your bonus question… I’d first suggest you look at a tool like Open Repose, which elegantly handles rate limiting, as well as other sorts of filtering (white lists, black lists, logging of request/responses, and a lot more) in one centralized (or scalable centralized) manner. That said, I’d opt for a 429 over a 401/403. My preference.