---
name: http_post_json
kind: function
lang: py
domain: infra
version: "1.0.0"
purity: impure
signature: "http_post_json(url: str, body: dict, headers: dict[str, str] | None = None, timeout: float = 30.0) -> dict"
description: "POST request con body JSON. Agrega Content-Type: application/json y Accept: application/json. Lanza RuntimeError si status >= 400 con status code, url truncada y primeros 200 chars del body."
tags: [http, json, post, client, network, stdlib, infra]
uses_functions: []
uses_types: []
returns: []
returns_optional: false
error_type: "error_go_core"
imports: ["json", "urllib.error", "urllib.request"]
params:
  - name: url
    desc: "URL destino para la solicitud POST"
  - name: body
    desc: "diccionario a serializar como JSON en el body"
  - name: headers
    desc: "diccionario opcional de headers HTTP personalizados"
  - name: timeout
    desc: "timeout en segundos para la solicitud (defecto 30.0)"
output: "diccionario con la respuesta JSON parseada"
tested: true
tests:
  - "mock de POST con body serializado correctamente"
  - "mock de respuesta 201"
  - "mock de respuesta 500 → error"
  - "body con unicode"
test_file_path: "python/functions/infra/http_post_json_test.py"
file_path: "python/functions/infra/http_post_json.py"
---

## Ejemplo

```python
response = http_post_json(
    "https://api.example.com/users",
    body={"name": "Alice", "role": "admin"},
    headers={"X-Api-Key": "secret"},
)
print(response["id"])
```

## Notas

Solo usa stdlib (urllib). El body se serializa con json.dumps(ensure_ascii=False) y se codifica a UTF-8. Headers custom se fusionan con Content-Type y Accept por defecto (los custom tienen precedencia).
