Hecho con por Angelito Systems S.A.C. Desarrollamos sistemas web, apps móviles, SDKs y ERPs a medida ¿Necesitas ayuda con tu proyecto? Contáctanos Integraciones SUNAT · CPE · Guías de remisión Software a medida para empresas peruanas APIs, backends NestJS y frontends modernos Hecho con por Angelito Systems S.A.C. Desarrollamos sistemas web, apps móviles, SDKs y ERPs a medida ¿Necesitas ayuda con tu proyecto? Contáctanos Integraciones SUNAT · CPE · Guías de remisión Software a medida para empresas peruanas APIs, backends NestJS y frontends modernos
V7 SDK Visioner7

NestJS + TypeScript · v2.0.0

Una capa tipada entre tu backend y el servicio de Visioner7

SDK de integración independiente que organiza las consultas SUNAT, la emisión de comprobantes y las guías de remisión en interfaces TypeScript listas para NestJS, sin que tu aplicación tenga que hablar HTTP directamente con el proveedor.

$ npm install @angelitosystems/sdk-visioner7
7 operacionesconsultas, guías y comprobantes
API en inglésmapping automático al proveedor
NestJS nativoforRoot y forRootAsync
Errores centralizadosSDKVisioner7ApiException

Primeros pasos

Instala la capa de integración

El SDK se distribuye como paquete scoped y depende de @nestjs/axios para realizar las peticiones HTTP hacia el servicio contratado.

Terminal
npm install @angelitosystems/sdk-visioner7
npm install @nestjs/axios axios reflect-metadata rxjs

Si el proyecto vive dentro de un monorepo o como código interno, también puede integrarse como librería privada, por ejemplo en libs/sdk-visioner7/, o distribuirse mediante un registro privado de paquetes.

Primeros pasos

Requisitos

  • NestJS 12 y TypeScript en el proyecto host.
  • Node.js en una versión moderna con soporte activo.
  • @nestjs/axios, axios, reflect-metadata y rxjs como dependencias del proyecto.
  • Credenciales vigentes del servicio contratado (token de autenticación y, según la operación, token de negocio o credenciales SOL).

Configuración

Registra el módulo

Usa forRoot para una configuración directa, o forRootAsync cuando las credenciales provienen de variables de entorno o de un ConfigService. El módulo puede registrarse como global para evitar importaciones repetidas donde se use SDKVisioner7Service.

app.module.ts
import { Module } from '@nestjs/common';
import { SDKVisioner7Module } from '@angelitosystems/sdk-visioner7';

@Module({
  imports: [
    SDKVisioner7Module.forRoot({
      baseUrl: 'https://visioner7-api.com/api',
      authToken: process.env.SDK_VISIONER7_AUTH_TOKEN,
      businessToken: process.env.SDK_VISIONER7_BUSINESS_TOKEN,
      timeout: 15000,
    }),
  ],
})
export class AppModule {}
OpciónDescripción
baseUrlURL base del servicio contratado.
authTokenToken de autenticación proporcionado para el servicio.
businessTokenToken utilizado por determinadas operaciones.
timeoutTiempo máximo de espera de las solicitudes HTTP.

El valor de baseUrl debe corresponder al entorno y servicio que tenga habilitado el cliente.

Recomendado cuando la configuración proviene de variables de entorno o ConfigService.

app.module.ts
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { SDKVisioner7Module } from '@angelitosystems/sdk-visioner7';

@Module({
  imports: [
    ConfigModule.forRoot({ isGlobal: true }),

    SDKVisioner7Module.forRootAsync({
      imports: [ConfigModule],
      inject: [ConfigService],
      useFactory: (config: ConfigService) => ({
        baseUrl: config.get<string>('SDK_VISIONER7_BASE_URL'),
        authToken: config.get<string>('SDK_VISIONER7_AUTH_TOKEN'),
        businessToken: config.get<string>('SDK_VISIONER7_BUSINESS_TOKEN'),
        timeout: 15000,
      }),
    }),
  ],
})
export class AppModule {}

