¿Por qué el cuerpo de la solicitud HTTP POST necesita estar JSON en Python?

Me encontré con este problema al jugar con una API externa. Estaba enviando mis datos corporales como un diccionario directamente a la solicitud y estaba recibiendo 400 errores:

data = {
  "someParamRange": {
    "to": 1000, 
    "from": 100
  }, 
  "anotherParamRange": {
    "to": True, 
    "from": False
  }
}

Cuando agregué una envoltura json.dumps, funciona:

data = json.dumps({
  "someParamRange": {
    "to": 1000, 
    "from": 100
  }, 
  "anotherParamRange": {
    "to": True, 
    "from": False
  }
})

No entiendo completamente por qué esto es necesario, ya que los diccionarios y los objetos JSON son sintácticamente idénticos. ¿Puede alguien ayudarme a entender lo que está pasando detrás de las escenas aquí?

Para completar, aquí están mis encabezados:

headers = {'API-KEY': 'blerg', 'Accept-Encoding': 'UTF-8', 'Content-Type': 'application/json', 'Accept': '*/*', 'username': 'user', 'password': 'pwd'}

EDITAR:

No mencioné esto antes, pero ahora siento que puede ser relevante. Estoy usando la biblioteca de solicitudes de Python, y otra publicación parece sugerir que nunca deberías tener que codificar parámetros a un objeto de solicitud:https://stackoverflow.com/a/14804320/1012040

"Independientemente de si GET / POST nunca tendrá que volver a codificar los parámetros, simplemente toma un diccionario como argumento y está listo".

Parece que la serialización no debería ser necesaria?

Mi objeto de solicitud:

response = requests.post(url, data=data, headers=headers)

Respuestas a la pregunta(2)

Su respuesta a la pregunta