El sandbox
Modo test — qué garantiza, cómo forzar un rechazo o un reparo, y los test helpers que mueven el mundo exterior.
Qué es, y qué no es
Modo test (sk_test_) | Certificación SII (sk_live_, empresa ambiente: certificacion) | Producción (sk_live_, empresa ambiente: produccion) | |
|---|---|---|---|
| Tráfico al SII | ninguno | maullin / apicert (servidores de prueba del SII) | palena / api.sii.cl |
| Certificado requerido | no | sí (el .pfx real de la empresa) | sí |
| CAF real requerido | no (folios virtuales) | sí (CAF de maullin) | sí |
| Latencia a estado terminal | ~1 s, determinista | minutos a horas | minutos a horas |
| Resultado | forzable | lo que diga el SII | lo que diga el SII |
| Efecto legal | ninguno | ninguno | completo |
| Precio | gratis para siempre | medido | medido |
El modo test es una simulación completa en proceso. Nunca abre un socket al SII, así que es instantáneo, determinista e inmune a las ventanas de mantención del SII. La certificación SII es el SII real en sus servidores de prueba, usada durante la puesta en marcha para certificar una empresa específica — rara vez la manejarás directamente.
Garantías de determinismo
En modo test:
- Los folios parten en 1 por cada
(empresa, tipo_dte)e incrementan de a uno. No se necesita CAF;GET /v1/foliosreporta un rango virtual de 1 a 1.000.000. - El
track_ides un entero sintético creciente de 10 dígitos que empieza en9000000001. - Los documentos se asientan
queued → sent → accepteden aproximadamente un segundo, disparando cada webhook que dispararía un documento real. - El XML es válido contra el esquema, firmado con el certificado de sandbox de Facturia, y lleva un TED construido desde un CAF de sandbox. No va a validar contra el SII — ese es el punto.
- Los PDF traen el layout real con una marca de agua
SIN VALOR TRIBUTARIO. - Todo objeto lleva estampado
"mode": "test".
Los límites de tasa del modo test son los mismos que los de live, así que una prueba de carga es representativa.
Forzar resultados
Agrega un objeto test a cualquier emisión.
curl -sS https://api.facturia.cl/v1/documents \
-H "Authorization: Bearer $FACTURIA_KEY" \
-H "Facturia-Empresa: $EMPRESA" \
-H "Content-Type: application/json" \
-d '{
"tipo_dte": 33,
"receptor": { "rut": "76543212-K" },
"items": [{ "description": "Consultoría", "quantity": 1, "unit_price": 1200000 }],
"test": { "outcome": "rejected", "reason_code": "TED-2-510", "settle_after_ms": 3000 }
}'test.outcome | Resultado |
|---|---|
accepted (por defecto) | status: accepted, estado SII DOK |
reparo | status: reparo, estado SII DNK, un rejection_reason |
rejected | status: rejected, estado de sobre RCT, reason_code devuelto tal cual |
failed | status: failed antes de transmitir (simula una falla al armar o firmar) |
stuck | se queda en sent para siempre (para probar tus timeouts de polling) |
Trampa
El campo test es una alarma, no una opción
Enviar el objeto test con una llave live se rechaza con 400 test_field_in_live_mode. Es un cable
trampa deliberado: el código de simulación no puede correr en silencio contra el SII.
Si tu cliente no puede agregar campos, los RUT de receptor mágicos hacen lo mismo:
| RUT del receptor | Fuerza |
|---|---|
44444440-1 | accepted |
44444441-K | reparo |
44444442-8 | rejected |
44444443-6 | failed |
44444444-4 | stuck |
66666666-6 | consumidor final anónimo (válido también en live, solo boletas) |
Test helpers
Los endpoints bajo /v1/test_helpers existen solo para llaves de test (403 test_mode_only en otro
caso). Te dejan manejar las mitades del sistema que normalmente maneja el mundo exterior.
# Inyectar un DTE de proveedor como si hubiera llegado a [email protected]
curl -sS https://api.facturia.cl/v1/test_helpers/received_documents \
-H "Authorization: Bearer $FACTURIA_KEY" \
-H "Facturia-Empresa: $EMPRESA" \
-H "Content-Type: application/json" \
-d '{
"tipo_dte": 33,
"folio": 8812,
"emisor": { "rut": "96790240-3", "legal_name": "Proveedor Austral SpA" },
"issue_date": "2026-08-12",
"totals": { "net": 450000, "iva": 85500, "total": 535500 }
}'# Sembrar filas de RCV en un período para que la propuesta de F29 tenga sobre qué calcular
curl -sS https://api.facturia.cl/v1/test_helpers/rcv/seed \
-H "Authorization: Bearer $FACTURIA_KEY" -H "Facturia-Empresa: $EMPRESA" \
-H "Content-Type: application/json" \
-d '{"period":"2026-07","purchases":12,"sales":40}'
# Adelantar el reloj simulado de esta empresa
# (prueba la ventana de acuse de 8 días, el vencimiento de folios, los plazos del F29)
curl -sS https://api.facturia.cl/v1/test_helpers/clock \
-H "Authorization: Bearer $FACTURIA_KEY" -H "Facturia-Empresa: $EMPRESA" \
-H "Content-Type: application/json" \
-d '{"advance_days":9}'
# Llevar una máquina de estados de puesta en marcha a cualquier estado sin esperar al SII
curl -sS https://api.facturia.cl/v1/test_helpers/empresas/emp_01K2R.../onboarding \
-H "Authorization: Bearer $FACTURIA_KEY" \
-H "Content-Type: application/json" \
-d '{"status":"action_required","step":"sii_postulacion"}'El helper del reloj es cómo se prueba la ventana de 8 días
Inyecta un documento recibido, avanza el reloj nueve días y observa cómo la respuesta comercial deja
de aceptar acciones con 422 commercial_response_window_closed. Es la única forma de ejercitar ese
plazo sin esperar más de una semana. La ventana está explicada en
La ventana de 8 días.
Realidades de arriba que igual conviene diseñar
Por encima de nuestros límites hay dos realidades del SII que existen aunque el sandbox no las
simule: el SII limita tasa sin publicar sus cifras, y tiene ventanas de mantención programadas. La
emisión está encolada de nuestro lado, así que una ráfaga sobre 10 req/s es un 429 del lado del
cliente, nunca un documento perdido — pero un documento que ya aceptamos va a quedarse en queued
más tiempo durante una caída del SII. Construye sobre webhooks, no sobre polling apretado.