Configuración

Variables de entorno

Nunca almacenes credenciales reales directamente en el código fuente. Usa variables de entorno, un secret manager o los secretos administrados por tu proveedor de infraestructura.

.env
SDK_VISIONER7_BASE_URL=https://visioner7-api.com/api
SDK_VISIONER7_AUTH_TOKEN=your_token_here
SDK_VISIONER7_BUSINESS_TOKEN=your_business_token_here

Uso

Inyecta el servicio donde lo necesites

Una vez registrado el módulo, SDKVisioner7Service queda disponible para cualquier servicio de dominio o controlador de NestJS.

facturacion.service.ts
import { Injectable } from '@nestjs/common';
import { SDKVisioner7Service } from '@angelitosystems/sdk-visioner7';

@Injectable()
export class FacturacionService {
  constructor(private readonly sdkVisioner7Service: SDKVisioner7Service) {}

  async validarCliente(ruc: string) {
    const response = await this.sdkVisioner7Service.lookupTaxpayer(ruc);
    return response.taxpayer;
  }
}

Referencia de API

Tres grupos de operaciones

Cada grupo se identifica con un color a lo largo de toda la guía, para que sea fácil ubicar a qué frente pertenece cada método.

Consultas

RUC, DNI y tipo de cambio

Consulta de RUC, domicilio fiscal, establecimientos anexos, DNI y tipo de cambio.

lookupTaxpayer()lookupPerson()getExchangeRate()
Guías de remisión

Emisión y seguimiento

Emisión de guías por tipo de remitente o transportista, y consulta de estado mediante ticket.

issueRemittanceGuide()getRemittanceGuideTicketStatus()
Comprobantes

CPE y facturación

Generación de comprobantes de pago electrónicos, al contado o al crédito.

generateVoucher()

Consultar RUC

lookupTaxpayer(ruc: string | number)Promise<TaxpayerLookupResponse>

Realiza una consulta de RUC mediante el servicio contratado. La aplicación debe contar con las credenciales y permisos correspondientes para utilizar esta operación.

Ver ejemplo
Ejemplo
const response = await sdkVisioner7Service.lookupTaxpayer('20611187719');
console.log(response.taxpayer.businessName);
lookupEstablishments(ruc, queryType)Promise<EstablishmentLookupResponse>

Consulta el domicilio fiscal o los establecimientos anexos de un RUC. El tipo de consulta acepta el enum EstablishmentQueryType o su valor numérico equivalente, por ejemplo EstablishmentQueryType.FISCAL_ADDRESS o 1.

Ver ejemplo
Ejemplo
const domicilio = await sdkVisioner7Service.lookupEstablishments(
  '20611187719',
  EstablishmentQueryType.FISCAL_ADDRESS,
);
lookupPerson(dni: string | number)Promise<NaturalPersonLookupResponse>

Obtiene los datos asociados a un DNI. El uso de información personal debe realizarse de acuerdo con la normativa aplicable y con una finalidad legítima.

Ver ejemplo
Ejemplo
const persona = await sdkVisioner7Service.lookupPerson('10292315');
console.log(persona.person.givenNames);
getExchangeRate(params: ExchangeRateRequest)Promise<ExchangeRateResponse>

Devuelve el tipo de cambio de compra y venta para el año y mes indicados. Cuando corresponda, el SDK utiliza el businessToken configurado en el módulo.

Ver ejemplo
Ejemplo
const response = await sdkVisioner7Service.getExchangeRate({ year: 2025, month: 7 });

const compra = response.data.find(item => item.side === 'C')?.value;
const venta = response.data.find(item => item.side === 'V')?.value;

Guías de remisión

issueRemittanceGuide(payload: RemittanceGuideRequest)Promise<RemittanceGuideResponse>

