Skip to main content

Descripción

Las Guías de Remisión Electrónicas (GRE tipo 09) son documentos obligatorios para el traslado de bienes. La empresa remitente (quien envía la mercadería) emite este tipo de guía cuando:
  • Realiza traslado de mercadería propia
  • Vende productos y coordina el envío
  • Transfiere stock entre almacenes
  • Realiza devoluciones o consignaciones
El sistema genera automáticamente la serie T001 para guías de remitente.

Flujo de Trabajo (Asíncrono GRE API)

Las guías de remisión usan un flujo asíncrono diferente al de facturas/boletas.
  1. Crear guía: POST /api/guias-remision - Genera el registro y XML firmado
  2. Enviar a SUNAT GRE: POST /api/guias-remision/{id}/enviar - Envío asíncrono vía REST, devuelve ticket
  3. Consultar ticket: POST /api/guias-remision/{id}/ticket - Verifica estado y descarga CDR
  4. Obtener CDR: GET /api/guias-remision/{id}/cdr - Descarga la constancia cuando esté disponible

Diferencia con Facturas/Boletas

AspectoFacturas/BoletasGuías de Remisión
ProtocoloSOAPREST (GRE API)
FlujoSincrónicoAsíncrono (ticket)
AutenticaciónCredenciales SOLOAuth 2.0 + SOL
Respuesta inmediataCDRTicket
Consulta posteriorNo necesariaObligatoria

POST /api/guias-remision

Crea una nueva guía de remisión.

Request Body

Destinatario

destinatario_tipo_doc
string
required
Tipo de documento del destinatario: 1 (DNI), 4 (Carnet Extranjería), 6 (RUC)
destinatario_documento
string
required
Número de documento del destinatario (máx 15 caracteres)
destinatario_nombre
string
required
Razón social o nombre completo del destinatario (máx 255 caracteres)
destinatario_direccion
string
required
Dirección del destinatario (máx 500 caracteres)
destinatario_ubigeo
string
Código ubigeo INEI (6 dígitos). Ejemplo: 150101 = Lima-Lima-Lima

Traslado

motivo_traslado
string
required
Código de motivo de traslado (2 dígitos). Ver tabla de motivos abajo
descripcion_motivo
string
Descripción adicional del motivo (máx 255 caracteres)
fecha_traslado
date
required
Fecha en que se realizará el traslado (formato: YYYY-MM-DD)
peso_total
decimal
required
Peso total de la mercadería (mínimo 0.001)
und_peso_total
string
default:"KGM"
Unidad de medida del peso: KGM (kilogramos), TNE (toneladas)
ubigeo_partida
string
Ubigeo del punto de partida (usa dirección de empresa si se omite)
dir_partida
string
Dirección de partida (usa dirección de empresa si se omite)

Transporte

mod_transporte
string
required
Modalidad de transporte: 01 (transporte público), 02 (transporte privado)
Si mod_transporte = ‘01’ (Transporte Público)
transportista_tipo_doc
string
required
Tipo de documento del transportista: 6 (RUC)
transportista_documento
string
required
RUC de la empresa de transporte (11 dígitos)
transportista_nombre
string
required
Razón social de la empresa de transporte (máx 255 caracteres)
transportista_nro_mtc
string
Número de inscripción MTC (máx 20 caracteres)
Si mod_transporte = ‘02’ (Transporte Privado)
vehiculo_m1l
boolean
default:"false"
Indica si el vehículo es categoría M1 o L (exime requisitos de conductor y placa)
Si vehiculo_m1l = false (vehículo no M1/L), todos estos campos son obligatorios:
conductor_tipo_doc
string
required
Tipo de documento del conductor: 1 (DNI), 4 (Carnet Extranjería)
conductor_documento
string
required
Número de documento del conductor (máx 15 caracteres)
conductor_nombres
string
required
Nombres del conductor (máx 255 caracteres)
conductor_apellidos
string
required
Apellidos del conductor (máx 255 caracteres)
conductor_licencia
string
required
Número de licencia de conducir (máx 20 caracteres)
vehiculo_placa
string
required
Placa del vehículo (máx 10 caracteres)
Si vehiculo_m1l = true, todos estos campos son opcionales.

Mercadería

detalles
array
required
Lista de ítems a trasladar (mínimo 1)
detalles[].descripcion
string
required
Descripción del ítem
detalles[].cantidad
decimal
required
Cantidad del ítem (mínimo 0.001)
detalles[].unidad
string
default:"NIU"
Unidad de medida: NIU (unidades), KGM (kilogramos), etc.
detalles[].codigo
string
Código interno del producto (máx 30 caracteres)
detalles[].id_producto
integer
ID del producto en el sistema (opcional)

