Saltar al contenido principal
Version: Guardian v0.1.0

Collect (Servidor a servidor)

v0.3.0+

Dos rutas de verificación​

El Guardian SDK ofrece dos formas de verificar dispositivos. Elige según tu arquitectura:

verify()collect()
Quién llama a SurtEl SDK (desde el dispositivo)Tu backend (servidor a servidor)
Requisito de JWTRequerido, fresco por llamadaOpcional (solo para la IP del dispositivo)
Llamadas de red desde el SDKSíSolo GET /geolocation/client-ip cuando se proporciona un JWT
Tu backend involucradoNoSí
RespuestaVerificationResult (permitido/denegado)CollectResult (payload cifrado)
Ideal paraIntegración simple, decisiones en el frontendDecisiones en el backend, lógica personalizada, requisitos de auditoría

Flujo de verify()​

App → fetch fresh JWT from your backend → SDK.verify(jwt) → Surt backend → risk decision → App

El SDK llama a Surt directamente y devuelve allowed: true/false. Tu aplicación actúa sobre la decisión inmediatamente. Se requiere un JWT fresco para cada llamada.

Flujo de collect()​

App → SDK.collect() → encrypted payload → App → Your backend → Surt /evaluate → Your backend → App

El SDK recopila datos del dispositivo y los cifra localmente. Sin argumentos, collect() realiza cero llamadas de red a Surt. Tu backend envía el payload al endpoint de evaluación de Surt, recibe la evaluación de riesgo completa y decide qué devolver a tu aplicación.

Cuándo usar collect()​

  • Tu backend necesita los datos de riesgo antes de responder al cliente
  • Quieres combinar el riesgo del dispositivo con tu propia lógica de negocio del lado del servidor
  • Necesitas control total sobre lo que el cliente ve
  • El cumplimiento requiere que todas las llamadas a terceros se originen desde tu infraestructura

Uso​

1. Recopilar en el dispositivo​

import { useGuardian } from '@surtai/guardian-rn';

function PaymentScreen() {
const { collect } = useGuardian();

const handlePayment = async () => {
// El JWT es opcional para collect(). Llama a collect() sin argumentos,
// o pasa collect(jwt) solo si quieres que la IP pública del dispositivo
// se resuelva dentro del payload.
const { payload } = await collect();

// Send payload to YOUR backend
const response = await fetch('https://your-api.com/verify-device', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
payload,
amount: 500,
currency: 'USD',
}),
});

const result = await response.json();
// Your backend already made the risk decision
};
}

Para collect(), pasa un JWT a collect(jwt) solo si quieres que la IP pública del dispositivo se resuelva dentro del payload; de lo contrario, llama a collect() sin argumentos. A diferencia de verify(), un JWT de collect() puede reutilizarse u omitirse, ya que collect() no requiere un JWT por llamada.

2. Llamar a Surt desde tu backend​

Tu backend recibe el payload cifrado de la aplicación y luego llama al endpoint de evaluación de Surt:

POST https://api.surt.com/geolocation/transactions/evaluate
Content-Type: application/json
Authorization: Bearer YOUR_SURT_API_KEY
{
"customer_id": "user_123",
"transaction_type": "withdrawal",
"transaction_name": "User Payment",
"payload": {
"type": "encrypted",
"data": "<payload from SDK>"
},
"config": {
"response": {
"address": { "type": "include" }
}
}
}

Campos de la solicitud​

CampoTipoRequeridoDescripción
customer_idstringSíTu identificador de usuario
transaction_typestringSílogin, sign_up, deposit o withdrawal
transaction_namestringNoEtiqueta legible para humanos
payload.typestringSíSiempre "encrypted"
payload.datastringSíEl payload cifrado de collect()
config.response.addressobjectNo{ "type": "include" } para obtener la dirección completa, omitido por defecto

Config​

El objeto config controla qué datos opcionales se incluyen en la respuesta.

{
"config": {
"response": {
"address": { "type": "include" }
}
}
}
CampoValoresPor defectoDescripción
config.response.address.type"include" o "omit""omit"Si se incluye la dirección completa de geocodificación inversa (calle, ciudad, estado, país, código postal) en la respuesta. Requiere datos GPS en el payload.

Cuando address se omite (por defecto), el campo address en la respuesta será null incluso si se recopilaron datos de ubicación. Establece en "include" si tu backend necesita la dirección física para cumplimiento, revisión de fraude o visualización.

