POST /api/emisores/certificado/cargar/
POST /api/emisores/certificado/cargar/
Sube un certificado .p12 a Backblaze B2 y crea el registro.
POST /api/emisores/certificado/cargar/ (multipart con
emisor, archivo y clave).
El .p12 es material criptográfico sensible: se almacena siempre en
B2 (dev y prod), nunca en disco local. Si B2 no está configurado se
rechaza la subida (400) para no escribir el certificado en disco.
Antes de almacenarlo se valida el .p12 (integridad, clave, vigencia,
que la llave sea RSA y que el NIT corresponda al emisor); ver
validar_pkcs12. Las fechas de vigencia se toman del propio
certificado.
Cada emisor tiene un certificado, y lo impone la base (el emisor
del certificado es OneToOne). Si ya hay uno, la carga se rechaza
con un 400 que dice cuál borrar: renovar es dos pasos explícitos, no un
reemplazo silencioso, porque subir un .p12 no debería destruir el que
estaba sin que nadie lo pida.
operationId: emisores_certificado_cargar_create
Autenticación
Sección titulada «Autenticación»Cualquiera de estas credenciales:
- LlaveApi — Llave de API de una integración. El valor completo es
Api-Key <prefijo>.<secreto>, tal como lo imprimemanage.py crear_llave_api. La llave alcanza exactamente los mismos emisores que la persona a cuyo nombre se creó.
Cuerpo de la petición
Sección titulada «Cuerpo de la petición»Tipo de contenido: application/json · obligatorio.
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
emisor | integer | sí | |
alias | string | no | |
archivo | string (binary) | sí | |
clave | string | sí | |
vigente_desde | string (date) | no | Admite null. |
vigente_hasta | string (date) | no | Admite null. |
Ejemplo
Sección titulada «Ejemplo»curl -X POST "https://api.rededoc.uk/api/emisores/certificado/cargar/" \ -H "Authorization: <llaveapi>" \ -H "Content-Type: application/json" \ -d '{ "emisor": 1, "alias": "texto", "archivo": "texto", "clave": "texto", "vigente_desde": "2026-01-31", "vigente_hasta": "2026-01-31" }'Respuestas
Sección titulada «Respuestas»| Código | Descripción |
|---|---|
200 | |
400 | Error |
401 | Error |
429 | Error |
200 — cuerpo
Sección titulada «200 — cuerpo»| Campo | Tipo | Descripción |
|---|---|---|
id | integer | Solo lectura. |
emisor | integer | |
alias | string | |
nombre_archivo | string | Solo lectura. |
vigente_desde | string (date) | Admite null. |
vigente_hasta | string (date) | Admite null. |
{ "id": 1, "emisor": 1, "alias": "texto", "nombre_archivo": "texto", "vigente_desde": "2026-01-31", "vigente_hasta": "2026-01-31"}400 — cuerpo
Sección titulada «400 — cuerpo»| Campo | Tipo | Descripción |
|---|---|---|
detail | string | Mensaje para mostrar a la persona. |
errores | array<object> | Nunca vacía. Cada error trae codigo, que es lo que el cliente mapea —los de DRF tal cual (required, invalid, does_not_exist, not_found…) y los propios en español (campo_desconocido, solicitud_invalida…)—, y mensaje, para la persona. Si el error es de un campo, su ruta va delante del mensaje: detalles[0].impuestos[0].tributo: Este campo es obligatorio. |
{ "detail": "texto", "errores": [ { "codigo": "texto", "mensaje": "texto" } ]}401 — cuerpo
Sección titulada «401 — cuerpo»| Campo | Tipo | Descripción |
|---|---|---|
detail | string | Mensaje para mostrar a la persona. |
errores | array<object> | Nunca vacía. Cada error trae codigo, que es lo que el cliente mapea —los de DRF tal cual (required, invalid, does_not_exist, not_found…) y los propios en español (campo_desconocido, solicitud_invalida…)—, y mensaje, para la persona. Si el error es de un campo, su ruta va delante del mensaje: detalles[0].impuestos[0].tributo: Este campo es obligatorio. |
{ "detail": "texto", "errores": [ { "codigo": "texto", "mensaje": "texto" } ]}429 — cuerpo
Sección titulada «429 — cuerpo»| Campo | Tipo | Descripción |
|---|---|---|
detail | string | Mensaje para mostrar a la persona. |
errores | array<object> | Nunca vacía. Cada error trae codigo, que es lo que el cliente mapea —los de DRF tal cual (required, invalid, does_not_exist, not_found…) y los propios en español (campo_desconocido, solicitud_invalida…)—, y mensaje, para la persona. Si el error es de un campo, su ruta va delante del mensaje: detalles[0].impuestos[0].tributo: Este campo es obligatorio. |
{ "detail": "texto", "errores": [ { "codigo": "texto", "mensaje": "texto" } ]}RedEDoc es un servicio de Semántica Digital S.A.S.