Referencia de la API de FPP
Este documento describe cómo integrarse con la API de prevención del fraude de Guardline. Cubre la autenticación, el envío de transacciones para análisis, la interpretación de las decisiones, la recepción de notificaciones por webhook y el manejo del ciclo de vida completo de la decisión.
El modelo de integración sigue una separación clara de responsabilidades: Guardline decide y señaliza, el integrador ejecuta. Guardline nunca accede directamente al core bancario. Todas las acciones (retenciones cautelares, bloqueos de cuenta) se comunican mediante respuesta síncrona o webhook, y el integrador es responsable de ejecutarlas.
Autenticación
Sección titulada «Autenticación»Todas las solicitudes a la API deben incluir una clave de API válida en el encabezado X-API-Key.
X-API-Key: gl_live_your_api_key_hereLas claves de API son provisionadas por el equipo de Guardline y tienen alcance por entorno (sandbox, producción). Mantenga su clave de API confidencial. Si se ve comprometida, contacte a Guardline de inmediato para rotarla.
Además del alcance por entorno, las claves de API llevan uno o más alcances de permiso que controlan el acceso a grupos específicos de endpoints. Cada sección de endpoint de este documento indica el alcance que requiere, cuando corresponde. Contacte a Guardline para habilitar alcances adicionales en su clave.
Todos los endpoints requieren HTTPS. Las solicitudes HTTP serán rechazadas.
Análisis de transacciones
Sección titulada «Análisis de transacciones»Envíe una transacción para el análisis de fraude en tiempo real. Este es el endpoint principal de integración.
Endpoint
Sección titulada «Endpoint»POST /api/v2/decisions/analyzeSolicitud
Sección titulada «Solicitud»Content-Type: application/json
Campos obligatorios
Sección titulada «Campos obligatorios»Estos cinco campos son obligatorios en toda solicitud de análisis. Tenga en cuenta que no se requiere ningún registro previo del cliente. Guardline intentará enriquecer el contexto buscando los datos del cliente mediante el accountId, pero si no se encuentra ningún cliente, el análisis continúa normalmente con los datos provistos en la solicitud.
| Campo | Tipo | Descripción |
|---|---|---|
transactionId | string | Identificador único de la transacción en su sistema. Se usa para la idempotencia (las solicitudes duplicadas devuelven la decisión original). Recomendamos un patrón como TX-YYYYMMDD-NNNNNNNN. |
accountId | string | Identificador de la cuenta en su sistema. Se usa para buscar los datos del cliente (si fue registrado previamente) y para correlacionar transacciones en el análisis de velocidad y comportamiento. |
transactionType | string | Código del tipo de transacción. Crítico para el enrutamiento del flujo de trabajo: el motor de fraude usa este campo para determinar qué flujo de trabajo ejecutar. Para transacciones PIX, use PIX. Los demás tipos admitidos dependen de su configuración. |
transactionDate | string | Marca de tiempo ISO 8601 con zona horaria (por ejemplo, 2026-03-08T14:30:00-03:00). Se usa para el análisis temporal y el cálculo del SLA. |
totalAmount | string | Importe de la transacción como cadena decimal (por ejemplo, "15000.00"). Use el punto como separador decimal, sin separador de miles. |
Campos opcionales
Sección titulada «Campos opcionales»Estos campos son opcionales. Cuanto más contexto se proporcione, más preciso será el análisis de fraude. El integrador decide qué bloques incluir según los datos disponibles.
| Campo | Tipo | Descripción |
|---|---|---|
accountHolderId | string | Muy recomendado. CPF o CNPJ del titular de la cuenta (por ejemplo, 12345678900). La resolución de identidad se basa en la cantidad de dígitos una vez quitada la puntuación: 11 dígitos se tratan como CPF, 14 como CNPJ, y cualquier otra longitud se ignora a efectos de resolución. Habilita la resolución de identidad del cliente, las baselines de comportamiento, el análisis de velocidad y el perfilado de riesgo. Sin este campo, cada transacción se evalúa de forma aislada, sin historial del cliente. En una transacción entrante este es el documento del receptor, no el del pagador (consulte PIX In). |
currency | string | Código de moneda ISO 4217 (predeterminado: BRL) |
channel | string | Canal de origen (MOBILE, WEB, API) |
country | string | Código de país ISO 3166-1 alfa-2 |
metadata | object | Metadatos de la transacción (dirección, estado) |
customer | object | Datos del perfil del cliente |
counterPart | object | Información de la contraparte (beneficiario) |
device | object | Huella digital y señales del device |
location | object | Geolocalización e inteligencia de IP |
instantPayment | object | Datos específicos de PIX, incluido DICT (ver abajo) |
riskSignals | object | Puntajes y señales de riesgo preexistentes |
compliance | object | Indicadores de cumplimiento |
Los bloques adicionales (location, riskSignals, compliance) siguen el mismo principio: envíe lo que esté disponible y omita lo que no. La estructura de campos de estos bloques se definirá de forma colaborativa durante la configuración de la integración, según los datos que el integrador pueda proporcionar.
Flexibilidad del payload de entrada
Sección titulada «Flexibilidad del payload de entrada»El payload de la solicitud es flexible por diseño. Más allá de los cinco campos obligatorios (transactionId, accountId, transactionType, transactionDate, totalAmount), el integrador controla qué bloques opcionales incluir y qué campos completar dentro de cada bloque.
No se requiere registro previo: no necesita crear clientes, cuentas ni ninguna otra entidad antes de enviar transacciones. Guardline hará lo siguiente:
- Enriquecer automáticamente: si en la base de datos de Guardline existe un cliente con el
accountIdindicado (por registros o sincronizaciones previas), se usarán los datos de su perfil para mejorar el análisis. - Resolver por documento: si ningún cliente coincide con el
accountIdperoaccountHolderIdcontiene un CPF o CNPJ válido, Guardline buscará al cliente por documento. Si lo encuentra, se usa su perfil para el análisis. Si no lo encuentra, Guardline inscribe automáticamente al cliente para que las transacciones futuras acumulen historial y líneas base de comportamiento. - Continuar sin datos del cliente: si no se encuentra ningún cliente por ninguno de los dos métodos, el análisis se ejecuta con los datos provistos en la solicitud. Las reglas que dependen de atributos del cliente simplemente no coincidirán.
- Usar los datos de la solicitud: si incluye el bloque
customeren la solicitud, esos datos tienen prioridad y se usan directamente.
La estructura de cada bloque opcional (customer, counterPart, device, location, instantPayment, riskSignals, compliance) la define Guardline, pero el integrador decide qué bloques son relevantes para su caso de uso y qué campos puede proporcionar. Las reglas de fraude se configuran para funcionar con los datos disponibles. Los campos que no se envían simplemente no se evalúan.
El ejemplo siguiente es una referencia que muestra un escenario realista de PIX Out. El payload real debe adaptarse a los datos disponibles en los sistemas del integrador.
Ejemplo de solicitud (PIX Out)
Sección titulada «Ejemplo de solicitud (PIX Out)»{ "transactionId": "TX-20260308-00001234", "accountId": "ACC-00086", "accountHolderId": "12345678900", "transactionType": "PIX", "transactionDate": "2026-03-08T14:30:00-03:00", "totalAmount": "15000.00", "currency": "BRL", "channel": "MOBILE", "country": "BR", "metadata": { "direction": "OUT", "status": "pending", "originSystem": "IPAY" }, "customer": { "age": 42, "kycStatus": "approved", "kycLevel": "complete", "riskScore": 15.0, "riskLevel": "low", "isPEP": false, "country": "BR", "accountAgeDays": 730, "accountStatus": "active", "isNewCustomer": false }, "counterPart": { "name": "Maria Santos", "taxIdentifier": { "taxId": "987.654.321-00", "country": "BR" }, "isNewCounterpart": true, "transactionsCount": 0, "isSameNetwork": false }, "device": { "id": "DEV-9f8e7d6c", "type": "mobile", "os": "android", "isNewDevice": false, "isTrustedDevice": true, "ipAddress": "189.44.120.33" }, "instantPayment": { "keyType": "cpf", "keyValue": "987.654.321-00", "endToEndId": "E60701190202603081430abcd1234ef", "initiationMethod": "DICT", "payer": { "ispb": "60701190", "ispbName": "Itaú Unibanco S.A.", "document": "123.456.789-00", "branch": "0001", "account": "12345-6", "name": "João Oliveira" }, "receiver": { "ispb": "00000000", "ispbName": "Banco do Brasil S.A.", "document": "987.654.321-00", "branch": "3456", "account": "78901-2", "name": "Maria Santos" }, "dict": { "keyCreationDate": "2024-06-15T00:00:00Z", "keyOwnershipDate": "2024-06-15T00:00:00Z", "accountType": "CACC", "accountOpeningDate": "2023-01-10T00:00:00Z", "pspName": "Banco do Brasil S.A.", "pspIspb": "00000000", "fraudMarkersCount": 0, "infractionCount": 0, "isFlagged": false, "claimsCount": 0, "portabilityCount": 0, "correlationId": "A20260308143052899607011905AD7C8", "registeredAccounts": "1", "naturalPersonAntifraudPercentage": 0, "legalPersonAntifraudPercentage": 0, "spi": { "d90": "0", "m12": "0", "m60": "0" }, "reports": { "openReports": "0", "distinctReports": "0", "rejectedD90": "0", "rejectedM12": "0", "rejectedM60": "0" }, "frauds": [] } }}Idempotencia
Sección titulada «Idempotencia»Si el mismo transactionId se envía más de una vez, Guardline devuelve la decisión original sin volver a procesarla. La respuesta incluye "idempotent_replay": true para indicarlo.
Esto permite reintentos seguros ante un tiempo de espera de red, sin riesgo de procesamiento duplicado.
Comprender la respuesta
Sección titulada «Comprender la respuesta»Los tres escenarios (ALLOW, REVIEW, BLOCK) devuelven la misma estructura de respuesta. Este es el formato de payload unificado que se usa en toda la plataforma, tanto en las respuestas síncronas como en los webhooks.
Envoltorio de la respuesta
Sección titulada «Envoltorio de la respuesta»Las respuestas de la API se envuelven en un envoltorio estándar:
{ "error": false, "data": { ... }}El campo data contiene el payload de decisión descrito a continuación. Las respuestas de error usan "error": true (ver Manejo de errores).
Estructura del payload de decisión
Sección titulada «Estructura del payload de decisión»| Campo | Tipo | Siempre presente | Descripción |
|---|---|---|---|
id | UUID | sí | Identificador único de la decisión |
transaction_id | UUID | sí | Identificador interno de la transacción |
workflow_id | UUID | sí | Flujo de trabajo que procesó la transacción |
workflow_name | string | sí | Nombre del flujo de trabajo |
workflow_version | integer | sí | Versión del flujo de trabajo |
assessment | string | sí | Resultado de la decisión: ALLOW, REVIEW, BLOCK o ESCALATE. Las respuestas síncronas solo llevan ALLOW, REVIEW o BLOCK (el motor no produce ESCALATE). ESCALATE aparece exclusivamente en el evento de webhook en que un analista escala un caso en REVIEW (ver Cuándo se envían los webhooks). |
score | number | sí | Puntaje de riesgo final (0-100) |
thresholds | object | sí | Umbrales aplicados (revisión y bloqueo) |
resolution_source | string | sí | Quién tomó la decisión (ver abajo) |
reason_code | string | no | Código de motivo estructurado de la decisión (ver abajo) |
reason_description | string | no | Descripción legible del motivo |
actions | array | no | Acciones a ejecutar (ver abajo) |
review_info | object | no | Presente solo cuando assessment es REVIEW |
execution_time_ms | integer | sí | Tiempo de procesamiento del motor en milisegundos |
analysis_time_ms | integer | sí | Tiempo total de análisis, incluido el enriquecimiento |
created_at | datetime | sí | Marca de tiempo ISO 8601 |
idempotent_replay | boolean | no | true si esta es una respuesta reproducida |
sources_loaded | object | no | Fuentes de datos cargadas con éxito |
source_errors | object | no | Fuentes de datos que no se pudieron cargar |
explanation | object | sí | Desglose del puntaje por etapa |
Origen de la resolución
Sección titulada «Origen de la resolución»| Valor | Significado |
|---|---|
ENGINE | Decisión automática del motor de fraude (respuesta síncrona y, opcionalmente, un webhook cuando el flujo de trabajo vincula send_webhook al tipo de decisión resuelto) |
ANALYST | Decisión manual de un analista en la mesa de operaciones (webhook) |
SLA_TIMEOUT | Resolución automática de respaldo por vencimiento del SLA (webhook) |
Código de motivo
Sección titulada «Código de motivo»Los campos reason_code y reason_description aportan contexto sobre por qué se tomó la decisión. Esto es crítico para los reportes regulatorios (R6, MED) y para determinar cómo ejecutar las acciones señalizadas.
En las respuestas síncronas (resolution_source: "ENGINE"), el código de motivo refleja la evaluación automatizada del motor. Esa misma evaluación del motor también puede entregarse como webhook cuando el flujo de trabajo vincula send_webhook al tipo de decisión resuelto; en ese caso, el cuerpo del webhook lleva el mismo código de motivo que la respuesta síncrona. En las resoluciones por webhook (resolution_source: "ANALYST" o "SLA_TIMEOUT"), refleja el criterio del analista o la política de tiempo de espera.
| Origen | Ejemplo de reason_code | Ejemplo de reason_description |
|---|---|---|
ENGINE | HIGH_RISK_SCORE | Transacción bloqueada por puntaje de riesgo alto |
ENGINE | LOW_RISK | Transacción aprobada con riesgo bajo |
ANALYST | CONFIRMED_FRAUD | El analista confirmó actividad fraudulenta |
ANALYST | CUSTOMER_CONFIRMED | El cliente confirmó que la transacción es legítima |
ANALYST | SUSPICIOUS_UNCONFIRMED | Actividad sospechosa, evidencia insuficiente para confirmar el fraude |
ANALYST | FALSE_POSITIVE | El análisis determinó que la alerta era un falso positivo |
SLA_TIMEOUT | SLA_TIMEOUT_AUTO_APPROVED | Aprobada automáticamente por vencimiento del SLA |
El conjunto de códigos de motivo no es fijo. Pueden introducirse códigos nuevos a medida que evolucionen las necesidades operativas. El integrador debe tratar reason_code como una cadena de formato libre y manejar con tolerancia los valores desconocidos. El campo reason_description siempre ofrece una explicación legible, sea cual sea el código.
Ambos campos son null cuando no aplican (por ejemplo, en la respuesta síncrona inicial de REVIEW, donde aún no se conoce el motivo final).
Acciones
Sección titulada «Acciones»Las acciones representan efectos secundarios que el integrador debe ejecutar. Cada acción tiene un type y parameters opcionales.
| Tipo de acción | Descripción | Parámetros |
|---|---|---|
CAUTIONARY_HOLD | Congelar los fondos acreditados por hasta 72 horas (Resolución BCB 142/2021). Se debe notificar al titular de la cuenta. | duration_hours (integer) |
ACCOUNT_BLOCK | Suspensión preventiva de la cuenta. | ninguno |
BLOCK_BENEFICIARY | Bloquear a la contraparte (beneficiario) para transacciones futuras. | ninguno |
BLOCK_DEVICE | Bloquear el device usado en la transacción. | ninguno |
ADD_TO_WATCHLIST | Agregar al cliente a una lista restrictiva de monitoreo para un escrutinio reforzado en transacciones futuras. | ninguno |
CAUTIONARY_HOLD_CLEAR | Liberar una retención cautelar aplicada previamente; levantar el congelamiento temporal de los fondos acreditados. Se emite en el evento de webhook en que un analista libera la retención cautelar y en las resoluciones de caso del analista en que este activa el indicador de liberación. | ninguno |
ACCOUNT_BLOCK_CLEAR | Liberar un bloqueo preventivo de cuenta aplicado previamente; restaurar la cuenta al estado activo. Se emite en el evento de webhook en que un analista libera el bloqueo de cuenta y en las resoluciones de caso del analista en que este activa el indicador de liberación. | ninguno |
Información de revisión
Sección titulada «Información de revisión»Presente solo cuando assessment es REVIEW. Aporta información para notificar al usuario final.
| Campo | Tipo | Descripción |
|---|---|---|
estimated_resolution_minutes | integer | Tiempo estimado para la resolución (28 o 58 minutos) |
review_reason | string | Motivo genérico apto para una notificación de cara al usuario |
tracking_id | UUID | Identificador para que el usuario haga seguimiento del caso |
Ejemplo de respuesta: ALLOW
Sección titulada «Ejemplo de respuesta: ALLOW»{ "error": false, "data": { "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "transaction_id": "f9e8d7c6-b5a4-3210-fedc-ba0987654321", "workflow_id": "11223344-5566-7788-99aa-bbccddeeff00", "workflow_name": "pix_out_standard", "workflow_version": 3, "assessment": "ALLOW", "score": 12.5, "thresholds": { "review_threshold": 45.0, "block_threshold": 80.0, "adjustments": [] }, "stages_executed": 4, "stages_total": 4, "early_terminated": false, "execution_time_ms": 23, "analysis_time_ms": 45, "explanation": { "stages": [ { "name": "identity_verification", "score": 0 }, { "name": "transaction_patterns", "score": 5.0 }, { "name": "counterpart_analysis", "score": 7.5 }, { "name": "device_signals", "score": 0 } ] }, "created_at": "2026-03-08T17:30:00.123Z", "resolution_source": "ENGINE", "reason_code": "LOW_RISK", "reason_description": "Transaction approved with low risk", "actions": [], "sources_loaded": { "customer": true, "counterpart": true, "device": true, "dict": true, "datarudder": true }, "enrich_time_ms": 18, "eval_time_ms": 23 }}Ejemplo de respuesta: REVIEW
Sección titulada «Ejemplo de respuesta: REVIEW»Cuando la decisión es REVIEW, la transacción queda retenida para análisis manual. El integrador no debe procesar la transacción y debe informar al usuario final que está en revisión.
{ "error": false, "data": { "id": "b2c3d4e5-f6a7-8901-bcde-f12345678901", "transaction_id": "e8d7c6b5-a493-2101-edcb-a09876543210", "workflow_id": "11223344-5566-7788-99aa-bbccddeeff00", "workflow_name": "pix_out_standard", "workflow_version": 3, "assessment": "REVIEW", "score": 62.0, "thresholds": { "review_threshold": 45.0, "block_threshold": 80.0, "adjustments": [] }, "stages_executed": 4, "stages_total": 4, "early_terminated": false, "execution_time_ms": 31, "analysis_time_ms": 52, "explanation": { "stages": [ { "name": "identity_verification", "score": 0 }, { "name": "transaction_patterns", "score": 25.0 }, { "name": "counterpart_analysis", "score": 30.0 }, { "name": "device_signals", "score": 7.0 } ] }, "created_at": "2026-03-08T17:30:00.456Z", "resolution_source": "ENGINE", "reason_code": null, "reason_description": null, "actions": [], "review_info": { "estimated_resolution_minutes": 28, "review_reason": "Transaction held for security analysis", "tracking_id": "b2c3d4e5-f6a7-8901-bcde-f12345678901" }, "sources_loaded": { "customer": true, "counterpart": true, "device": true, "dict": true, "datarudder": false }, "source_errors": { "datarudder": "timeout after 1000ms" }, "enrich_time_ms": 1012, "eval_time_ms": 31 }}Ejemplo de respuesta: BLOCK
Sección titulada «Ejemplo de respuesta: BLOCK»{ "error": false, "data": { "id": "c3d4e5f6-a7b8-9012-cdef-123456789012", "transaction_id": "d7c6b5a4-9382-1010-dcba-098765432109", "workflow_id": "11223344-5566-7788-99aa-bbccddeeff00", "workflow_name": "pix_out_standard", "workflow_version": 3, "assessment": "BLOCK", "score": 91.0, "thresholds": { "review_threshold": 45.0, "block_threshold": 80.0, "adjustments": [] }, "stages_executed": 2, "stages_total": 4, "early_terminated": true, "blocked_at": "counterpart_analysis", "execution_time_ms": 15, "analysis_time_ms": 38, "explanation": { "stages": [ { "name": "identity_verification", "score": 10.0 }, { "name": "counterpart_analysis", "score": 81.0 } ], "blocked_at": "counterpart_analysis" }, "created_at": "2026-03-08T17:30:00.789Z", "resolution_source": "ENGINE", "reason_code": "HIGH_RISK_SCORE", "reason_description": "Transaction blocked due to high risk score", "actions": [ { "type": "ACCOUNT_BLOCK", "parameters": {} } ], "sources_loaded": { "customer": true, "counterpart": true, "dict": true, "datarudder": true }, "enrich_time_ms": 22, "eval_time_ms": 15 }}Webhooks
Sección titulada «Webhooks»Los webhooks son el canal asíncrono por el cual Guardline notifica al integrador los eventos del ciclo de vida de la decisión. Todo webhook se entrega a través de la configuración de resultados del flujo de trabajo: un resultado con una acción send_webhook entrega por el transporte configurado en ese flujo de trabajo. Todas las clases de evento viajan por este único flujo:
- Eventos del ciclo de vida de la decisión: decisiones del motor, resoluciones de caso del analista (aprobar, bloquear, escalar) y resoluciones automáticas por vencimiento del SLA.
- Acciones manuales del analista: una retención cautelar o un bloqueo preventivo de cuenta que un analista aplica o libera desde la estación de trabajo de operaciones, fuera de cualquier caso abierto. Estas acciones viajan por el mismo flujo y el mismo transporte de la instancia; no hay ningún endpoint manual aparte.
Todo cuerpo lleva tres campos discriminadores (event_id, event_kind, subject) que clasifican el evento. Consulte los campos del contrato unificado más abajo.
Cuándo se envían los webhooks
Sección titulada «Cuándo se envían los webhooks»Webhooks por resultado
Sección titulada «Webhooks por resultado»La emisión de webhooks está condicionada por la configuración de resultados del flujo de trabajo: una acción send_webhook se vincula a uno o más tipos de decisión (allow, review, block, escalate), y el webhook solo se dispara cuando la decisión resuelta coincide con un tipo de decisión vinculado. Los vínculos se configuran durante la puesta en marcha de la integración, según los eventos que usted quiera recibir.
Esto significa que no existe una regla fija del tipo “solo hay webhooks en REVIEW”. Una decisión ALLOW puede disparar un webhook si el flujo de trabajo vincula send_webhook a allow; una decisión BLOCK puede disparar un webhook si está vinculada a block; y así sucesivamente. A la inversa, una decisión REVIEW no disparará ningún webhook si el flujo de trabajo no tiene el vínculo. Sus decisiones de configuración determinan el conjunto real de entregas.
Los eventos emitidos por este flujo son:
| Evento | resolution_source | assessment típico |
|---|---|---|
| El motor decide ALLOW | ENGINE | ALLOW |
| El motor decide REVIEW | ENGINE | REVIEW |
| El motor decide BLOCK | ENGINE | BLOCK |
| El analista aprueba un caso en REVIEW | ANALYST | ALLOW |
| El analista bloquea un caso en REVIEW | ANALYST | BLOCK |
| El analista escala un caso en REVIEW | ANALYST | ESCALATE |
| El SLA vence y se resuelve automáticamente | SLA_TIMEOUT | ALLOW o BLOCK |
Acciones manuales del analista
Sección titulada «Acciones manuales del analista»El analista puede actuar fuera de un caso REVIEW abierto: aplicar o liberar una retención cautelar sobre una transacción, o aplicar o liberar un bloqueo preventivo sobre una cuenta. Cada acción emite un webhook para que el integrador pueda aplicar o liberar el estado correspondiente de su lado. Las cuatro llevan event_kind: "manual_action" y se entregan por el mismo flujo y el mismo transporte de la instancia que los eventos del ciclo de vida de la decisión; no hay ningún endpoint manual aparte.
| Evento | Disparador | subject.type | assessment |
|---|---|---|---|
analyst_cautionary_hold_apply | El analista aplica una retención cautelar sobre una transacción | transaction | BLOCK (acción aplicada en actions) |
analyst_cautionary_hold_clear | El analista libera una retención cautelar activa | transaction | ALLOW (acción de liberación en actions) |
analyst_account_block_apply | El analista aplica un bloqueo preventivo sobre una cuenta | account | BLOCK (acción aplicada en actions) |
analyst_account_block_clear | El analista libera un bloqueo de cuenta activo | account | ALLOW (acción de liberación en actions) |
Estos eventos usan los mismos encabezados, modos de autenticación, política de reintentos y semántica de idempotencia que se describen a continuación. Las retenciones cautelares se anclan a la decisión de fraude de la transacción, así que su cuerpo lleva el contexto completo de la decisión (transaction_id, workflow_*, score, etc.) junto a resolution_source: "ANALYST" y la acción aplicada o liberada. Los bloqueos preventivos de cuenta no tienen decisión: el analista actúa directamente sobre la cuenta, sin transacción de origen ni decisión de fraude, así que su cuerpo omite el contexto de la decisión y lleva solo el sujeto cuenta. Para esos eventos de cuenta, decision_id y transaction_id son nulos en las superficies de polling y de monitoreo; nunca se emite un UUID en cero. Consulte los eventos con alcance de cuenta (sin decisión) más abajo.
Formato del payload
Sección titulada «Formato del payload»En los eventos con alcance de transacción, el cuerpo del webhook usa la misma estructura plana que la respuesta síncrona de la API (el payload de decisión), pero sin el envoltorio {"error": false, "data": ...}, y lleva de forma aditiva tres campos del contrato unificado (event_id, event_kind, subject). Todos los campos planos del payload síncrono de decisión se conservan, de modo que un parser existente sigue funcionando y un consumidor conforme ignora los campos aditivos que no conoce.
Esto significa que el integrador puede mantener un solo parser para los campos planos de la decisión (reutilizándolo tanto para la respuesta síncrona, extrayendo desde .data, como para el cuerpo del webhook) y ramificar por event_kind más subject para clasificar el evento.
Campos del contrato unificado
Sección titulada «Campos del contrato unificado»Todo cuerpo de webhook lleva tres campos de primer nivel que clasifican el evento:
| Campo | Tipo | Descripción |
|---|---|---|
event_id | UUID | Único por evento de webhook. No es el id de la decisión (resolver y escalar reutilizan el id de la decisión a lo largo de un ciclo de vida; el event_id es distinto en cada emisión). Estable entre los reintentos de una misma entrega. |
event_kind | string | El discriminador del evento. Uno de engine_decision, case_resolution, case_escalation, sla_timeout_resolution, manual_action. Clasifique por este campo, nunca por la presencia de actions[]. |
subject | objeto | El sujeto tipado. subject.type es transaction o account. subject.transaction_id está presente en los eventos con alcance de transacción; subject.account_id está presente en los eventos con alcance de cuenta. |
Eventos con alcance de cuenta (sin decisión)
Sección titulada «Eventos con alcance de cuenta (sin decisión)»La aplicación y la liberación de un bloqueo preventivo de cuenta no tienen decisión: el analista actúa directamente sobre una cuenta, sin transacción de origen ni decisión de fraude. Su cuerpo es deliberadamente mínimo y honesto:
subjectes{ "type": "account", "account_id": "<id>" }.event_kindesmanual_action;assessmentesBLOCKal aplicar yALLOWal liberar;actions[]llevaACCOUNT_BLOCKoACCOUNT_BLOCK_CLEAR;resolution_sourceesANALYST;created_ates el momento en que la acción del analista quedó confirmada.- Los campos de contexto de la decisión se omiten (sin
id, sintransaction_id, sinworkflow_*,score,thresholds,stages_*,explanation, tiempos,trace_idnirequest_id). Nunca se emite un id de decisión sintético ni un id de transacción en ceros. En las superficies de lectura de polling y de monitoreo, eldecision_idy eltransaction_iddel ledger sonnullpara estos eventos.
Los eventos con alcance de transacción (decisiones del motor, resolución y escalamiento de caso, retenciones cautelares) conservan todos sus campos planos; solo se añaden los tres campos del contrato unificado.
Ejemplo de webhook: el analista aprueba con retención cautelar
Sección titulada «Ejemplo de webhook: el analista aprueba con retención cautelar»{ "event_id": "9a1b2c3d-4e5f-6071-8293-a4b5c6d7e8f9", "event_kind": "case_resolution", "subject": { "type": "transaction", "transaction_id": "e8d7c6b5-a493-2101-edcb-a09876543210" }, "id": "b2c3d4e5-f6a7-8901-bcde-f12345678901", "transaction_id": "e8d7c6b5-a493-2101-edcb-a09876543210", "workflow_id": "11223344-5566-7788-99aa-bbccddeeff00", "workflow_name": "pix_out_standard", "workflow_version": 3, "assessment": "ALLOW", "score": 62.0, "thresholds": { "review_threshold": 45.0, "block_threshold": 80.0, "adjustments": [] }, "stages_executed": 4, "stages_total": 4, "early_terminated": false, "execution_time_ms": 31, "analysis_time_ms": 52, "explanation": { "stages": [ { "name": "identity_verification", "score": 0 }, { "name": "transaction_patterns", "score": 25.0 }, { "name": "counterpart_analysis", "score": 30.0 }, { "name": "device_signals", "score": 7.0 } ] }, "created_at": "2026-03-08T17:30:00.456Z", "resolution_source": "ANALYST", "reason_code": "CUSTOMER_CONFIRMED", "reason_description": "Customer confirmed the transaction is legitimate", "actions": [ { "type": "CAUTIONARY_HOLD", "parameters": { "duration_hours": 72 } } ]}Ejemplo de webhook: aprobación automática por vencimiento del SLA
Sección titulada «Ejemplo de webhook: aprobación automática por vencimiento del SLA»{ "event_id": "1d2e3f40-5161-7283-94a5-b6c7d8e9f001", "event_kind": "sla_timeout_resolution", "subject": { "type": "transaction", "transaction_id": "e8d7c6b5-a493-2101-edcb-a09876543210" }, "id": "b2c3d4e5-f6a7-8901-bcde-f12345678901", "transaction_id": "e8d7c6b5-a493-2101-edcb-a09876543210", "workflow_id": "11223344-5566-7788-99aa-bbccddeeff00", "workflow_name": "pix_out_standard", "workflow_version": 3, "assessment": "ALLOW", "score": 62.0, "thresholds": { "review_threshold": 45.0, "block_threshold": 80.0, "adjustments": [] }, "stages_executed": 4, "stages_total": 4, "early_terminated": false, "execution_time_ms": 31, "analysis_time_ms": 52, "explanation": { "stages": [ { "name": "identity_verification", "score": 0 }, { "name": "transaction_patterns", "score": 25.0 }, { "name": "counterpart_analysis", "score": 30.0 }, { "name": "device_signals", "score": 7.0 } ] }, "created_at": "2026-03-08T17:30:00.456Z", "resolution_source": "SLA_TIMEOUT", "reason_code": "SLA_TIMEOUT_AUTO_APPROVED", "reason_description": "Automatically approved due to SLA expiration", "actions": [ { "type": "CAUTIONARY_HOLD", "parameters": { "duration_hours": 72 } } ]}Ejemplo de webhook: el analista bloquea con suspensión de la cuenta
Sección titulada «Ejemplo de webhook: el analista bloquea con suspensión de la cuenta»{ "event_id": "2e3f4051-6273-8495-a6b7-c8d9e0f10203", "event_kind": "case_resolution", "subject": { "type": "transaction", "transaction_id": "e8d7c6b5-a493-2101-edcb-a09876543210" }, "id": "b2c3d4e5-f6a7-8901-bcde-f12345678901", "transaction_id": "e8d7c6b5-a493-2101-edcb-a09876543210", "workflow_id": "11223344-5566-7788-99aa-bbccddeeff00", "workflow_name": "pix_out_standard", "workflow_version": 3, "assessment": "BLOCK", "score": 62.0, "thresholds": { "review_threshold": 45.0, "block_threshold": 80.0, "adjustments": [] }, "stages_executed": 4, "stages_total": 4, "early_terminated": false, "execution_time_ms": 31, "analysis_time_ms": 52, "explanation": { "stages": [ { "name": "identity_verification", "score": 0 }, { "name": "transaction_patterns", "score": 25.0 }, { "name": "counterpart_analysis", "score": 30.0 }, { "name": "device_signals", "score": 7.0 } ] }, "created_at": "2026-03-08T17:30:00.456Z", "resolution_source": "ANALYST", "reason_code": "CONFIRMED_FRAUD", "reason_description": "Analyst confirmed fraudulent activity", "actions": [ { "type": "CAUTIONARY_HOLD", "parameters": { "duration_hours": 72 } }, { "type": "ACCOUNT_BLOCK", "parameters": {} } ]}Ejemplo de webhook: el analista aplica un bloqueo preventivo de cuenta (sin decisión)
Sección titulada «Ejemplo de webhook: el analista aplica un bloqueo preventivo de cuenta (sin decisión)»Un evento de cuenta sin decisión lleva el sujeto cuenta y omite el contexto de la decisión. El created_at es el momento en que el analista aplicó el bloqueo. El evento de liberación tiene la misma forma, con assessment: "ALLOW" y actions[0].type: "ACCOUNT_BLOCK_CLEAR".
{ "event_id": "7c1f0a2b-3d4e-5f60-7182-93a4b5c6d7e8", "event_kind": "manual_action", "subject": { "type": "account", "account_id": "ACC-00086" }, "assessment": "BLOCK", "resolution_source": "ANALYST", "reason_code": "SUSPECTED_FRAUD", "reason_description": null, "created_at": "2026-03-08T17:32:10.004Z", "actions": [ { "type": "ACCOUNT_BLOCK", "parameters": {} } ]}Encabezados
Sección titulada «Encabezados»Toda solicitud de webhook incluye los siguientes encabezados HTTP:
| Encabezado | Descripción |
|---|---|
Content-Type | Siempre application/json |
X-Guardline-Delivery-ID | UUID estable de esta entrega, idéntico en todos los reintentos. Úselo para la deduplicación |
X-Guardline-Attempt-Number | Número secuencial del intento (1 para la primera entrega, 2 para el primer reintento, etc.) |
X-Guardline-Timestamp | Marca de tiempo Unix del momento de la firma (cuando HMAC está habilitado) |
X-Guardline-Signature | Firma HMAC-SHA256 en hexadecimal (cuando HMAC está habilitado) |
Authorization | Token Bearer (cuando OAuth está habilitado) |
Autenticación del webhook
Sección titulada «Autenticación del webhook»Guardline admite cuatro modos de autenticación de webhook. El modo se configura por endpoint de webhook durante la puesta en marcha de la integración. La firma HMAC aporta verificación de integridad del mensaje y puede combinarse con cualquier modo. En el modo solo HMAC es la única autenticación y es obligatoria. En los modos OAuth, mTLS y OAuth + mTLS es opcional, aunque recomendada como defensa en profundidad; cuando no hay un secreto HMAC configurado en esos modos, los encabezados X-Guardline-Signature y X-Guardline-Timestamp no se envían.
| Modo | Firma HMAC | Bearer OAuth | Certificado de cliente |
|---|---|---|---|
| Solo HMAC (predeterminado) | Obligatoria | No | No |
| OAuth 2.0 | Opcional, recomendada | Sí | No |
| mTLS | Opcional, recomendada | No | Sí |
| OAuth 2.0 + mTLS | Opcional, recomendada | Sí | Sí |
Autenticación HMAC-SHA256
Sección titulada «Autenticación HMAC-SHA256»La autenticación HMAC usa un secreto compartido provisionado durante la puesta en marcha del integrador.
Proceso de verificación en el receptor:
- Extraer el encabezado
X-Guardline-Timestamp - Rechazar si la marca de tiempo tiene más de 5 minutos de antigüedad respecto del reloj del servidor
- Concatenar la marca de tiempo y el cuerpo de la solicitud:
{timestamp}.{body} - Calcular
HMAC-SHA256de la concatenación usando el secreto compartido - Codificar el resultado en hexadecimal
- Comparar con el encabezado
X-Guardline-Signatureusando una comparación de tiempo constante - Rechazar si hay discrepancia
Pseudocódigo:
import hmac, hashlib, time
def verify_webhook(body: bytes, timestamp: str, signature: str, secret: str) -> bool: if abs(time.time() - int(timestamp)) > 300: return False
message = f"{timestamp}.".encode() + body expected = hmac.new( secret.encode(), message, hashlib.sha256 ).hexdigest()
return hmac.compare_digest(expected, signature)Autenticación mTLS
Sección titulada «Autenticación mTLS»La autenticación TLS mutua garantiza la identidad de Guardline en la capa de transporte, sin requerir validación a nivel de aplicación.
Configuración:
- Durante el aprovisionamiento, Guardline entrega el certificado de la CA raíz (
guardline-ca.pem) - El integrador configura su servidor de webhook para exigir certificados de cliente
- El integrador agrega
guardline-ca.pema la lista de CA de confianza del servidor - En cada entrega, Guardline presenta un certificado de cliente firmado por la CA raíz
- El servidor del integrador valida la cadena de certificados automáticamente en la capa TLS
El campo CN (Common Name) del certificado de cliente contiene el identificador de la instancia del integrador. El integrador puede validar opcionalmente este campo para asegurarse de que la solicitud proviene de la instancia correcta.
Cuando mTLS es el único modo de autenticación y no hay un secreto HMAC configurado, los encabezados X-Guardline-Signature y X-Guardline-Timestamp no se envían. La misma omisión aplica a los modos OAuth y OAuth + mTLS cuando no hay un secreto HMAC configurado. Consulte la matriz de autenticación del webhook incluida arriba para ver el detalle completo por modo.
Autenticación OAuth 2.0
Sección titulada «Autenticación OAuth 2.0»La autenticación OAuth permite que Guardline obtenga un token de acceso antes de cada entrega, mediante el flujo de Client Credentials (RFC 6749, sección 4.4).
Configuración:
- El integrador proporciona, durante la puesta en marcha de la integración:
token_endpoint,client_id,client_secrety, opcionalmente,scope - Antes de cada entrega, Guardline solicita un token al endpoint indicado
- La solicitud del token sigue el formato estándar:
POST {token_endpoint}Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials&client_id={client_id}&client_secret={client_secret}&scope={scope}- Guardline incluye el token obtenido en el encabezado de autorización del webhook:
Authorization: Bearer {access_token}- El integrador valida el token en su endpoint de webhook según su implementación de OAuth
Guardline almacena el token en caché respetando el campo expires_in de la respuesta del endpoint de token, con un margen de seguridad de 60 segundos. Si el receptor del webhook devuelve 401, el token en caché se invalida y se obtiene un token nuevo para un único reintento.
Si la obtención del token falla por credenciales inválidas (401 o 400 desde el endpoint de token), el primer intento de envío registra una entrega fallida. El worker de reintentos reconoce el error de autenticación no reintentable en su siguiente ciclo y marca la entrega como exhausted, sin más intentos, de modo que el integrador no ve una espera larga por una falla de configuración de credenciales. Las fallas transitorias del endpoint de token (500, tiempo de espera) siguen la política normal de reintentos.
Configuración del endpoint
Sección titulada «Configuración del endpoint»El endpoint de webhook se configura durante la puesta en marcha de la integración. Requisitos:
| Requisito | Detalle |
|---|---|
| Protocolo | HTTPS obligatorio |
| Versión de TLS | 1.2 o superior |
| Respuesta de éxito | Cualquier código 2xx (el cuerpo se ignora) |
| Tiempo de espera | Responder en menos de 10 segundos |
| Idempotencia | Deduplicar las entregas usando X-Guardline-Delivery-ID |
Recomendación de implementación: reciba el webhook, encólelo para procesamiento asíncrono y responda de inmediato con 200. Así se evitan los tiempos de espera agotados y se garantiza una entrega confiable.
Rotación de credenciales
Sección titulada «Rotación de credenciales»Cuando se rotan las credenciales de OAuth o los certificados mTLS, los reintentos en curso de entregas ya despachadas continúan usando las credenciales que estaban activas en el momento del despacho. Las entregas nuevas usan las credenciales actualizadas de inmediato.
Si es necesario reenviar entregas fallidas con las credenciales nuevas, se puede disparar un reenvío desde el lado de operaciones de Guardline. El endpoint correspondiente (POST /api/v2/webhooks/deliveries/{id}/redispatch) es exclusivo de administradores: requiere autenticación JWT con el rol SUPERVISOR o ADMIN y no se puede invocar con una clave de API de integrador. Para disparar un reenvío tras la rotación de credenciales, contacte a su representante de soporte de Guardline; él lo ejecutará en su nombre. El reenvío crea una entrega nueva usando las últimas credenciales configuradas, preservando el payload original y el contexto de la decisión, y la entrega original se conserva intacta con fines de auditoría.
Política de reintentos
Sección titulada «Política de reintentos»Si Guardline no recibe una respuesta HTTP 2xx, el webhook se reintenta con retroceso exponencial:
| Intento | Espera tras la falla |
|---|---|
| 1 | 5 segundos |
| 2 | 30 segundos |
| 3 | 2 minutos |
| 4 | 10 minutos |
| 5 | 30 minutos |
| 6 | 1 hora |
| 7 | 2 horas |
| 8 | 4 horas |
| 9 | 8 horas |
| 10 | 12 horas |
Tras 10 intentos fallidos, la entrega se marca como exhausted y se genera una alerta interna. La notificación aún puede recuperarse mediante el endpoint de sondeo.
Tiempo de espera: cada intento de entrega tiene un tiempo de espera de 10 segundos. Asegúrese de que su manejador de webhook responda dentro de esa ventana.
Respuesta esperada: devuelva HTTP 200 OK con cualquier cuerpo. Solo importa el código de estado.
Idempotencia
Sección titulada «Idempotencia»Los webhooks pueden entregarse más de una vez (por reintentos tras problemas de red). Use el encabezado X-Guardline-Delivery-ID para deduplicar:
- Almacene cada
X-Guardline-Delivery-IDprocesado. - Al recibir un webhook, verifique si el ID de entrega ya fue procesado.
- Si ya lo fue, responda
200 OKsin volver a procesarlo.
Gestión de decisiones
Sección titulada «Gestión de decisiones»Consultar una decisión
Sección titulada «Consultar una decisión»Consulte el estado actual de una decisión por su ID.
GET /api/v2/decisions/{id}Encabezados:
X-API-Key: gl_live_your_api_key_hereRespuesta: el mismo envoltorio y la misma estructura de payload de decisión que el endpoint de análisis.
Cancelar una decisión en REVIEW
Sección titulada «Cancelar una decisión en REVIEW»Cuando una transacción en REVIEW deja de ser relevante (desistimiento del usuario, expiración de la sesión, duplicado, etc.), el integrador debe cancelarla para que los analistas dejen de trabajar en ella. No se envía ningún webhook después de la cancelación.
POST /api/v2/decisions/{id}/cancelEncabezados:
Content-Type: application/jsonX-API-Key: gl_live_your_api_key_hereSolicitud:
{ "reason": "Client cancelled the transaction"}| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
reason | string | sí | Motivo de la cancelación (de 3 a 500 caracteres) |
Respuesta (200 OK):
{ "error": false, "data": { "decision_id": "b2c3d4e5-f6a7-8901-bcde-f12345678901", "case_id": "d4e5f6a7-b890-1234-efab-567890123456", "previous_status": "PENDING", "new_status": "CANCELLED", "cancelled_at": "2026-03-08T17:45:00.123Z" }}Comportamiento:
- Devuelve
200si el caso se cancela correctamente. - Devuelve
200si el caso ya estaba cancelado (idempotente). - Devuelve
409si el caso ya fue resuelto por un analista o por vencimiento del SLA. - Solo se pueden cancelar los casos en estado
PENDINGoIN_PROGRESS.
Sondeo de notificaciones (fallback)
Sección titulada «Sondeo de notificaciones (fallback)»Si los webhooks fallan de forma repetida (por ejemplo, durante una indisponibilidad prolongada), el integrador puede sondear las notificaciones no entregadas y confirmarlas después de procesarlas.
Este es un mecanismo de respaldo. El webhook es el canal principal de entrega.
Listar notificaciones pendientes
Sección titulada «Listar notificaciones pendientes»GET /api/v2/decisions/notificationsEncabezados:
X-API-Key: gl_live_your_api_key_hereParámetros de consulta:
| Parámetro | Tipo | Predeterminado | Descripción |
|---|---|---|---|
since | string | ninguno | Marca de tiempo ISO 8601. Devuelve solo las notificaciones creadas después de ese momento. |
status | string | ninguno | Filtrar por estado: pending, failed o exhausted |
limit | integer | 50 | Máximo de resultados (de 1 a 200) |
Respuesta (200 OK):
{ "error": false, "data": { "notifications": [ { "delivery_id": "aabbccdd-1122-3344-5566-778899001122", "decision_id": "b2c3d4e5-f6a7-8901-bcde-f12345678901", "transaction_id": "e8d7c6b5-a493-2101-edcb-a09876543210", "status": "exhausted", "payload": { "id": "b2c3d4e5-f6a7-8901-bcde-f12345678901", "transaction_id": "e8d7c6b5-a493-2101-edcb-a09876543210", "assessment": "ALLOW", "resolution_source": "ANALYST", "actions": [ { "type": "CAUTIONARY_HOLD", "parameters": { "duration_hours": 72 } } ], "score": 62.0, "created_at": "2026-03-08T17:30:00.456Z" }, "created_at": "2026-03-08T17:35:00.000Z", "attempt_number": 10 } ], "total": 1 }}El campo payload contiene el mismo cuerpo enviado en el webhook, incluidos los campos event_id, event_kind y subject. En los eventos de cuenta sin decisión (event_kind: "manual_action" con sujeto cuenta), el decision_id y el transaction_id de primer nivel son null, y el payload omite el contexto de la decisión y lleva solo el sujeto cuenta.
Confirmar una notificación
Sección titulada «Confirmar una notificación»Después de procesar una notificación obtenida por sondeo, confírmela para que deje de aparecer en las consultas siguientes.
POST /api/v2/decisions/notifications/{delivery_id}/ackEncabezados:
X-API-Key: gl_live_your_api_key_hereRespuesta (200 OK):
{ "error": false, "data": { "delivery_id": "aabbccdd-1122-3344-5566-778899001122", "acknowledged": true }}Comportamiento:
- Devuelve
200si la confirmación se registra correctamente. - Devuelve
200si ya estaba confirmada (idempotente).
Flujos de integración
Sección titulada «Flujos de integración»PIX Out: decisión directa (ALLOW o BLOCK)
Sección titulada «PIX Out: decisión directa (ALLOW o BLOCK)»Integrator Guardline | | | POST /decisions/analyze | |---------------------------->| | | Enrich context (DICT, Data Rudder) | | Execute fraud rules | | Calculate score + decision | 200 OK (ALLOW or BLOCK) | |<----------------------------| | | | Execute actions | | (if any in response) |Responsabilidades del integrador:
- Si es
ALLOW: autorizar el PIX. - Si es
BLOCK: rechazar el PIX y ejecutar lasactionsque correspondan (por ejemplo,ACCOUNT_BLOCK).
Presupuesto de tiempo: la respuesta de Guardline suele completarse en menos de 100 ms. El SLA regulatorio del PIX es de 40 segundos de extremo a extremo, por lo que el integrador tiene un margen amplio.
PIX Out: flujo de revisión
Sección titulada «PIX Out: flujo de revisión»Integrator Guardline Analyst | | | | POST /decisions/analyze | | |---------------------------->| | | | Score in review zone | | 200 OK (REVIEW) | | |<----------------------------| | | | Create case (async) | | Hold transaction | | | Notify end user | | | | | | | Case assigned | | |<---------------------------| | | Resolve case | | |<---------------------------| | | | | Webhook (resolution) | | |<----------------------------| | | | | | Execute decision | | | Execute actions | |Responsabilidades del integrador:
- Ante un
REVIEW: retener la transacción y notificar al usuario final con los datos dereview_info. - Ante el webhook: ejecutar la decisión final (
ALLOWoBLOCK) y lasactionsque correspondan. - Use
review_info.estimated_resolution_minutespara informar al usuario final el tiempo de espera previsto.
SLA: si ningún analista resuelve el caso dentro del plazo regulatorio, Guardline aplica automáticamente la resolución de respaldo configurada (por lo general, ALLOW con CAUTIONARY_HOLD) y envía el webhook con resolution_source: "SLA_TIMEOUT".
PIX In usa el mismo contrato de API y los mismos nombres de campo que PIX Out, pero las partes que llevan están invertidas, y la semántica de la respuesta difiere porque a Guardline se la llama una vez que el crédito ya se liquidó.
Qué parte lleva cada campo
Sección titulada «Qué parte lleva cada campo»La regla es la misma para cualquier dirección: accountId y accountHolderId siempre identifican a su cliente, el titular de la cuenta sobre cuyo historial y cuyas baselines de comportamiento se construye el análisis, y counterPart siempre describe a la otra parte. Lo que cambia con la dirección es qué parte del mundo real ocupa cada rol.
| Campo | PIX Out (direction: "OUT") | PIX In (direction: "IN") |
|---|---|---|
accountId | La cuenta pagadora | La cuenta receptora |
accountHolderId | El CPF o CNPJ del pagador | El CPF o CNPJ del receptor |
counterPart | El beneficiario | El pagador |
instantPayment.payer | Su cliente | La contraparte |
instantPayment.receiver | La contraparte | Su cliente |
Semántica de la respuesta
Sección titulada «Semántica de la respuesta»ALLOW: no se requiere ninguna acción.BLOCK: no significa “rechazar” (los fondos ya están acreditados). Significa “aplicar remediación”. Ejecute lasactionsseñalizadas (por lo general,CAUTIONARY_HOLDsobre el importe acreditado oACCOUNT_BLOCK, o ambas).REVIEW: el crédito ya ocurrió. Esto señaliza “en investigación”. La resolución y las acciones de remediación que correspondan llegarán por webhook.
Esta semántica supone que la integración entrante llama a Guardline después de que el crédito se liquidó, que es el modo de operación para el que PIX In está diseñado. Guardline no lo verifica: la liquidación la llevan los campos opcionales metadata.settledAt y metadata.transactionStatus, y ninguno de los dos es obligatorio ni se valida. Envíelos cuando los tenga, para que el registro de la decisión refleje el momento real de la liquidación.
Cómo fijar la dirección
Sección titulada «Cómo fijar la dirección»Fije metadata.direction en "IN" para PIX In. Los valores canónicos son IN, OUT y SELF, la comparación no distingue mayúsculas de minúsculas, y los alias INBOUND y OUTBOUND se aceptan y se canonizan a IN y OUT.
Ejemplo de solicitud (PIX In)
Sección titulada «Ejemplo de solicitud (PIX In)»El ejemplo de abajo refleja el ejemplo de PIX Out anterior, con los roles invertidos: ACC-00086 es la cuenta receptora, 12345678900 es el documento del receptor, y el bloque counterPart describe al pagador que envió el dinero.
{ "transactionId": "TX-20260308-00005678", "accountId": "ACC-00086", "accountHolderId": "12345678900", "transactionType": "PIX", "transactionDate": "2026-03-08T09:12:00-03:00", "totalAmount": "8400.00", "currency": "BRL", "channel": "API", "metadata": { "direction": "IN", "status": "settled", "settledAt": "2026-03-08T09:12:01-03:00", "transactionStatus": "Success", "originSystem": "IPAY" }, "customer": { "age": 42, "kycStatus": "approved", "kycLevel": "complete", "riskScore": 15.0, "riskLevel": "low", "isPEP": false, "isNewCustomer": false }, "counterPart": { "name": "Carlos Pereira", "taxIdentifier": { "taxId": "321.654.987-00", "country": "BR" }, "isNewCounterpart": true, "transactionsCount": 0, "isSameNetwork": false }, "instantPayment": { "keyValue": "12345678900", "endToEndId": "E60701190202603080912wxyz5678gh", "initiationMethod": "DICT", "payer": { "ispb": "60701190", "ispbName": "Itaú Unibanco S.A.", "document": "321.654.987-00", "branch": "0042", "account": "55555-1", "name": "Carlos Pereira" }, "receiver": { "ispb": "00000000", "ispbName": "Banco do Brasil S.A.", "document": "123.456.789-00", "branch": "3456", "account": "78901-2", "name": "João Oliveira" } }}Observe cómo instantPayment.payer lleva a la contraparte y instantPayment.receiver lleva a su cliente, al revés que en el ejemplo de PIX Out. Guardline lee el nombre del receptor de este bloque para mantener al día el registro del cliente en las transacciones entrantes, así que completarlo correctamente es lo que mantiene el nombre del cliente atado a la persona correcta.
Manejo de errores
Sección titulada «Manejo de errores»Formato de respuesta de error
Sección titulada «Formato de respuesta de error»Todos los errores siguen esta estructura:
{ "error": true, "message": "description of the error", "code": "ERROR_CODE", "details": "additional context (optional)", "request_id": "550e8400-e29b-41d4-a716-446655440000"}Códigos de estado HTTP
Sección titulada «Códigos de estado HTTP»| Código | Significado |
|---|---|
| 200 | Éxito |
| 400 | Solicitud inválida (JSON malformado, falla de validación) |
| 401 | Falla de autenticación (clave de API inválida o ausente) |
| 404 | Recurso no encontrado (el ID de decisión no existe) |
| 409 | Conflicto (el caso ya fue resuelto, no se puede cancelar) |
| 429 | Límite de solicitudes alcanzado (demasiadas solicitudes) |
| 500 | Error interno del servidor |
Manejo de errores recomendado
Sección titulada «Manejo de errores recomendado»- Ante un
400: corrija el payload de la solicitud. No reintente. - Ante un
401: verifique la clave de API. No reintente. - Ante un
404: verifique el ID de la decisión. No reintente. - Ante un
409: el caso ya fue resuelto. Trátelo como un éxito. - Ante un
429: reduzca el ritmo y reintente después de la espera indicada. - Ante un
500: reintente con retroceso exponencial (hasta 3 intentos). - Ante un tiempo de espera de red agotado: reintente. La idempotencia del
transactionIdgarantiza que no haya procesamiento duplicado.
Calendario de feriados
Sección titulada «Calendario de feriados»Recupera la lista de feriados nacionales y bancarios que Guardline usa para las ventanas de SLA y la lógica de días hábiles. Es útil para los integradores que necesitan alinear su propia programación con el mismo calendario que usa Guardline.
Endpoint
Sección titulada «Endpoint»GET /api/v2/holidays?year=<int>Autenticación
Sección titulada «Autenticación»Requiere una clave de API con el alcance holidays.read. Contacte a Guardline para habilitar este alcance en su clave.
Parámetros de consulta
Sección titulada «Parámetros de consulta»| Parámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
year | integer | No | Año por el cual filtrar. De forma predeterminada, el año actual. Rango válido: 2000 a 2100. |
Respuesta
Sección titulada «Respuesta»{ "error": false, "data": { "items": [ { "date": "2026-12-25", "name": "Natal", "type": "NATIONAL", "created_at": "2025-01-01T00:00:00Z" } ], "total": 12 }}| Campo | Tipo | Descripción |
|---|---|---|
data.items[].date | string | Fecha ISO 8601 (YYYY-MM-DD) |
data.items[].name | string | Nombre del feriado para mostrar (en portugués) |
data.items[].type | string | NATIONAL (feriados federales) o BANKING (cierres bancarios observados por el sistema bancario brasileño) |
data.items[].created_at | string | Marca de tiempo ISO 8601 del registro de la entrada |
data.total | integer | Cantidad de elementos devueltos |
Ejemplo
Sección titulada «Ejemplo»GET /api/v2/holidays?year=2026 HTTP/1.1X-API-Key: gl_live_your_api_key_hereLa lista de feriados cambia con poca frecuencia, normalmente una vez al año, cuando se confirman los nuevos calendarios. Se recomienda que los integradores guarden la respuesta en caché de su lado y la actualicen cada semana o cada mes, en lugar de hacerlo en cada solicitud.
Horario de funcionamiento
Sección titulada «Horario de funcionamiento»Devuelve las ventanas configurables de horario de funcionamiento que rigen el nivel de SLA y las reglas de horario hábil de Guardline. Se exponen dos ventanas en una única respuesta:
pixcontrola el nivel de SLA de las retenciones PIX (ventana de 30 minutos en horario hábil, 60 minutos fuera de él).enginecontrola el predicadois_business_hoursque referencian las reglas tácticas del motor de decisión.
Ambas ventanas se definen por día de la semana, con indicadores explícitos de apertura y cierre y cadenas HH:MM de inicio y fin. Los feriados cierran ambas ventanas, sea cual sea la configuración por día de la semana.
Endpoint
Sección titulada «Endpoint»GET /api/v2/calendar/working-hoursAutenticación
Sección titulada «Autenticación»Requiere un JWT o una clave de API con el alcance calendar.read. Contacte a Guardline para habilitar este alcance en su clave. El mismo alcance admitirá futuras lecturas de calendario (por ejemplo, un evaluador por marca de tiempo), de modo que una única concesión cubre todo el conjunto.
Respuesta
Sección titulada «Respuesta»{ "error": false, "data": { "pix": { "version": 1, "timezone": "America/Sao_Paulo", "weekdays": { "sunday": {"open": false, "start": "00:00", "end": "00:00"}, "monday": {"open": true, "start": "08:00", "end": "20:00"}, "tuesday": {"open": true, "start": "08:00", "end": "20:00"}, "wednesday": {"open": true, "start": "08:00", "end": "20:00"}, "thursday": {"open": true, "start": "08:00", "end": "20:00"}, "friday": {"open": true, "start": "08:00", "end": "20:00"}, "saturday": {"open": false, "start": "00:00", "end": "00:00"} } }, "engine": { "version": 1, "timezone": "America/Sao_Paulo", "weekdays": { "sunday": {"open": false, "start": "00:00", "end": "00:00"}, "monday": {"open": true, "start": "08:00", "end": "18:00"}, "tuesday": {"open": true, "start": "08:00", "end": "18:00"}, "wednesday": {"open": true, "start": "08:00", "end": "18:00"}, "thursday": {"open": true, "start": "08:00", "end": "18:00"}, "friday": {"open": true, "start": "08:00", "end": "18:00"}, "saturday": {"open": false, "start": "00:00", "end": "00:00"} } } }}| Campo | Tipo | Descripción |
|---|---|---|
data.pix | object | Ventana de horario de funcionamiento del nivel de SLA de PIX. |
data.engine | object | Ventana de horario de funcionamiento del predicado is_business_hours del motor. |
data.<window>.version | integer | Versión del payload. La forma actual es la versión 1. |
data.<window>.timezone | string | Nombre de zona horaria IANA. Actualmente fijo en America/Sao_Paulo a nivel de implantación para todos los integradores. |
data.<window>.weekdays.<day>.open | boolean | Indica si el día de la semana está abierto. Cuando es false, start y end se ignoran. |
data.<window>.weekdays.<day>.start | string | Inicio de la ventana en hora local, en formato HH:MM de 24 horas. |
data.<window>.weekdays.<day>.end | string | Fin de la ventana en hora local, en formato HH:MM de 24 horas. El fin es exclusivo: una ventana que termina a las 20:00 no incluye 20:00:00. |
Ejemplo
Sección titulada «Ejemplo»GET /api/v2/calendar/working-hours HTTP/1.1X-API-Key: gl_live_your_api_key_hereNotas de comportamiento
Sección titulada «Notas de comportamiento»- La zona horaria está fija actualmente en
America/Sao_Paulopara todos los integradores. Las zonas horarias por tenant están en la hoja de ruta; este campo se expone hoy para que las futuras implantaciones por tenant no requieran un cambio de contrato. - Los feriados cierran ambas ventanas. Use el Calendario de feriados para alinear su propia lista de feriados con la de Guardline.
startyendson límites de reloj en hora local, no desplazamientos respecto de UTC. Conviértalos a su interpretación local usando eltimezonedevuelto.- La ventana
enginepuede diferir depix(por ejemplo,pixde 08:00 a 20:00 mientras queengineva de 08:00 a 18:00). Lea ambos campos en lugar de suponer una única ventana global.
Respuestas de error
Sección titulada «Respuestas de error»| Estado | Motivo |
|---|---|
| 401 | Credencial ausente o inválida. |
| 403 | La clave de API no tiene el alcance calendar.read. |
| 500 | Error inesperado. |
No existe un 400 porque el endpoint no recibe parámetros.
La configuración de horario de funcionamiento cambia con poca frecuencia. Se recomienda que los integradores guarden la respuesta en caché de su lado y la actualicen cada semana o cada mes, en lugar de hacerlo en cada solicitud.
Apéndice A: referencia de SLA
Sección titulada «Apéndice A: referencia de SLA»Transacción PIX estándar
Sección titulada «Transacción PIX estándar»El Banco Central do Brasil exige un SLA de 40 segundos de extremo a extremo para las transacciones PIX estándar. El tiempo de respuesta de Guardline (normalmente inferior a 100 ms) es una fracción pequeña de ese presupuesto.
Transferencia inteligente (retención en REVIEW)
Sección titulada «Transferencia inteligente (retención en REVIEW)»Cuando una transacción queda retenida para análisis de fraude (decisión REVIEW), el SLA regulatorio depende del momento en que se retuvo la transacción:
| Momento de la retención | Tiempo máximo de retención |
|---|---|
| Horario hábil (días hábiles, de 08:00 a 20:00 BRT) | 30 minutos |
| Fuera del horario hábil (noches, fines de semana, feriados) | 60 minutos |
Guardline aplica un margen de seguridad de 2 minutos, disparando la resolución automática de respaldo a los 28 o 58 minutos, respectivamente.
El concepto de “día hábil” sigue el calendario nacional de feriados del Banco Central do Brasil. La lista completa está disponible mediante el endpoint Calendario de feriados.
Retención cautelar
Sección titulada «Retención cautelar»Una retención cautelar congela los fondos acreditados por hasta 72 horas cuando existe sospecha fundada de fraude, conforme a la Resolución BCB 142/2021. Se debe notificar al titular de la cuenta sobre la retención.
Apéndice B: referencia de campos
Sección titulada «Apéndice B: referencia de campos»Las tablas siguientes documentan los campos disponibles en cada bloque de la solicitud. Todos los campos de los bloques opcionales son, a su vez, opcionales. El integrador debe enviar los campos que estén disponibles en sus sistemas. Guardline usará lo que se le proporcione y omitirá lo que falte.
Solicitud de análisis: objeto instantPayment
Sección titulada «Solicitud de análisis: objeto instantPayment»| Campo | Tipo | Descripción |
|---|---|---|
keyType | string | Tipo de clave PIX: cpf, cnpj, phone, email, evp |
keyValue | string | Valor de la clave PIX |
endToEndId | string | Identificador de extremo a extremo proveniente del SPI |
originalEndToEndId | string | ID E2E original (para devoluciones o reversiones) |
reconciliationId | string | Identificador de conciliación (txid) |
initiationMethod | string | Método de inicio (DICT, QRCODE, MANUAL) |
transactionPurpose | string | Código de finalidad de la transacción |
isQRCode | boolean | Si se inició mediante código QR |
isScheduled | boolean | Si se trata de un pago programado |
payer | object | Datos de la parte pagadora (ver PixParty abajo) |
receiver | object | Datos de la parte receptora (ver PixParty abajo) |
dict | object | Datos de enriquecimiento del DICT (ver abajo) |
Solicitud de análisis: payer / receiver (PixParty)
Sección titulada «Solicitud de análisis: payer / receiver (PixParty)»| Campo | Tipo | Descripción |
|---|---|---|
ispb | string | Código ISPB de la institución |
ispbName | string | Nombre de la institución |
document | string | CPF o CNPJ |
branch | string | Número de agencia |
account | string | Número de cuenta |
name | string | Nombre del titular de la cuenta |
Solicitud de análisis: objeto dict
Sección titulada «Solicitud de análisis: objeto dict»| Campo | Tipo | Descripción |
|---|---|---|
keyCreationDate | string | Fecha ISO 8601 de creación de la clave PIX |
keyOwnershipDate | string | Fecha ISO 8601 en que se estableció la titularidad |
accountType | string | Tipo de cuenta (CACC, SVGS, etc.) |
accountOpeningDate | string | Fecha ISO 8601 de apertura de la cuenta |
pspName | string | Nombre de la institución PSP |
pspIspb | string | Código ISPB del PSP |
fraudMarkersCount | integer | Cantidad de marcadores de fraude (notificaciones de infracción) |
infractionCount | integer | Cantidad de infracciones |
lastFraudReportDate | string | Fecha ISO 8601 del último reporte de fraude |
isFlagged | boolean | Si la clave está marcada actualmente |
flaggedSince | string | Fecha ISO 8601 desde la cual la clave está marcada |
claimsCount | integer | Cantidad de reclamos de titularidad |
portabilityCount | integer | Cantidad de eventos de portabilidad |
correlationId | string | Identificador de correlación R6 |
registeredAccounts | string | Cantidad de cuentas registradas para el titular de esta clave |
lastMarkFraudDate | string | Fecha ISO 8601 de la última marca de fraude |
naturalPersonAntifraudPercentage | integer | Porcentaje antifraude para personas físicas |
legalPersonAntifraudPercentage | integer | Porcentaje antifraude para personas jurídicas |
spi | object | Estadísticas del SPI (ver abajo) |
reports | object | Reportes de infracción (ver abajo) |
frauds | array | Entradas de fraude por tipo (ver abajo) |
Solicitud de análisis: objeto dict.spi
Sección titulada «Solicitud de análisis: objeto dict.spi»| Campo | Tipo | Descripción |
|---|---|---|
d90 | string | Transacciones SPI en los últimos 90 días |
m12 | string | Transacciones SPI en los últimos 12 meses |
m60 | string | Transacciones SPI en los últimos 60 meses |
Solicitud de análisis: objeto dict.reports
Sección titulada «Solicitud de análisis: objeto dict.reports»| Campo | Tipo | Descripción |
|---|---|---|
openReports | string | Cantidad de reportes de infracción abiertos |
distinctReports | string | Cantidad de instituciones denunciantes distintas |
rejectedD90 | string | Transacciones rechazadas en los últimos 90 días |
rejectedM12 | string | Transacciones rechazadas en los últimos 12 meses |
rejectedM60 | string | Transacciones rechazadas en los últimos 60 meses |
Solicitud de análisis: elementos del arreglo dict.frauds
Sección titulada «Solicitud de análisis: elementos del arreglo dict.frauds»| Campo | Tipo | Descripción |
|---|---|---|
fraudType | string | Tipo de fraude (por ejemplo, SCAMMER_ACCOUNT, MULE_ACCOUNT) |
d90 | string | Ocurrencias en los últimos 90 días |
m12 | string | Ocurrencias en los últimos 12 meses |
m60 | string | Ocurrencias en los últimos 60 meses |
Solicitud de análisis: objeto customer
Sección titulada «Solicitud de análisis: objeto customer»| Campo | Tipo | Descripción |
|---|---|---|
age | integer | Edad del cliente |
kycStatus | string | Estado KYC (approved, pending, rejected) |
kycLevel | string | Nivel KYC (basic, intermediate, complete) |
riskScore | number | Puntaje de riesgo preexistente |
riskLevel | string | Nivel de riesgo (low, medium, high) |
isPEP | boolean | Indicador de Persona Expuesta Políticamente |
country | string | País del cliente (ISO 3166-1 alfa-2) |
accountAgeDays | integer | Antigüedad de la cuenta en días |
accountStatus | string | Estado de la cuenta (active, suspended, blocked) |
hasNegativeBalance | boolean | Si la cuenta tiene saldo negativo |
isNewCustomer | boolean | Si se trata de un cliente incorporado recientemente |
Solicitud de análisis: objeto metadata
Sección titulada «Solicitud de análisis: objeto metadata»| Campo | Tipo | Descripción |
|---|---|---|
direction | string | Dirección de la transacción. Valores canónicos: IN, OUT, SELF. No distingue mayúsculas de minúsculas; INBOUND y OUTBOUND se aceptan como alias de IN y OUT. Un valor no reconocido o ausente se registra como OUT sin error de validación (consulte PIX In). |
status | string | Estado de la transacción en el sistema de origen |
isInternational | boolean | Si se trata de una transacción transfronteriza |
originSystem | string | Identificador del sistema de origen |
Solicitud de análisis: objeto device
Sección titulada «Solicitud de análisis: objeto device»| Campo | Tipo | Descripción |
|---|---|---|
id | string | Identificador del device |
type | string | Tipo de device (mobile, desktop, tablet) |
os | string | Sistema operativo (android, ios, windows) |
isNewDevice | boolean | Primera vez que se ve este device |
isTrustedDevice | boolean | El device está en la lista de confianza |
hasScreenSharing | boolean | Se detectó compartición de pantalla |
isEmulator | boolean | Se detectó un emulador |
isRootedJailbroken | boolean | Se detectó un device con root o jailbreak |
ipAddress | string | Dirección IP de origen |
Solicitud de análisis: objeto counterPart
Sección titulada «Solicitud de análisis: objeto counterPart»| Campo | Tipo | Descripción |
|---|---|---|
name | string | Nombre de la contraparte |
taxIdentifier | object | { "taxId": "...", "country": "..." } |
isNewCounterpart | boolean | Primera transacción con esta contraparte |
riskScore | number | Puntaje de riesgo preexistente de la contraparte |
transactionsCount | integer | Cantidad histórica de transacciones con esta contraparte |
isSanctionedEntity | boolean | Si la contraparte está en una lista de sanciones |
isSameNetwork | boolean | Si la contraparte pertenece a la misma red |
Resumen de endpoints
Sección titulada «Resumen de endpoints»| Método | Ruta | Autenticación | Descripción |
|---|---|---|---|
| POST | /api/v2/decisions/analyze | API Key | Enviar una transacción para análisis de fraude |
| GET | /api/v2/decisions/{id} | API Key | Consultar una decisión por ID |
| POST | /api/v2/decisions/{id}/cancel | API Key | Cancelar una decisión en REVIEW |
| GET | /api/v2/decisions/notifications | API Key | Listar las notificaciones no entregadas (sondeo) |
| POST | /api/v2/decisions/notifications/{delivery_id}/ack | API Key | Confirmar una notificación obtenida por sondeo |
| GET | /api/v2/holidays | API Key (holidays.read) | Consultar los feriados nacionales y bancarios de un año dado |
Versión 18, actualizada el