Emite una guía de remisión con los datos del documento, el emisor y el detalle de ítems transportados. Los campos requeridos dependen del tipo de guía y de las especificaciones del servicio contratado.

Los tres tipos de guía (remitente público, privado o transportista) se especifican combinando los campos correspondientes de RemittanceGuideRequest.

Ver ejemplo
Ejemplo ilustrativo
const resultado = await sdkVisioner7Service.issueRemittanceGuide({
  processType: '1',
  companyDocumentNumber: 'YOUR_RUC',
  companySolUsername: 'YOUR_SOL_USER',
  companySolPassword: 'YOUR_SOL_PASSWORD',
  signaturePassword: 'YOUR_SIGNATURE_PASSWORD',
  idToken: 'YOUR_ID_TOKEN',
  tokenKey: 'YOUR_TOKEN_KEY',
  documentTypeCode: '09',
  documentNumber: 'T001-00000002',
  documentDate: '2025-08-10',
  companyDocumentType: '6',
  companyBusinessName: 'EMPRESA DE EJEMPLO S.A.C.',
  recipientDocumentType: '6',
  recipientDocumentNumber: 'YOUR_CLIENT_RUC',
  recipientBusinessName: 'CLIENTE DE EJEMPLO S.A.C.',
  shipmentItem: '1',
  transferReasonCode: '01',
  transferReasonDescription: 'VENTA',
  grossWeightUnit: 'KGM',
  grossWeight: '10.00',
  transportModalityCode: '01',
  startDate: '2025-08-10',
  originUbigeoCode: '150101',
  originAddress: 'AV. EJEMPLO 123',
  destinationUbigeoCode: '150101',
  destinationAddress: 'AV. DESTINO 456',
  items: [
    { item: '1', unitOfMeasure: 'NIU', quantity: '1', orderItem: '1', description: 'PRODUCTO DE EJEMPLO', code: 'PROD001' },
  ],
});
// los valores mostrados son ilustrativos: sustitúyelos por los de tu propio entorno
getRemittanceGuideTicketStatus(payload)Promise<RemittanceGuideTicketStatusResponse>

Consulta el estado de una guía a partir del ticket devuelto en la emisión.

Ver ejemplo
Ejemplo
const estado = await sdkVisioner7Service.getRemittanceGuideTicketStatus({
  ticket: 'YOUR_TICKET',
  companyDocumentNumber: 'YOUR_RUC',
  companySolUsername: 'YOUR_SOL_USER',
  companySolPassword: 'YOUR_SOL_PASSWORD',
  idToken: 'YOUR_ID_TOKEN',
  tokenKey: 'YOUR_TOKEN_KEY',
  documentTypeCode: '31',
  documentNumber: 'V001-00000001',
  processType: '1',
});

Comprobantes electrónicos

generateVoucher(payload: GenerateVoucherRequest)Promise<GenerateVoucherResponse>

Genera un comprobante de pago electrónico. La modalidad de pago se determina mediante la información enviada en paymentTerms (contado o crédito con cuotas).

La respuesta expone sunatCode, sunatMessage, file, cdrHash y el bloque cdrData.