Otros

id_venta
integer
ID de la venta relacionada (opcional)
observaciones
string
Observaciones adicionales

Motivos de Traslado (Catálogo SUNAT 20)

CódigoDescripción
01Venta
02Compra
03Traslado entre establecimientos de la misma empresa
04Traslado emisor itinerante CP
05Traslado a zona primaria
06Importación
07Exportación
08Venta con entrega a terceros
09Traslado de bienes para transformación
13Otros
14Venta sujeta a confirmación del comprador
18Traslado por emisor itinerante de bienes
19Traslado por devolución

Lógica del Servidor

  1. Valida todos los campos según la modalidad de transporte y categoría de vehículo
  2. Asigna serie fija T001 y genera número correlativo
  3. Sincroniza con documentos_empresas para numeración base configurable
  4. Usa dirección de empresa como punto de partida si no se especifica
  5. Usa ubigeo de Lima (150101) como fallback para llegada
  6. Crea registros en guia_remision y guia_remision_detalle
  7. Genera XML UBL 2.1 versión 2022 para GRE
  8. Firma digitalmente el XML con certificado PEM
  9. Calcula hash CPE
  10. Almacena XML en storage/app/sunat/xml/{ruc}/

Response

success
boolean
Indica si la operación fue exitosa
data
object
Objeto de la guía de remisión creada
xml
object
Información sobre el XML generado

Ejemplo de Request (Transporte Privado)

{
  "destinatario_tipo_doc": "6",
  "destinatario_documento": "20456789012",
  "destinatario_nombre": "DISTRIBUIDORA NORTE SAC",
  "destinatario_direccion": "AV. BENAVIDES 1234, MIRAFLORES",
  "destinatario_ubigeo": "150122",
  "motivo_traslado": "01",
  "descripcion_motivo": "Venta según factura F001-523",
  "mod_transporte": "02",
  "fecha_traslado": "2026-03-07",
  "peso_total": 85.5,
  "und_peso_total": "KGM",
  "vehiculo_m1l": false,
  "conductor_tipo_doc": "1",
  "conductor_documento": "12345678",
  "conductor_nombres": "JUAN CARLOS",
  "conductor_apellidos": "PEREZ GOMEZ",
  "conductor_licencia": "Q12345678",
  "vehiculo_placa": "ABC123",
  "detalles": [
    {
      "descripcion": "CAJAS DE CERAMICA 60X60 CM",
      "cantidad": 50,
      "unidad": "NIU",
      "codigo": "CER-6060"
    },
    {
      "descripcion": "PEGAMENTO PARA CERAMICA",
      "cantidad": 20,
      "unidad": "KGM",
      "codigo": "PEG-001"
    }
  ],
  "observaciones": "Entregar en horario de oficina"
}

Ejemplo de Request (Transporte Público)

{
  "destinatario_tipo_doc": "6",
  "destinatario_documento": "20456789012",
  "destinatario_nombre": "COMERCIAL DEL SUR EIRL",
  "destinatario_direccion": "JR. CUSCO 567, AREQUIPA",
  "motivo_traslado": "01",
  "mod_transporte": "01",
  "fecha_traslado": "2026-03-08",
  "peso_total": 1.250,
  "und_peso_total": "TNE",
  "transportista_tipo_doc": "6",
  "transportista_documento": "20123456789",
  "transportista_nombre": "TRANSPORTES RAPIDITOS SAC",
  "transportista_nro_mtc": "MTC-2024-12345",
  "detalles": [
    {
      "descripcion": "PALLETS DE PRODUCTOS VARIOS",
      "cantidad": 25,
      "unidad": "NIU"
    }
  ]
}

Ejemplo de Response (201 Created)

