Por que o corpo da solicitação HTTP POST precisa ser JSON enconded em Python?

Eu me deparei com esse problema ao brincar com uma API externa. Eu estava enviando meus dados do corpo como um dicionário direto para a solicitação e estava recebendo 400 erros:

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

Quando adicionei um wrap json.dumps, ele funciona:

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

Eu não entendo completamente porque isso é necessário, já que dicionários e objetos JSON são sintaticamente idênticos. Alguém pode me ajudar a entender o que está acontecendo nos bastidores aqui?

Para completar, aqui estão meus cabeçalhos:

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

EDITAR:

Eu não mencionei isso antes, mas agora sinto que isso pode ser relevante. Estou usando a biblioteca Solicitações do Python, e outro post parece sugerir que você nunca deve codificar parâmetros para um objeto de solicitação:https://stackoverflow.com/a/14804320/1012040

"Independentemente de se GET / POST você nunca tem que codificar os parâmetros novamente, ele simplesmente usa um dicionário como argumento e é bom de ir."

Parece que a serialização não deveria ser necessária?

Meu objeto de solicitação:

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

questionAnswers(2)

yourAnswerToTheQuestion