Ver ejemplo
Ejemplo ilustrativo
const factura = await sdkVisioner7Service.generateVoucher({
  operationType: '0101',
  totalTaxableAmount: '305.08',
  subtotal: '305.08',
  igvPercentage: '18.00',
  totalIgv: '54.92',
  total: '360.00',
  voucherTypeCode: '01',
  currencyCode: 'PEN',
  voucherNumber: 'F001-00000001',
  issueDate: '2025-08-10',
  totalInWords: 'TRESCIENTOS SESENTA CON 00/100 SOLES',
  clientDocumentNumber: 'YOUR_CLIENT_DOCUMENT',
  clientBusinessName: 'CLIENTE DE EJEMPLO',
  clientDocumentType: '6',
  companyDocumentNumber: 'YOUR_RUC',
  companyDocumentType: '6',
  companyBusinessName: 'EMPRESA DE EJEMPLO S.A.C.',
  companySolUsername: 'YOUR_SOL_USER',
  companySolPassword: 'YOUR_SOL_PASSWORD',
  certificatePassword: 'YOUR_CERT_PASSWORD',
  signaturePassword: 'YOUR_SIGNATURE_PASSWORD',
  processType: '1',
  paymentTerms: [{ paymentFormCode: 'Contado', amount: '360.00' }],
  items: [{
    item: '1', unitOfMeasure: 'NIU', quantity: '1.00',
    price: '360.00', amount: '305.08', igv: '54.92',
    code: 'PROD001', description: 'PRODUCTO DE EJEMPLO',
    priceTypeCode: '01', igvPercentage: '18.00', isc: '0.00',
    operationTypeCode: '10', priceWithoutIgv: '305.08',
    icbperFlag: 0, icbperTaxAmount: '0.00', icbperTotalAmount: '0.00',
  }],
});

console.log(factura.sunatMessage, factura.file);

Operación

Manejo de errores

El SDK centraliza los errores mediante SDKVisioner7ApiException, que extiende HttpException de NestJS, para integrarse con los ExceptionFilter globales de tu aplicación.

Ejemplo
import { SDKVisioner7ApiException } from '@angelitosystems/sdk-visioner7';

try {
  await sdkVisioner7Service.lookupTaxpayer('00000000000');
} catch (error) {
  if (error instanceof SDKVisioner7ApiException) {
    console.error(error.endpoint, error.providerResponse);
  }
  throw error;
}

Operación

Arquitectura recomendada

El frontend no debe comunicarse directamente con el servicio externo usando credenciales privadas. Las credenciales permanecen exclusivamente en el backend, detrás de SDKVisioner7Service.

Frontend
Backend / API
Clientes
Facturación
Guías
Reportes
SDKVisioner7Service
Servicio API contratado
Operaciones correspondientes

Los distintos servicios de dominio de tu backend hablan con SDKVisioner7Service; solo esa capa conoce el servicio externo.

!

Seguridad

Las credenciales nunca salen del backend

No expongas tokens SOL ni credenciales en frontend, JavaScript de navegador, apps móviles sin protección o repositorios públicos. Usa variables de entorno o un secret manager.

SDK_VISIONER7_AUTH_TOKENSDK_VISIONER7_BUSINESS_TOKENUSUARIO_SOL_EMPRESAPASS_SOL_EMPRESAPAS_FIRMACLAVE_TOKENID_TOKEN
.gitignore
.env
.env.local
.env.production
Leer guía completa

Seguridad

Protección de datos

Las operaciones de consulta y emisión pueden involucrar información empresarial o datos personales. La aplicación que utilice este SDK es responsable de:

  • Gestionar adecuadamente las credenciales.
  • Implementar controles de acceso.
  • Proteger la información almacenada.
  • Evitar registrar información sensible innecesariamente.
  • Cumplir con la normativa que resulte aplicable.
  • Utilizar las credenciales únicamente para las finalidades autorizadas.
  • Implementar medidas adecuadas de seguridad.

El SDK no pretende sustituir las obligaciones legales, regulatorias o contractuales del sistema que lo utilice.

Referencia

Glosario

El servicio integra con conceptos tributarios y logísticos de Perú. Esta sección explica cada término que aparece en el SDK y en los payloads del proveedor.