{
  "success": true,
  "data": {
    "id": 87,
    "serie": "T001",
    "numero": 456,
    "fecha_emision": "2026-03-06",
    "fecha_traslado": "2026-03-07",
    "destinatario_documento": "20456789012",
    "destinatario_nombre": "DISTRIBUIDORA NORTE SAC",
    "motivo_traslado": "01",
    "descripcion_motivo": "Venta según factura F001-523",
    "mod_transporte": "02",
    "peso_total": "85.500",
    "und_peso_total": "KGM",
    "ubigeo_partida": "150101",
    "dir_partida": "AV. REPUBLICA 1234, LIMA",
    "ubigeo_llegada": "150122",
    "dir_llegada": "AV. BENAVIDES 1234, MIRAFLORES",
    "conductor_documento": "12345678",
    "conductor_nombres": "JUAN CARLOS",
    "conductor_apellidos": "PEREZ GOMEZ",
    "conductor_licencia": "Q12345678",
    "vehiculo_placa": "ABC123",
    "vehiculo_m1l": false,
    "estado": "pendiente",
    "nombre_xml": "20612706702-09-T001-00000456",
    "hash_cpe": "zX8mW5kL3pN...",
    "xml_url": "sunat/xml/20612706702/20612706702-09-T001-00000456.xml",
    "detalles": [
      {
        "descripcion": "CAJAS DE CERAMICA 60X60 CM",
        "cantidad": "50.000",
        "unidad": "NIU",
        "codigo": "CER-6060"
      },
      {
        "descripcion": "PEGAMENTO PARA CERAMICA",
        "cantidad": "20.000",
        "unidad": "KGM",
        "codigo": "PEG-001"
      }
    ]
  },
  "xml": {
    "success": true,
    "nombre_archivo": "20612706702-09-T001-00000456",
    "hash": "zX8mW5kL3pN..."
  }
}

POST /api/guias-remision//enviar

Envía la guía de remisión a SUNAT GRE. Devuelve un ticket para consulta posterior.

Path Parameters

id
integer
required
ID de la guía de remisión a enviar

Flujo SUNAT GRE (Asíncrono)

  1. Autenticación OAuth 2.0:
    • Endpoint: https://api-seguridad.sunat.gob.pe/v1/clientessol/{client_id}/oauth2/token/
    • Credenciales: gre_client_id + gre_client_secret (configuradas por empresa)
    • Scope: https://api-cpe.sunat.gob.pe
    • Grant type: password (usa RUC + SOL)
    • Respuesta: Access token JWT
  2. Preparación del archivo:
    • Lee el XML firmado
    • Crea un archivo ZIP con el XML
    • Calcula hash SHA-256 del ZIP
    • Codifica el ZIP en base64
  3. Envío a GRE API:
    • Endpoint: https://api-cpe.sunat.gob.pe/v1/contribuyente/gem/comprobantes/{nombre}
    • Método: POST
    • Authorization: Bearer {access_token}
    • Body JSON:
      {
        "archivo": {
          "nomArchivo": "20612706702-09-T001-00000456.zip",
          "arcGreZip": "UEsDBAoAAAAAAA...",
          "hashZip": "abc123..."
        }
      }
      
    • Respuesta: { "numTicket": "16827364" }
  4. Actualización local:
    • Cambia estado a enviado
    • Almacena el ticket_sunat
Ver SunatService::enviarGuiaRemision() (línea 766).

Response (Éxito)

success
boolean
true si se obtuvo el ticket correctamente
ticket
string
Número de ticket para consulta posterior
message
string
Mensaje informativo

Response (Error)

success
boolean
false si hubo error
message
string
Descripción del error

Ejemplo de Response (Éxito)

{
  "success": true,
  "ticket": "16827364",
  "message": "Guía enviada. Use el ticket para consultar el estado."
}

Ejemplo de Response (Error)

{
  "success": false,
  "message": "SUNAT rechazó la guía: El RUC no está autorizado para emitir guías electrónicas"
}

POST /api/guias-remision//ticket

Consulta el estado de procesamiento en SUNAT usando el ticket obtenido al enviar.

Path Parameters

id
integer
required
ID de la guía de remisión

Flujo de Consulta

  1. Valida que la guía tenga un ticket_sunat
  2. Se autentica nuevamente con OAuth 2.0
  3. Consulta el ticket en GRE API:
    • Endpoint: https://api-cpe.sunat.gob.pe/v1/contribuyente/gem/comprobantes/envios/{ticket}
    • Método: GET
    • Authorization: Bearer {access_token}
  4. Procesa la respuesta según codRespuesta:
    • “0”: Aceptado → Descarga CDR, actualiza estado a aceptado
    • “98”: En proceso → Usuario debe reintentar después
    • Otro código: Rechazado → Actualiza estado a rechazado
Ver SunatService::consultarTicketGuia() (línea 844).

Response (Aceptado)

success
boolean
true
codigo
string
“0” (aceptado)
mensaje
string
“Guía aceptada por SUNAT.”

Response (En Proceso)