Autenticación​

Usa tu clave de API de Surt en el encabezado Authorization como un token Bearer. Esta es una llamada servidor a servidor; la clave de API nunca toca el dispositivo.

3. Manejar la respuesta​

El endpoint de evaluación devuelve los mismos datos que verify(), pero con detalle completo. El campo address depende de tu config.

Con config.response.address.type: "include"​

{
"status_code": 200,
"message": "Transaction evaluated successfully",
"data": {
"transaction": {
"transaction_id": "1775514112-f2e3034b891e...",
"created_at": "2026-04-06T22:21:52Z",
"customer_id": "user_123",
"transaction_type": "withdrawal",
"transaction_name": "User Payment",
"status": {
"type": "completed",
"risk_level": "low",
"result": {
"status": "accepted",
"review": false
},
"address": {
"street": "123 Main St",
"city": "San Francisco",
"state": "California",
"country": "United States",
"postal_code": "94103",
"formatted_address": "123 Main St, San Francisco, CA 94103, USA"
},
"signals": [ ... ],
"triggered_scenarios": [ ... ]
},
"device": {
"device_id": "fingerprint_abc",
"manufacturer": "Apple",
"model": "iPhone 15",
"os_version": "18.0"
},
"metadata": {
"device_locations": [ ... ],
"ip_locations": [ ... ],
"device_ids": [ ... ]
},
"network_threat": {
"status": "not_analyzed"
},
"country": "United States",
"ip_address": "203.0.113.50"
}
}
}

Con config.response.address.type: "omit" (por defecto)​

La misma respuesta, pero address es null:

{
"status_code": 200,
"message": "Transaction evaluated successfully",
"data": {
"transaction": {
"transaction_id": "1775514112-f2e3034b891e...",
"created_at": "2026-04-06T22:21:52Z",
"customer_id": "user_123",
"transaction_type": "withdrawal",
"transaction_name": "User Payment",
"status": {
"type": "completed",
"risk_level": "low",
"result": {
"status": "accepted",
"review": false
},
"address": null,
"signals": [ ... ],
"triggered_scenarios": [ ... ]
},
"device": {
"device_id": "fingerprint_abc",
"manufacturer": "Apple",
"model": "iPhone 15",
"os_version": "18.0"
},
"metadata": {
"device_locations": [ ... ],
"ip_locations": [ ... ],
"device_ids": [ ... ]
},
"network_threat": {
"status": "not_analyzed"
},
"country": "United States",
"ip_address": "203.0.113.50"
}
}
}

Tu backend puede usar status.risk_level, status.result.status, signals, triggered_scenarios y address para tomar su propia decisión antes de responder al cliente.

Anulación de ubicación​

Igual que verify(), puedes anular la recopilación de ubicación por llamada:

// Recopilar con ubicación (y resolver la IP del dispositivo mediante el JWT)
const { payload } = await collect(jwt, { collectLocation: true });

// Recopilar sin ubicación y sin un JWT (sin llamada de red a Surt)
const { payload } = await collect(undefined, { collectLocation: false });

CollectResult​

interface CollectResult {
/** Base64-encoded encrypted payload. Pass as payload.data in the evaluate request. */
payload: string;
}

El payload está cifrado y solo puede ser descifrado por el backend de Surt. Contiene la huella digital del dispositivo, datos de integridad del dispositivo, señales de seguridad y opcionalmente ubicación.

Ejemplo de backend​

app.post('/verify-device', async (req, res) => {
const { payload, userId } = req.body;

const surtResponse = await fetch(
'https://api.surt.com/geolocation/transactions/evaluate',
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${process.env.SURT_API_KEY}`,
},
body: JSON.stringify({
customer_id: userId,
transaction_type: 'login',
payload: { type: 'encrypted', data: payload },
config: { response: { address: { type: 'include' } } },
}),
}
);

const { data } = await surtResponse.json();
const risk = data.transaction.status.risk_level;
const accepted = data.transaction.status.result.status === 'accepted';

res.json({ allowed: accepted, risk });
});

Diagnósticos del resultado​

El resultado de collect() incluye un objeto opcional diagnostics (location, networkIntel, warnings y, solo en Android a partir de v0.5.2, timings con milisegundos por fase) con lo que observó el SDK. Consulta Códigos de error para la referencia completa.