TérminoSignificado
SUNATSuperintendencia Nacional de Aduanas y de Administración Tributaria: entidad del Estado peruano que administra impuestos y valida los comprobantes electrónicos.
RUCRegistro Único de Contribuyentes: número de 11 dígitos que identifica a una empresa o persona con negocio ante SUNAT.
DNIDocumento Nacional de Identidad: documento de identidad de personas naturales peruanas (8 dígitos).
CPEComprobante de Pago Electrónico: factura o boleta electrónica enviada a SUNAT para su validación antes de considerarse emitida.
Factura / BoletaTipos de comprobante. Códigos SUNAT: 01 = factura, 03 = boleta (campo voucherTypeCode).
Guía de Remisión (GRE)Documento electrónico que sustenta el traslado de bienes (campo documentTypeCode: '09').
Remitente público / privado / transportistaModalidades de guía de remisión según quién traslada los bienes. Se definen por los campos incluidos en el payload.
TicketCódigo que devuelve el proveedor al emitir una guía; permite consultar después el resultado de la validación (getRemittanceGuideTicketStatus).
CDRConstancia de Recepción: respuesta oficial de SUNAT con el resultado de la validación del comprobante. responseCode/sunatCode en "0" significa aceptado.
Hash CDR / CPEResumen criptográfico (huella) del XML del comprobante o de la constancia.
XML / UBLFormato estándar en el que se genera y firma el comprobante electrónico.
IGVImpuesto General a las Ventas: IVA peruano (18% habitual). Campos igv, igvPercentage, totalIgv.
ISCImpuesto Selectivo al Consumo: aplica a ciertos bienes (bebidas, combustibles, etc.). Campos isc, totalIsc.
ICBPERImpuesto a la Bolsa Plástica de un solo uso. En el proveedor aparece como IMPUESTO_BP/IMPORTE_BP y el flag FLG_ICBPER (mapeado a icbperFlag, icbperTaxAmount, icbperTotalAmount).
GravadoOperación afecta al IGV (totalTaxableAmount).
ExoneradoOperación no afecta al IGV por ley (totalExemptAmount).
InafectoOperación no sujeta al IGV por naturaleza (totalUntaxedAmount).
GratuitoEntregas gratuitas (totalFreeAmount).
DetracciónRetención de un porcentaje del pago a una cuenta del Banco de la Nación para ciertos bienes/servicios (campos detractionCode, detractionPercentage, detractionsTotal).
PercepciónCobro anticipado del IGV en la venta (campos perceptions*).
RetenciónRetención del IGV al proveedor (campos retentions*).
Contado / CréditoFormas de pago del CPE. En el proveedor: COD_FORMA_PAGO = 'Contado' o 'Credito' + cuotas Cuota001, Cuota002, ... (mapeado a paymentTerms).
Tipo de cambioPrecio de referencia del dólar (USD) publicado por SUNAT, con valores de compra (side: 'C') y venta (side: 'V').
UbigeoCódigo geográfico oficial (departamento / provincia / distrito) usado en direcciones.
Usuario SOL / Clave SOLCredenciales del portal de SUNAT con las que se firma y envía el comprobante (companySolUsername, companySolPassword).
Certificado digital / firmaCertificado con el que se firma el XML del comprobante (signaturePassword, certificatePassword).
Habido / condición de domicilioCondición del contribuyente frente a SUNAT (ubicable o no). Campos statusCode y presenceCode en el lookup de RUC.
Establecimientos anexosSucursales o locales adicionales declarados por un contribuyente además de su domicilio fiscal.
Tipo de proceso (processType)Modo de emisión según el proveedor: producción o beta ('1' / '2').
MTCMinisterio de Transportes y Comunicaciones: registros de vehículos y conductores usados en guías transportista (campos *MtcRegistrationId).
NIU / KGMUnidades de medida: NIU = unidades, KGM = kilogramos (campos unitOfMeasure, grossWeightUnit).
PEN / USDCódigos de moneda ISO: sol peruano y dólar estadounidense (campo currencyCode).

Referencia

Migración v1 → v2

Desde la versión 2.0.0 la API pública del SDK (métodos, clases e interfaces) está nombrada en inglés, y el SDK traduce internamente los payloads hacia el formato del proveedor (capa de mapping/). Los alias antiguos (SunatModule, consultarRuc, etc.) fueron eliminados.