success
boolean
true (no es error, pero no está listo)
codigo
string
“98”
mensaje
string
“En proceso. Intente nuevamente en unos segundos.”
en_proceso
boolean
true (indica que debe seguir consultando)

Response (Rechazado)

success
boolean
false
codigo
string
Código de error de SUNAT
message
string
Descripción del error

Ejemplo de Uso (Polling)

// 1. Enviar guía
const envio = await fetch('/api/guias-remision/87/enviar', { method: 'POST' });
const { ticket } = await envio.json();

// 2. Consultar ticket cada 3 segundos hasta obtener respuesta definitiva
const consultar = async () => {
  const response = await fetch('/api/guias-remision/87/ticket', { method: 'POST' });
  const data = await response.json();
  
  if (data.en_proceso) {
    // Sigue en proceso, reintentar en 3 segundos
    setTimeout(consultar, 3000);
  } else if (data.success) {
    // Aceptado por SUNAT
    console.log('Guía aceptada:', data.mensaje);
  } else {
    // Rechazado
    console.error('Guía rechazada:', data.message);
  }
};

// Esperar 5 segundos antes de la primera consulta
setTimeout(consultar, 5000);

GET /api/guias-remision

Obtiene lista paginada de guías de remisión.

Query Parameters

page
integer
default:"1"
Número de página

Response

Objeto de paginación Laravel con 15 items por página.

GET /api/guias-remision/

Obtiene detalle completo de una guía específica.

GET /api/guias-remision//cdr

Descarga el archivo CDR (Constancia de Recepción) en formato ZIP.

GET /api/guias-remision/xml/

Descarga el archivo XML de la guía.

GET /api/guias-remision/proximo-numero

Obtiene el próximo número correlativo para serie T001.

Response

{
  "success": true,
  "numero": 457,
  "numero_completo": "T001-00000457"
}

GET /api/guias-remision/motivos

Obtiene la lista de motivos de traslado disponibles.

Response

[
  {
    "id": 1,
    "codigo": "01",
    "descripcion": "Venta",
    "estado": true
  },
  {
    "id": 2,
    "codigo": "02",
    "descripcion": "Compra",
    "estado": true
  }
]

GET /api/guias-remision/empresa-activa

Obtiene datos de la empresa actual (útil para prellenar dirección de partida).

GET /api/guias-remision/ubigeos

Busca ubigeos INEI.

Query Parameters

q
string
Texto de búsqueda (nombre o código)

Response

[
  {
    "id_ubigeo": "150101",
    "nombre": "LIMA - LIMA - LIMA"
  },
  {
    "id_ubigeo": "150122",
    "nombre": "LIMA - LIMA - MIRAFLORES"
  }
]

Notas Técnicas

GRE API vs SOAP

La API GRE de SUNAT (guías electrónicas 2022) usa:
  • REST en lugar de SOAP
  • OAuth 2.0 para autenticación
  • Flujo asíncrono con tickets
  • Endpoints separados de facturas/boletas

Credenciales OAuth

Las empresas deben registrar su aplicación en SUNAT para obtener:
  • gre_client_id: ID de cliente OAuth
  • gre_client_secret: Secreto de cliente OAuth
Estos se configuran por empresa en la base de datos. Si no están configurados, usa los valores por defecto de config/sunat.php.

Indicador M1/L

Vehículos categoría M1 (automóviles) o L (motocicletas) están exentos de algunos requisitos. Si vehiculo_m1l = true, el XML incluye el indicador especial:
<cbc:IndicadorTrasladoVehiculoM1L>true</cbc:IndicadorTrasladoVehiculoM1L>
Esto permite que conductor y placa sean opcionales. Ver SunatService::generarGuiaRemisionXml() línea 594.

Dirección de Partida

Si no se proporciona, usa automáticamente la dirección de la empresa emisora:
$ubigeoPartida = $request->ubigeo_partida ?: ($empresa->ubigeo ?: '150101');
$dirPartida = $request->dir_partida ?: ($empresa->direccion ?: '');

Tiempo de Procesamiento

SUNAT puede tardar entre 5 segundos y 2 minutos en procesar una guía. El frontend debe implementar polling con intervalos de 3-5 segundos.

Errores Comunes

CódigoDescripciónSolución
2800RUC no autorizado para GREActivar GRE en SUNAT Operaciones en Línea
4000Error en OAuthVerificar client_id y client_secret
2324Datos de transporte incompletosVerificar conductor/vehículo según modalidad
98En procesoNormal, seguir consultando el ticket
422XML no generadoLlamar primero a POST /api/guias-remision

Build docs developers (and LLMs) love