Skip to content

uploadDocument

POST SOAP 1.1

El método uploadDocument es el punto de entrada principal para enviar documentos de nómina electrónica al sistema Facturatech. Este endpoint:

  • Recibe el XML de nómina codificado en Base64
  • Valida la estructura según esquema DIAN
  • Encola el documento para firma digital
  • Retorna un transactionID para seguimiento

ParámetroTipoObligatorioDescripción
usernamestringOKUsuario de acceso al servicio
passwordstringOKContraseña encriptada en SHA256
xmlBase64stringOKDocumento XML de nómina codificado en Base64

Request SOAP completo
<?xml version="1.0" encoding="UTF-8"?>
<x:Envelope
xmlns:x="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:dem="urn:https://ws-nomina.facturatech.co/v1/demo/">
<x:Header/>
<x:Body>
<dem:FtechAction.uploadDocument x:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<username xsi:type="xsd:string">DATAEM19112025</username>
<password xsi:type="xsd:string">f8c0e8471f126c77bd23f664f3ce251b8f9943f1d95a6ffdda72f8e6b76c9b93</password>
<xmlBase64 xsi:type="xsd:string">PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPE5vbW...</xmlBase64>
</dem:FtechAction.uploadDocument>
</x:Body>
</x:Envelope>

Response SOAP exitoso
<uploadDocumentResponse>
<codigo>200</codigo>
<transaccionID>340c8da2ee7c92713b43a9946319157d819cd2dd08d07329da622cd146cb39857e</transaccionID>
<mensaje>Documento recibido correctamente</mensaje>
</uploadDocumentResponse>
CampoTipoDescripción
codigointCódigo de estado HTTP
transaccionIDstringIdentificador único de la transacción (64 caracteres hexadecimales)
mensajestringDescripción del resultado de la operación

200 - Success

Documento recibido correctamente

El XML fue validado exitosamente y encolado para procesamiento.

Acción: Guardar transactionID y proceder a consultar estado.

400 - Bad Request

Error en la estructura del XML

Problemas de validación:

  • XML mal formado
  • Nodos mandatorios faltantes
  • Tipos de datos incorrectos
  • Valores fuera de rango

Acción: Revisar mensaje de error y corregir XML.

401 - Unauthorized

Error de autenticación

Credenciales inválidas:

  • Usuario incorrecto
  • Password SHA256 inválido
  • Credenciales expiradas

Acción: Verificar credenciales en configuración.

500 - Internal Server Error

Error interno del servidor

Problema en el servicio Facturatech:

  • Servicio temporalmente no disponible
  • Error en procesamiento interno

Acción: Reintentar después de 30-60 segundos.


  1. Generación del XML
    Dataemunáh genera el documento de nómina según estructura DIAN.

  2. Validación Local (Recomendado)
    Validar XML contra XSD antes de enviar para evitar errores 400.

  3. Codificación Base64

    $xmlBase64 = base64_encode($xmlContent);
  4. Envío a Facturatech
    Ejecutar uploadDocument con credenciales y XML codificado.

  5. Recepción de TransactionID
    Si código = 200, almacenar transactionID en base de datos.

  6. Registro en Log
    Guardar request/response completo para auditoría.

  7. Consulta de Estado
    Proceder a ejecutar documentStatus con el transactionID.


Problema: Estructura XML no cumple con esquema DIAN.

Ejemplo de error
{
"codigo": 400,
"mensaje": "Error: Nodo 'Periodo' mandatorio faltante"
}

Solución:

  1. Revisar el mensaje de error específico
  2. Validar XML contra XSD localmente
  3. Verificar todos los nodos mandatorios
  4. Corregir y reenviar

Checklist de validación:

  • Encoding UTF-8 declarado
  • Namespace correcto
  • Todos los nodos mandatorios presentes
  • Formatos de fecha/hora correctos
  • Valores numéricos con máximo 2 decimales
  • Totales cuadran matemáticamente

El transactionID debe almacenarse para operaciones posteriores:

Guardar en Base de Datos
<?php
function guardarTransactionID($nominaId, $transactionID, $xmlOriginal) {
$db = Zend_Db_Table::getDefaultAdapter();
$data = [
'nomina_id' => $nominaId,
'transaction_id' => $transactionID,
'estado' => 'ENVIADO',
'xml_original' => gzcompress($xmlOriginal), // Comprimir para ahorrar espacio
'fecha_envio' => new Zend_Db_Expr('NOW()'),
'intentos_envio' => 1
];
$db->insert('nomina_electronica', $data);
// Log
Zend_Log::info("TransactionID almacenado: $transactionID para nómina #$nominaId");
}

Log detallado
<?php
$logData = [
'timestamp' => date('Y-m-d H:i:s'),
'operacion' => 'uploadDocument',
'nomina_id' => $nominaId,
'empleado_id' => $empleadoId,
'prefijo' => $prefijo,
'consecutivo' => $consecutivo,
'transaction_id' => $response->transaccionID ?? null,
'codigo_respuesta' => $response->codigo,
'mensaje' => $response->mensaje,
'tiempo_respuesta' => $tiempoTranscurrido,
'tamano_xml' => strlen($xmlContent),
'ip_servidor' => $_SERVER['SERVER_ADDR'] ?? null
];
Zend_Log::info('uploadDocument ejecutado', $logData);

Antes de usar este endpoint en producción:

  • Validador XML local implementado
  • Codificación Base64 correcta
  • Credenciales configuradas y validadas
  • Sistema de logging activo
  • TransactionID se almacena en BD
  • Manejo de errores implementado
  • Rate limiter configurado
  • Reintentos con backoff exponencial
  • Monitoreo de tiempos de respuesta
  • Alertas configuradas para errores 500

UploadDocumentService.php
<?php
class Nomina_Service_UploadDocument
{
private $soapClient;
private $rateLimiter;
private $logger;
public function __construct()
{
$this->soapClient = new Dataemunah_Facturatech_SoapClient();
$this->rateLimiter = new Dataemunah_Facturatech_RateLimiter();
$this->logger = Zend_Registry::get('logger');
}
public function enviarNomina($nominaId)
{
try {
// 1. Obtener datos de nómina
$nomina = $this->obtenerNomina($nominaId);
// 2. Generar XML
$xml = $this->generarXML($nomina);
// 3. Validar XML localmente
if (!$this->validarXML($xml)) {
throw new Exception('XML inválido según esquema XSD');
}
// 4. Codificar Base64
$xmlBase64 = base64_encode($xml);
// 5. Respetar rate limit
$this->rateLimiter->allowRequest();
// 6. Enviar a Facturatech
$startTime = microtime(true);
$response = $this->soapClient->uploadDocument($xmlBase64);
$elapsedTime = microtime(true) - $startTime;
// 7. Procesar respuesta
if ($response['success'] && $response['codigo'] == 200) {
$this->guardarTransactionID(
$nominaId,
$response['transaccionID'],
$xml
);
$this->logger->info("Nómina #$nominaId enviada exitosamente", [
'transaction_id' => $response['transaccionID'],
'tiempo' => $elapsedTime
]);
return $response['transaccionID'];
} else {
throw new Exception($response['mensaje']);
}
} catch (Exception $e) {
$this->logger->error("Error al enviar nómina #$nominaId: " . $e->getMessage());
$this->marcarComoError($nominaId, $e->getMessage());
throw $e;
}
}
// Métodos auxiliares...
}

Después de ejecutar uploadDocument exitosamente:

Consultar el estado del documento con documentStatus usando el transactionID obtenido.