¡tienes razón! acá va el archivo completo en un contenedor de código listo para pegar: ```html Guía maestra de integración API SII Chile (PHP + MySQL)

Guía maestra: Integración de APIs del SII (Chile) con PHP + MySQL

Última revisión: 10 de agosto de 2025 — Enfoque práctico para DTE (SOAP), Boleta Electrónica (REST) y Aceptación/Reclamo.

PHP 8.x MySQL 8.x TLS 1.2+ XMLDSIG

Resumen ejecutivo

El SII dispone de varios servicios, no una sola API. A efectos de desarrollo web, la integración se divide en:

La documentación oficial de la API REST de Boleta está publicada en el portal Swagger del SII.

Mapa de servicios & ambientes

Ambientes y dominios más usados

  • Autenticación SOAP (semilla/token): https://palena.sii.cl/DTEWS/CrSeed.jws?WSDL, https://palena.sii.cl/DTEWS/GetTokenFromSeed.jws?WSDL.
  • Consulta Estado DTE (SOAP): https://maullin.sii.cl/DTEWS/QueryEstDte.jws?WSDL.
  • Consulta Estado de Envío DTE (SOAP): https://maullin.sii.cl/DTEWS/QueryEstUp.jws?WSDL.
  • Upload de DTE: POST /cgi_dte/UPL/DTEUpload (usar host del ambiente, p. ej., palena/maullin). Requiere Cookie: TOKEN=... y campos rutSender, dvSender, rutCompany, dvCompany, archivo.
  • Boleta REST (Swagger): portal de endpoints y modelos en https://www4c.sii.cl/bolcoreinternetui/api/.

Para formatos XML y anexos (DTE, EnvíoDTE, RVD), ver el Instructivo Técnico de DTE.

Requisitos previos

Arquitectura recomendada

  1. Módulo de autenticación: obtiene y cachea el token (SOAP para DTE; REST específico para Boleta). La semilla expira en ~2 minutos, por lo que debe usarse de inmediato para solicitar el token.
  2. Módulo de envío:
    • DTE: POST multipart a DTEUpload con TOKEN en cookie.
    • Boleta: endpoint REST de “envío de boletas” (ver Swagger). Límite 500 boletas por envío; diagnóstico por servicio REST.
  3. Módulo de consultas:
    • Estado de envío (SOAP: QueryEstUp), Estado de DTE (SOAP: QueryEstDte).
    • Boleta: REST para estado de envío y consulta de boleta (ver Swagger).
  4. Eventos del DTE (Aceptación/Reclamo): WS para ingresarAceptacionReclamoDoc, listarEventosHistDoc, consultarDocDteCedible, consultarFechaRecepcionSii. Ventana de 8 días.

Esquema MySQL base

-- Tokens de autenticación (separar por ámbito)
CREATE TABLE sii_tokens (
  id BIGINT PRIMARY KEY AUTO_INCREMENT,
  scope ENUM('DTE','BOLETA') NOT NULL,
  token VARCHAR(500) NOT NULL,
  issued_at DATETIME NOT NULL,
  expires_at DATETIME NULL,
  meta JSON NULL,
  UNIQUE KEY uq_scope(scope)
);

-- Envíos (DTE y Boleta)
CREATE TABLE sii_envios (
  id BIGINT PRIMARY KEY AUTO_INCREMENT,
  tipo ENUM('DTE','BOLETA') NOT NULL,
  track_id VARCHAR(20) NULL,
  estado VARCHAR(10) NULL,
  glosa VARCHAR(255) NULL,
  payload MEDIUMTEXT NULL,
  respuesta MEDIUMTEXT NULL,
  created_at DATETIME NOT NULL,
  updated_at DATETIME NOT NULL
);

-- Documentos DTE/Boleta (cabecera mínima)
CREATE TABLE sii_documentos (
  id BIGINT PRIMARY KEY AUTO_INCREMENT,
  tipo ENUM('33','34','39','41','52','61','56','46') NOT NULL, -- etc.
  folio INT NOT NULL,
  rut_emisor VARCHAR(12) NOT NULL,
  rut_receptor VARCHAR(12) NOT NULL,
  fecha DATE NOT NULL,
  monto_total INT NOT NULL,
  xml MEDIUMTEXT NULL,
  estado_sii VARCHAR(50) NULL,
  created_at DATETIME NOT NULL,
  updated_at DATETIME NOT NULL,
  UNIQUE KEY uq_doc (tipo, folio, rut_emisor)
);

-- Bitácora de integración
CREATE TABLE sii_logs (
  id BIGINT PRIMARY KEY AUTO_INCREMENT,
  servicio VARCHAR(80) NOT NULL,
  metodo VARCHAR(80) NULL,
  request MEDIUMTEXT NULL,
  response MEDIUMTEXT NULL,
  http_status INT NULL,
  created_at DATETIME NOT NULL
);

Utilitarios PHP (certificados y helpers)

<?php
// Cargar credenciales desde variables de entorno
$CERT_PFX      = getenv('SII_CERT_PFX_PATH');     // /secure/certificado.p12
$CERT_PFX_PASS = getenv('SII_CERT_PFX_PASS');     // contraseña .p12
$CERT_KEY_PEM  = getenv('SII_CERT_KEY_PEM');      // /secure/cert.key (PEM)
$CERT_CRT_PEM  = getenv('SII_CERT_CRT_PEM');      // /secure/cert.crt (PEM)

// Si sólo tienes .p12, exporta a PEM una vez (con openssl) y referencia esas rutas.
// openssl pkcs12 -in certificado.p12 -out cert_full.pem -nodes
// openssl pkey   -in cert_full.pem -out cert.key
// openssl crl2pkcs7 -nocrl -certfile cert_full.pem | openssl pkcs7 -print_certs -out cert.crt

function rut_sin_puntos($rut){ return preg_replace('/[^0-9kK]/','',$rut); }
function dv($rut){ // cálculo Módulo 11
  $s=1; for($m=0;$rut;$rut=floor($rut/10)) $s=($s+$rut%10*(9-$m++%6))%11;
  return $s?$s-1:'K';
}
?>

Autenticación SOAP para DTE (semilla → token)

Flujo: getSeed → firmar XML de semilla (XMLDSIG) → getToken → usar TOKEN en servicios. La semilla expira en ~2 minutos, por lo que se debe firmar y canjear inmediatamente.

1) Obtener semilla

<?php
$wsdlSeed = 'https://palena.sii.cl/DTEWS/CrSeed.jws?WSDL';
$client = new SoapClient($wsdlSeed, ['trace' => 1, 'exceptions' => true]);
$resp = $client->getSeed();
$xml = new SimpleXMLElement($resp->getSeedReturn);
$semilla = (string)$xml->SEMILLA;
?>

2) Firmar semilla (XMLDSIG)

<?php
use RobRichards\XMLSecLibs\XMLSecurityDSig;
use RobRichards\XMLSecLibs\XMLSecurityKey;

$doc = new DOMDocument('1.0','UTF-8');
$doc->loadXML('<getToken><Semilla>'.htmlspecialchars($semilla).'</Semilla></getToken>');

$dsig = new XMLSecurityDSig();
$dsig->setCanonicalMethod(XMLSecurityDSig::EXC_C14N);
$dsig->addReference($doc->documentElement, XMLSecurityDSig::SHA1, ['http://www.w3.org/2000/09/xmldsig#enveloped-signature']); // RSA-SHA1 histórico

$key = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, ['type'=>'private']);
$key->loadKey($CERT_KEY_PEM, true);
$dsig->sign($key);
$dsig->add509Cert(file_get_contents($CERT_CRT_PEM));
$dsig->appendSignature($doc->documentElement);

$xmlFirmado = $doc->saveXML();
?>

3) Obtener token

<?php
$wsdlTok = 'https://palena.sii.cl/DTEWS/GetTokenFromSeed.jws?WSDL';
$clientTok = new SoapClient($wsdlTok, ['trace' => 1, 'exceptions' => true]);
$respTok = $clientTok->getToken(['pszXml' => $xmlFirmado]);
$xmlTok = new SimpleXMLElement($respTok->getTokenReturn);
$token = (string)$xmlTok->TOKEN;
// Persistir token en DB (scope = 'DTE')
?>

Envío de DTE (Upload)

El envío se realiza vía HTTP POST multipart a /cgi_dte/UPL/DTEUpload, con el TOKEN en la cookie y campos de formulario: rutSender, dvSender, rutCompany, dvCompany, más el archivo XML firmado.

<?php
$host = 'https://palena.sii.cl'; // o maullin según ambiente
$curl = curl_init($host.'/cgi_dte/UPL/DTEUpload');
$fields = [
  'rutSender'   => '66666666',
  'dvSender'    => '6',
  'rutCompany'  => '77777777',
  'dvCompany'   => '7',
  'archivo'     => new CURLFile('/path/EnvioDTE.xml','application/xml','EnvioDTE.xml'),
];
curl_setopt_array($curl, [
  CURLOPT_POST => true,
  CURLOPT_POSTFIELDS => $fields,
  CURLOPT_HTTPHEADER => ['Cookie: TOKEN='.$token],
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_TIMEOUT => 60,
]);
$resp = curl_exec($curl);
$http = curl_getinfo($curl, CURLINFO_HTTP_CODE);
curl_close($curl);
// Guardar respuesta y track-id en sii_envios
?>

Consultas SOAP para DTE

Consulta Estado de Envío (QueryEstUp)

Servicio SOAP para consultar el estado de un archivo subido (por TrackId).

<?php
$wsdl = 'https://maullin.sii.cl/DTEWS/QueryEstUp.jws?WSDL';
$cli = new SoapClient($wsdl, ['trace'=>1,'exceptions'=>true]);
$params = [
  'RutCompania' => '77777777',
  'DvCompania'  => '7',
  'TrackId'     => $trackId,
  'Token'       => $token,
];
$resp = $cli->getEstUp($params);
echo $resp->getEstUpReturn;
?>

Consulta Estado de DTE (QueryEstDte)

Servicio SOAP para consultar un DTE específico (emisor/tipo/folio/fecha/monto).

<?php
$wsdl = 'https://maullin.sii.cl/DTEWS/QueryEstDte.jws?WSDL';
$cli = new SoapClient($wsdl, ['trace'=>1,'exceptions'=>true]);
$params = [
  'RutConsultante'   => '66666666',
  'DvConsultante'    => '6',
  'RutCompania'      => '77777777',
  'DvCompania'       => '7',
  'RutReceptor'      => '55555555',
  'DvReceptor'       => '5',
  'TipoDte'          => '33',
  'FolioDte'         => '12345',
  'FechaEmisionDte'  => '2025-08-10',
  'MontoDte'         => '10620',
  'Token'            => $token,
];
$resp = $cli->getEstDte($params);
echo $resp->getEstDteReturn;
?>

Boleta Electrónica — API REST (Swagger)

Características clave:

  • Servicios REST dedicados para autenticación, envío, estado de envío y consulta de boletas.
  • Requiere TLS 1.2+ en certificación y producción.
  • Máx. 500 boletas por envío; diagnóstico por servicio REST; track-id de 15 dígitos.
  • La documentación oficial (OpenAPI/Swagger) está en el portal de la API del SII.

Flujo típico (resumen)

  1. Autenticación Boleta: solicitar semilla (REST), firmarla (XMLDSIG) y canjear por token específico de Boleta (distinto al token SOAP de facturas).
  2. Enviar boletas: POST de lote (hasta 500) con encabezado de autorización (token Boleta).
  3. Consultar estado de envío: REST por track-id (15 dígitos).
  4. Consultar boleta: endpoint de estado/validación por RUT–DV–Tipo–Folio (ver Swagger).

Ejemplo base con cURL en PHP (esqueleto)

<?php
$base = 'https://www4c.sii.cl/bolcoreinternetui/api'; // Ver rutas exactas en Swagger

// 1) Semilla (REST) - ejemplo genérico (ajusta ruta y cuerpo según Swagger)
$ch = curl_init($base.'/boleta.electronica.semilla'); // placeholder: verifica nombre real en Swagger
curl_setopt_array($ch, [CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 60]);
$resp = curl_exec($ch); curl_close($ch);
$semilla = json_decode($resp, true)['semilla'] ?? null;

// 2) Firmar semilla (igual que en SOAP, XMLDSIG) y canjear token (REST)
$xmlFirmado = firmar_semilla_xml($semilla, $CERT_KEY_PEM, $CERT_CRT_PEM); // reusa helper del módulo SOAP
$ch = curl_init($base.'/boleta.electronica.token'); // placeholder: verifica ruta exacta
curl_setopt_array($ch, [
  CURLOPT_POST => true,
  CURLOPT_HTTPHEADER => ['Content-Type: application/xml'],
  CURLOPT_POSTFIELDS => $xmlFirmado,
  CURLOPT_RETURNTRANSFER => true
]);
$resp = curl_exec($ch); curl_close($ch);
$tokenBoleta = json_decode($resp, true)['token'] ?? null;

// 3) Envío de boletas (hasta 500)
$ch = curl_init($base.'/boleta.electronica.envio'); // placeholder: verifica ruta exacta
curl_setopt_array($ch, [
  CURLOPT_POST => true,
  CURLOPT_HTTPHEADER => ['Authorization: Bearer '.$tokenBoleta, 'Content-Type: application/xml'],
  CURLOPT_POSTFIELDS => file_get_contents('/path/EnvioBoleta.xml'),
  CURLOPT_RETURNTRANSFER => true
]);
$resp = curl_exec($ch); curl_close($ch);
$trackId = json_decode($resp, true)['trackid'] ?? null;

// 4) Consultar estado de envío y/o boleta
?>

El portal Swagger muestra las rutas y modelos exactos de cada llamada (autenticación, envío, consulta). Úsalo como fuente de verdad para nombres de endpoints y campos.

Registro de Aceptación/Reclamo (ACD/ERM/RCD/RFP/RFT)

WebService para que receptor/emisor/tenedor vigente registren o consulten eventos del DTE. WSDL de certificación/producción y métodos disponibles: ingresarAceptacionReclamoDoc, listarEventosHistDoc, consultarDocDteCedible, consultarFechaRecepcionSii. Regla clave: ventana de 8 días desde la recepción del DTE en SII.

<?php
$wsdl = 'https://ws1.sii.cl/WSREGISTRORECLAMODTE/registroreclamodteservice?wsdl'; // prod
$cli = new SoapClient($wsdl, ['trace'=>1,'exceptions'=>true]);
$params = [
  'rutEmisor' => '77777777',
  'dvEmisor'  => '7',
  'tipoDoc'   => 33,   // 33=Factura, 34=Exenta, 43=Liquidación Factura
  'folio'     => 12345,
  'accionDoc' => 'ACD' // ACD/ERM/RCD/RFP/RFT
];
$resp = $cli->ingresarAceptacionReclamoDoc($params);
// Evaluar códigos de respuesta (1 OK; etc.)
?>

Paso a paso de implementación (checklist)

Preparar certificados

  • Exportar .p12 a .key (privada) y .crt (cadena) en PEM; proteger rutas y permisos.

Configurar entorno

  • Variables de entorno para rutas y contraseñas; dominios de ambiente (palena / maullin / ws1/ws2 / www4c).
  • Verificar TLS 1.2+ en clientes HTTP (boleta REST).

Autenticación DTE

  • Llamar getSeed (SOAP), firmar y obtener TOKEN con GetTokenFromSeed. Usar la semilla de inmediato (expira ~2 min).

Upload DTE & consultas

  • POST multipart a /cgi_dte/UPL/DTEUpload con cookie TOKEN. Guardar track-id.
  • Consultar estado de envío (QueryEstUp) y estado de DTE (QueryEstDte).

Boleta REST

  • Autenticación específica vía REST (semilla → token), envío por lotes (≤500), consulta de envío/boleta.
  • Usar el portal Swagger como referencia de rutas y modelos.

Aceptación/Reclamo

  • WS de Registro: aplicar acciones ACD/ERM/RCD/RFP/RFT cumpliendo ventana de 8 días; exponer consulta de eventos.

Buenas prácticas y operación

Solución de problemas comunes

SíntomaCausa probableAcción
“Semilla inválida / expirada”Demora entre getSeed y getTokenObtén nueva semilla y firma de inmediato.
Upload responde error de cookieFalta Cookie: TOKEN=...Incluye cookie; verifica vigencia del token.
Boleta: handshake TLS fallidoCliente usa TLS < 1.2Habilita TLS 1.2+ en cURL/OpenSSL.
No puedo registrar “ERM” tras reclamoReglas de negocio del WS de RegistroRevisa combinaciones válidas/errores y ventana de 8 días.

Anexos (esenciales)

Notas importantes

```