Inicio rápido
Esta guía te llevará desde cero hasta tener el SDK operativo con un escenario real de gestión de casos en Shori.
Elige tu plataforma
- ☕ Java
- 🔷 TypeScript / JavaScript
- 🌊 Axetflow / Node-RED
- 🐱 NestJS
- 🚀 Express
Añade la dependencia en tu pom.xml e inicializa el cliente:
<repositories>
<repository>
<id>gitlab-maven</id>
<url>https://gitlab.com/api/v4/projects/84253138/packages/maven</url>
</repository>
</repositories>
<dependency>
<groupId>com.nttdata.shori</groupId>
<artifactId>shori-api-client</artifactId>
<version>1.0.6</version>
</dependency>
ShoriClient client = ShoriClient.builder()
.environment(ShoriEnvironment.PROD)
.portalId("tu-portal-id")
.tenantId("tu-tenant-id")
.apiKey("tu-api-key")
.build();
// Crear un caso
CasoCreateResponse res = client.caso().create(
CasoCreateRequest.builder()
.casoTypeId("uuid-del-tipo")
.formId("uuid-del-formulario")
.submittedData(Map.of("campo", "valor"))
.build()
);
System.out.println("Caso creado: " + res.getCasoNumber());
Sigue leyendo para la guía completa paso a paso →
Instala el paquete e inicializa el cliente:
npm install shori-sdk-ts
import { ShoriClientBuilder, ShoriEnvironment } from "shori-sdk-ts";
const client = new ShoriClientBuilder()
.environment(ShoriEnvironment.PROD)
.portalId("tu-portal-id")
.tenantId("tu-tenant-id")
.apiKey("tu-api-key")
.build();
// Crear un caso
const res = await client.caso().create({
casoTypeId: "uuid-del-tipo",
formId: "uuid-del-formulario",
submittedData: { campo: "valor" },
});
console.log("Caso creado:", res.casoNumber);
Sigue leyendo para la guía completa paso a paso →
Instalación:
# Manage palette → Install → busca: axetflow-shori-nodes
# O por línea de comandos:
cd ~/.node-red
npm install axetflow-shori-nodes
Flujo básico en 3 pasos:
- Arrastra shori-config → configura
portalId,tenantId,apiKeyy el ambiente - Conecta el nodo de acción que necesitas (crear caso, buscar, comentar, etc.)
- Los datos se pasan por
msg.payloado se configuran directamente en el formulario del nodo
[inject] → [shori-config] → [shori-create-case] → [shori-next-state] → [debug]
+33 nodos disponibles cubriendo todos los módulos del SDK — sin escribir una sola línea de código.
npm install shori-sdk-ts
// shori.module.ts
@Module({
providers: [
{
provide: "SHORI_CLIENT",
useFactory: () =>
new ShoriClientBuilder()
.environment(ShoriEnvironment.PROD)
.portalId(process.env.SHORI_PORTAL_ID)
.tenantId(process.env.SHORI_TENANT_ID)
.apiKey(process.env.SHORI_API_KEY)
.build(),
},
],
exports: ["SHORI_CLIENT"],
})
export class ShoriModule {}
npm install shori-sdk-ts
import express from "express";
import { ShoriClientBuilder, ShoriEnvironment } from "shori-sdk-ts";
const app = express();
const client = new ShoriClientBuilder()
.environment(ShoriEnvironment.PROD)
.portalId(process.env.SHORI_PORTAL_ID!)
.tenantId(process.env.SHORI_TENANT_ID!)
.apiKey(process.env.SHORI_API_KEY!)
.build();
app.get("/cases/:id", async (req, res) => {
const caso = await client.caso().findById(req.params.id);
res.json(caso);
});
Prerrequisitos
- ☕ Java
- 🔷 TypeScript / JavaScript
Antes de comenzar, asegúrate de tener:
- ✅ Java 17 o superior instalado
- ✅ Maven 3.6+ configurado
- ✅ Credenciales de acceso a Shori:
portalId,tenantIdyapiKey - ✅ Los UUIDs de tu
casoTypeIdyformId(proporcionados por el equipo de Shori)
Antes de comenzar, asegúrate de tener:
- ✅ Node.js 18+ instalado (recomendado: Node.js 22 LTS)
- ✅ npm 9+ o pnpm configurado
- ✅ Credenciales de acceso a Shori:
portalId,tenantIdyapiKey - ✅ Los UUIDs de tu
casoTypeIdyformId(proporcionados por el equipo de Shori)
Contacta al equipo de Shori de NTT DATA para obtener las credenciales de acceso a los ambientes UAT (pruebas) y PROD (producción).
Paso 1 — Agregar la dependencia
- ☕ Java
- 🔷 TypeScript / JavaScript
Añade el repositorio y la dependencia en tu pom.xml:
<!-- 1. Repositorio del SDK (GitLab Package Registry — público) -->
<repositories>
<repository>
<id>gitlab-maven</id>
<url>https://gitlab.com/api/v4/projects/84253138/packages/maven</url>
</repository>
</repositories>
<!-- 2. Dependencia -->
<dependency>
<groupId>com.nttdata.shori</groupId>
<artifactId>shori-api-client</artifactId>
<version>1.0.6</version>
</dependency>
El Package Registry es público. No necesitas configurar credenciales para descargar el artefacto.
Instala el paquete desde npm:
npm install shori-sdk-ts
O con pnpm:
pnpm add shori-sdk-ts
El paquete incluye las definiciones de tipos TypeScript — no necesitas instalar @types/shori-sdk-ts.
shori-sdk-ts es compatible con Node.js 18+, browser moderno, Next.js, NestJS y Express. Usa únicamente Web APIs estándar (fetch, FormData, Blob) sin dependencias de Node.js en el bundle.
Paso 2 — Inicializar el cliente
- ☕ Java
- 🔷 TypeScript / JavaScript
Crea una instancia de ShoriClient con tus credenciales:
import com.nttdata.shori.client.ShoriClient;
import com.nttdata.shori.config.ShoriEnvironment;
ShoriClient client = ShoriClient.builder()
.environment(ShoriEnvironment.UAT) // DEV | UAT | PROD
.portalId("tu-portal-id")
.tenantId("tu-tenant-id")
.apiKey("tu-api-key")
.timeoutSeconds(30) // opcional, default: 30s
.build();
Crea el cliente una sola vez y reutilízalo. Es thread-safe y mantiene internamente el pool de conexiones HTTP y el token de autenticación.
maxConnections)Por defecto el SDK mantiene hasta 5 conexiones simultáneas por módulo (caso, repo, identify). Para automatizaciones con alta concurrencia, aumenta este valor:
ShoriClient client = ShoriClient.builder()
...
.maxConnections(10) // 10 por módulo = 30 conexiones totales
.build();
Si usas Spring Boot, declara el cliente como un @Bean en tu clase de configuración. Spring gestionará automáticamente su ciclo de vida:
@Configuration
public class ShoriConfiguration {
@Value("${shori.portal-id}")
private String portalId;
@Value("${shori.tenant-id}")
private String tenantId;
@Value("${shori.api-key}")
private String apiKey;
@Bean(destroyMethod = "close")
public ShoriClient shoriClient() {
return ShoriClient.builder()
.environment(ShoriEnvironment.PROD)
.portalId(portalId)
.tenantId(tenantId)
.apiKey(apiKey)
.build();
}
}
Luego inyéctalo donde lo necesites:
@Service
public class MiServicio {
private final ShoriClient shoriClient;
public MiServicio(ShoriClient shoriClient) {
this.shoriClient = shoriClient;
}
}
Para la configuración completa en application.properties / application.yml consulta Instalación y Configuración.
Si usas el SDK en una aplicación de escritorio con múltiples ventanas o automatizaciones,
usa ShoriClientRegistry para gestionar los clientes de forma centralizada.
Ver la guía completa en Instalación y Configuración → Integración con JavaFX.
Crea una instancia de ShoriClient con tus credenciales:
import { ShoriClientBuilder, ShoriEnvironment } from "shori-sdk-ts";
const client = new ShoriClientBuilder()
.environment(ShoriEnvironment.UAT) // DEV | UAT | PROD
.portalId("tu-portal-id")
.tenantId("tu-tenant-id")
.apiKey("tu-api-key")
.timeoutMs(30_000) // opcional, default: 30000ms
.build();
Crea el cliente una sola vez y reutilízalo. Gestiona internamente el token de autenticación con renovación automática en caso de expiración.
En Node.js, carga las credenciales desde variables de entorno:
import { ShoriClientBuilder, ShoriEnvironment } from "shori-sdk-ts";
const client = new ShoriClientBuilder()
.environment(
ShoriEnvironment[
process.env.SHORI_ENVIRONMENT as keyof typeof ShoriEnvironment
] ?? ShoriEnvironment.UAT,
)
.portalId(process.env.SHORI_PORTAL_ID!)
.tenantId(process.env.SHORI_TENANT_ID!)
.apiKey(process.env.SHORI_API_KEY!)
.build();
Archivo .env:
SHORI_ENVIRONMENT=UAT
SHORI_PORTAL_ID=0306444E-38B1-403D-8753-EC9C2BC43215
SHORI_TENANT_ID=80ff134a-cae2-4a4a-92b9-a109bdee1183
SHORI_API_KEY=tu-api-key-secreta
Para la configuración completa consulta Instalación y Configuración.
Paso 3 — Escenario completo: gestión de solicitudes de servicio
El siguiente ejemplo muestra un flujo BPO completo: obtener los estados del proceso, crear un caso, buscarlo y avanzar su estado.
3.1 Obtener el tipo de caso y sus estados
- ☕ Java
- 🔷 TypeScript / JavaScript
import com.nttdata.shori.modules.caso.dto.response.ProductResponse;
import com.nttdata.shori.util.ShoriUtils;
import java.util.List;
// Obtener la definición del tipo de caso (incluye estados disponibles)
ProductResponse tipoCaso = client.caso().casoType()
.findById("D0480B5C-8730-4CD9-858A-151AF7C0D852");
System.out.println("Tipo de caso: " + tipoCaso.getName());
// Obtener los IDs de los estados "abiertos" (para filtrar búsquedas)
List<String> estadosAbiertos = ShoriUtils.openStatesIds(tipoCaso);
System.out.println("Estados abiertos: " + estadosAbiertos.size());
// Obtener la definición del tipo de caso (incluye estados disponibles)
const tipoCaso = await client
.caso()
.casoType()
.findById("D0480B5C-8730-4CD9-858A-151AF7C0D852");
console.log("Tipo de caso:", tipoCaso.name);
// Obtener los IDs de los estados "abiertos" (para filtrar búsquedas)
import { ShoriUtils } from "shori-sdk-ts";
const estadosAbiertos = ShoriUtils.openStatesIds(tipoCaso);
console.log("Estados abiertos:", estadosAbiertos.length);
3.2 Crear un nuevo caso
- ☕ Java
- 🔷 TypeScript / JavaScript
import com.nttdata.shori.modules.caso.dto.request.CasoCreateRequest;
import com.nttdata.shori.modules.caso.dto.response.CasoCreateResponse;
import java.util.Map;
CasoCreateRequest solicitud = CasoCreateRequest.builder()
.casoTypeId("D0480B5C-8730-4CD9-858A-151AF7C0D852")
.formId("F1234567-ABCD-1234-EFGH-123456789012")
.priority("B2345678-ABCD-1234-EFGH-123456789012")
.submittedData(Map.of(
"nombreCliente", "Ana García López",
"tipoDocumento", "DNI",
"numeroDocumento","12345678",
"telefono", "+51987654321",
"tipoServicio", "PORTABILIDAD",
"observaciones", "Cliente solicita portabilidad de número fijo"
))
.build();
CasoCreateResponse resultado = client.caso().create(solicitud);
String casoId = resultado.getCaso();
System.out.println("Caso creado con ID: " + casoId);
System.out.println("Número de caso: " + resultado.getCasoNumber());
const resultado = await client.caso().create({
casoTypeId: "D0480B5C-8730-4CD9-858A-151AF7C0D852",
formId: "F1234567-ABCD-1234-EFGH-123456789012",
priority: "B2345678-ABCD-1234-EFGH-123456789012",
submittedData: {
nombreCliente: "Ana García López",
tipoDocumento: "DNI",
numeroDocumento: "12345678",
telefono: "+51987654321",
tipoServicio: "PORTABILIDAD",
observaciones: "Cliente solicita portabilidad de número fijo",
},
});
const casoId = resultado.casoId;
console.log("Caso creado con ID:", casoId);
console.log("Número de caso:", resultado.casoNumber);
3.3 Consultar el caso creado
- ☕ Java
- 🔷 TypeScript / JavaScript
import com.nttdata.shori.modules.caso.dto.response.CasoResponse;
CasoResponse caso = client.caso().findById(casoId);
System.out.println("Estado actual: " + caso.getWorkingSubStateName());
System.out.println("Creado el: " + caso.getCreatedAt());
const caso = await client.caso().findById(casoId);
console.log("Estado actual:", caso.workingSubStateName);
console.log("Creado el:", caso.createdAt);
3.4 Buscar casos abiertos del proceso
- ☕ Java
- 🔷 TypeScript / JavaScript
import com.nttdata.shori.modules.caso.filter.CaseFilter;
import com.nttdata.shori.modules.caso.filter.FilterOperator;
import com.nttdata.shori.modules.caso.dto.response.CasoSearchResponse;
List<CasoSearchResponse> casosAbiertos = client.caso().searchAll(
CaseFilter.builder()
.casoTypeId(FilterOperator.EQ, "D0480B5C-8730-4CD9-858A-151AF7C0D852")
.workingSubStateId(FilterOperator.IN, estadosAbiertos.toArray(new String[0]))
.pageSize(100)
.build()
);
System.out.println("Total casos abiertos: " + casosAbiertos.size());
casosAbiertos.forEach(c ->
System.out.printf(" [%s] %s - %s%n",
c.getCasoNumber(), c.getCasoId(), c.getWorkingSubStateName())
);
import { CaseFilter, FilterOperator } from "shori-sdk-ts";
const casosAbiertos = await client.caso().searchAll(
CaseFilter.builder()
.casoTypeId(FilterOperator.EQ, "D0480B5C-8730-4CD9-858A-151AF7C0D852")
.workingSubStateId(FilterOperator.IN, ...estadosAbiertos)
.pageSize(100)
.build(),
);
console.log("Total casos abiertos:", casosAbiertos.length);
casosAbiertos.forEach((c) =>
console.log(` [${c.casoNumber}] ${c.casoId} - ${c.workingSubStateName}`),
);
3.5 Avanzar el estado del caso
- ☕ Java
- 🔷 TypeScript / JavaScript
import com.nttdata.shori.modules.caso.dto.request.NextStateRequest;
// Obtener el ID del siguiente estado desde la definición del tipo de caso
String siguienteEstadoId = tipoCaso.getStates().stream()
.filter(s -> s.getName().equals("EN PROCESO"))
.map(s -> s.getId())
.findFirst()
.orElseThrow();
NextStateRequest cambioEstado = NextStateRequest.builder()
.casoId(casoId)
.stateId(siguienteEstadoId)
.build();
boolean exito = client.caso().state().next(cambioEstado);
System.out.println("Estado actualizado: " + exito);
// Obtener el ID del siguiente estado desde la definición del tipo de caso
const siguienteEstadoId = tipoCaso.states?.find(
(s) => s.name === "EN PROCESO",
)?.id;
if (!siguienteEstadoId) throw new Error("Estado 'EN PROCESO' no encontrado");
const exito = await client.caso().state().next({
casoId,
stateId: siguienteEstadoId,
});
console.log("Estado actualizado:", exito);
3.6 Agregar un comentario
- ☕ Java
- 🔷 TypeScript / JavaScript
import com.nttdata.shori.modules.caso.dto.request.AddCommentRequest;
AddCommentRequest comentario = AddCommentRequest.builder()
.casoId(casoId)
.comment("Caso asignado al equipo de portabilidad. Tiempo estimado: 48h.")
.build();
client.caso().comment().add(comentario);
System.out.println("Comentario registrado correctamente.");
import { AddCommentRequest } from "shori-sdk-ts";
await client
.caso()
.comment()
.add(
AddCommentRequest.builder()
.casoId(casoId)
.comment("Caso asignado al equipo de portabilidad. Tiempo estimado: 48h.")
.build(),
);
console.log("Comentario registrado correctamente.");
3.7 Adjuntar un documento
- ☕ Java
- 🔷 TypeScript / JavaScript
import com.nttdata.shori.modules.repo.dto.request.UploadDocumentRequest;
import java.io.File;
File contrato = new File("/ruta/al/contrato-firmado.pdf");
String documentId = client.repo().document().upload(
UploadDocumentRequest.builder()
.file(contrato)
.casoId(casoId)
.casoTypeId("D0480B5C-8730-4CD9-858A-151AF7C0D852")
.isValid(true)
.isDeleted(false)
.encrypted(false)
.build()
);
System.out.println("Documento subido con ID: " + documentId);
// Desde un <input type="file"> en el browser
const file = fileInput.files[0];
// O desde el sistema de archivos en Node.js
import { readFileSync } from "fs";
const buffer = readFileSync("/ruta/al/contrato-firmado.pdf");
const file = new File([buffer], "contrato-firmado.pdf", {
type: "application/pdf",
});
const documentId = await client.repo().document().upload({
file,
casoId,
casoTypeId: "D0480B5C-8730-4CD9-858A-151AF7C0D852",
isValid: true,
isDeleted: false,
encrypted: false,
});
console.log("Documento subido con ID:", documentId);
Paso 4 — Cerrar el cliente
- ☕ Java
- 🔷 TypeScript / JavaScript
Cuando tu aplicación termine de usar el SDK, libera los recursos del pool de conexiones HTTP.
Opción A — try-with-resources (scripts, tests, jobs de corta duración):
try (ShoriClient client = ShoriClient.builder()
.environment(ShoriEnvironment.UAT)
.portalId("tu-portal-id")
.tenantId("tu-tenant-id")
.apiKey("tu-api-key")
.build()) {
List<CasoSearchResponse> casos = client.caso().searchAll(filter);
// ...
}
Opción B — Manual (cuando no usas try-with-resources):
client.close();
En Spring Boot, declara el cliente como @Bean con destroyMethod = "close". Spring llama close() automáticamente al apagar el servidor:
@Bean(destroyMethod = "close")
public ShoriClient shoriClient() {
return ShoriClient.builder()
.environment(ShoriEnvironment.PROD)
.portalId(portalId)
.tenantId(tenantId)
.apiKey(apiKey)
.build();
}
El cliente TypeScript no requiere cerrado explícito. Usa fetch nativo del runtime — las conexiones HTTP son gestionadas automáticamente por el motor JS (Node.js o el browser).
A diferencia del SDK Java que gestiona un pool de conexiones HTTP, el SDK TypeScript delega la gestión de conexiones al runtime. No hay recursos que liberar al terminar.
Manejo de errores
- ☕ Java
- 🔷 TypeScript / JavaScript
El SDK lanza excepciones específicas según el tipo de error:
import com.nttdata.shori.exception.*;
try {
CasoResponse caso = client.caso().findById("uuid-inexistente");
} catch (ResourceNotFoundException e) {
// HTTP 404 — El recurso no existe
System.err.println("Caso no encontrado: " + e.getMessage());
} catch (AuthenticationException e) {
// Error de autenticación — revisa tu apiKey
System.err.println("Error de autenticación: " + e.getMessage());
} catch (ApiException e) {
// HTTP 400, 500, etc — Error del API
System.err.printf("Error HTTP %d: %s%n", e.getStatusCode(), e.getMessage());
} catch (ValidationException e) {
// Configuración inválida del SDK
System.err.println("Error de configuración: " + e.getMessage());
}
El SDK lanza excepciones específicas según el tipo de error:
import {
ApiException,
AuthenticationException,
ResourceNotFoundException,
} from "shori-sdk-ts";
try {
const caso = await client.caso().findById("uuid-inexistente");
} catch (e) {
if (e instanceof ResourceNotFoundException) {
// HTTP 404 — El recurso no existe
console.error("Caso no encontrado:", e.message);
} else if (e instanceof AuthenticationException) {
// Error de autenticación — revisa tu apiKey
console.error("Error de autenticación:", e.message);
} else if (e instanceof ApiException) {
// HTTP 400, 500, etc — Error del API
console.error(`Error HTTP ${e.statusCode}:`, e.message);
} else {
throw e; // Re-lanzar errores inesperados
}
}
Si una llamada tarda más de timeoutMs, el SDK lanza ApiException con código 408:
} catch (e) {
if (e instanceof ApiException && e.statusCode === 408) {
console.error("Timeout — incrementa timeoutMs en ShoriClientBuilder");
}
}
Próximos pasos
- 📖 Instalación y configuración avanzada — SSL, timeouts, Spring Boot, ambientes
- 📦 Módulo de Casos — CRUD, búsqueda paginada, attachments
- 📁 Archivos adjuntos — Subir, descargar y eliminar documentos
- 🔄 Estados del caso — Avanzar el flujo de trabajo
- 💬 Comentarios — Registrar notas en un caso
- 🏷️ Producto (casoType) — Obtener definición y estados disponibles
- 🏢 Servicios (primaryLevel) — Buscar, crear, actualizar, activar/desactivar servicios y sus working substates
- ⚙️ Procesos (secondaryLevel) — Buscar, crear, actualizar, activar/desactivar procesos
- 👤 Usuarios (user) — Asignar y desasignar usuarios responsables o participantes en casos
- 🗃️ Tipología de archivos (fileTypology) — Tipologías y categorías de archivos
- 🗂️ Repositorio de documentos — Gestión centralizada de archivos
- 📤 Subir y eliminar documentos — Sub-módulo de escritura del repositorio
- 📥 Descargar documentos — Descarga por ID, versión o exportación
- 👤 Identificación de usuarios — Buscar usuarios en Shori
- 🗒️ Gestión de Formularios — Creación, actualización y búsqueda de formularios
- ⚠️ Manejo de errores — Jerarquía de excepciones