v1 (anterior)v2 (actual)
SunatModuleSDKVisioner7Module
SunatServiceSDKVisioner7Service
SunatApiExceptionSDKVisioner7ApiException
consultarRuc()lookupTaxpayer()
consultarLocalesEstablecimientos()lookupEstablishments()
consultarDni()lookupPerson()
obtenerTipoCambio()getExchangeRate()
emitirGuiaRemision()issueRemittanceGuide()
consultarTicketGuiaRemision()getRemittanceGuideTicketStatus()
generarCpe()generateVoucher()
TipoConsultaLocalEstablishmentQueryType
SUNAT_* (variables de entorno)SDK_VISIONER7_*

Los payloads y respuestas también llegan tipados en inglés (por ejemplo response.taxpayer.businessName en vez de response.comprobante.desRazonSocial).

Proyecto

Estructura de carpetas

Compilar con npm run build genera los archivos JavaScript y las declaraciones TypeScript en dist/.

La carpeta mapping/ traduce entre la API pública del SDK (en inglés) y el formato que espera el proveedor (campos como txtTOTAL, NRO_DOCUMENTO_EMPRESA, etc.).

@angelitosystems/sdk-visioner7/ ├── src/ │ ├── interfaces/ │ │ ├── sdk-visioner7-config.interface.ts │ │ ├── lookups.interface.ts │ │ ├── remittance-guide.interface.ts │ │ ├── voucher.interface.ts │ │ └── index.ts │ ├── mapping/ │ │ ├── lookups.mapping.ts │ │ ├── remittance-guide.mapping.ts │ │ ├── voucher.mapping.ts │ │ ├── voucher-response.mapping.ts │ │ └── index.ts │ ├── exceptions/ │ │ └── sdk-visioner7-api.exception.ts │ ├── constants.ts │ ├── sdk-visioner7.module.ts │ ├── sdk-visioner7.service.ts │ └── index.ts ├── example/ │ ├── app.module.ts │ └── app.controller.ts ├── package.json ├── tsconfig.json ├── .gitignore └── README.md

La carpeta example/ contiene una integración de referencia completa, registrando el módulo con forRootAsync a partir de ConfigService.

Proyecto

Naturaleza del proyecto y licencia

Este proyecto es una librería de integración independiente. No constituye una API propia de SUNAT ni un producto oficial de Visioner7, y no implica afiliación, asociación, patrocinio o representación por parte de Visioner7. Se limita a ofrecer una interfaz de software para integrar una aplicación con un servicio externo al que el usuario o cliente tenga acceso autorizado.

Responsabilidad del usuario de la librería

  1. Contar con acceso legítimo al servicio externo.
  2. Mantener vigentes sus credenciales.
  3. Cumplir las condiciones de uso del servicio contratado.
  4. Utilizar las funcionalidades de acuerdo con las autorizaciones correspondientes.
  5. Proteger las credenciales de acceso.
  6. Cumplir las obligaciones tributarias, comerciales, de privacidad y seguridad que correspondan.
  7. Validar que los documentos generados cumplan con los requisitos aplicables a su operación.

Descargo de responsabilidad

El desarrollador de esta librería no garantiza la disponibilidad permanente, exactitud, continuidad, tiempos de respuesta o modificaciones futuras del servicio externo. Cambios en endpoints, autenticación, formatos de respuesta, límites o funcionalidades por parte del proveedor pueden requerir actualizaciones del SDK. Usar este SDK no sustituye la revisión de la documentación, condiciones contractuales o requisitos técnicos del servicio externo.

Licencia

La licencia debe definirse según la forma en que se distribuya la librería. Para uso privado en proyectos propios o de clientes, se recomienda mantener el repositorio privado y establecer por contrato las condiciones de uso, distribución y soporte.

Para conocer las condiciones, disponibilidad y características actuales del servicio externo, consulta directamente visioner7-api.com.