Pular para o conteúdo

FPP API Reference

This document describes how to integrate with the Guardline fraud prevention API. It covers authentication, submitting transactions for analysis, interpreting decisions, receiving webhook notifications, and handling the complete decision lifecycle.

The integration model follows a clear separation of responsibilities: Guardline decides and signals, the integrator executes. Guardline never accesses the core banking system directly. All actions (cautionary holds, account blocks) are communicated via synchronous response or webhook, and the integrator is responsible for executing them.

All API requests must include a valid API key in the X-API-Key header.

X-API-Key: gl_live_a1b2c3d4e5f6g7h8i9j0

API keys are provisioned by the Guardline team and are scoped per environment (sandbox, production). Keep your API key confidential. If compromised, contact Guardline immediately for rotation.

Beyond environment scoping, API keys carry one or more permission scopes that gate access to specific endpoint groups. Each endpoint section in this document indicates the scope it requires, where applicable. Contact Guardline to enable additional scopes on your key.

All endpoints require HTTPS. HTTP requests will be rejected.

Submit a transaction for real-time fraud analysis. This is the primary integration endpoint.

POST /api/v2/decisions/analyze

Content-Type: application/json

These five fields are mandatory for every analysis request. Note that no customer registration is required beforehand. Guardline will attempt to enrich the context by looking up customer data using the accountId, but if no customer is found, the analysis proceeds normally with the data provided in the request.

FieldTypeDescription
transactionIdstringUnique transaction identifier in your system. Used for idempotency (duplicate requests return the original decision). We recommend a pattern like TX-YYYYMMDD-NNNNNNNN.
accountIdstringAccount identifier in your system. Used to look up customer data (if previously registered) and to correlate transactions for velocity and behavior analysis.
transactionTypestringTransaction type code. Critical for workflow routing: the fraud engine uses this field to determine which workflow to execute. For PIX transactions, use PIX. Other supported types depend on your configuration.
transactionDatestringISO 8601 timestamp with timezone (e.g., 2026-03-08T14:30:00-03:00). Used for temporal analysis and SLA calculation.
totalAmountstringTransaction amount as decimal string (e.g., "15000.00"). Use dot as decimal separator, no thousands separator.

These fields are optional. The more context provided, the more accurate the fraud analysis. The integrator decides which blocks to include based on available data.

FieldTypeDescription
accountHolderIdstringStrongly recommended. Account holder’s CPF or CNPJ, digits only (e.g., 12345678900). Enables customer identity resolution, behavioral baselines, velocity analysis, and risk profiling. Without this field, each transaction is evaluated in isolation without customer history.
currencystringISO 4217 currency code (default: BRL)
channelstringOrigination channel (MOBILE, WEB, API)
countrystringISO 3166-1 alpha-2 country code
metadataobjectTransaction metadata (direction, status)
customerobjectCustomer profile data
counterPartobjectCounterpart (beneficiary) information
deviceobjectDevice fingerprint and signals
locationobjectGeolocation and IP intelligence
instantPaymentobjectPIX-specific data, including DICT (see below)
riskSignalsobjectPre-existing risk scores and signals
complianceobjectCompliance flags

Additional blocks (location, riskSignals, compliance) follow the same principle: send what is available, omit what is not. The field structure for these blocks will be defined collaboratively during integration setup based on what data the integrator can provide.

The request payload is flexible by design. Beyond the five required fields (transactionId, accountId, transactionType, transactionDate, totalAmount), the integrator controls which optional blocks to include and which fields to populate within each block.

No pre-registration required: You do not need to create customers, accounts, or any other entities before submitting transactions. Guardline will:

  1. Enrich automatically: If a customer with the given accountId exists in Guardline’s database (from previous registrations or syncs), their profile data will be used to enhance the analysis.
  2. Resolve by document: If no customer matches the accountId but accountHolderId contains a valid CPF or CNPJ, Guardline will look up the customer by document. If found, their profile is used for the analysis. If not found, Guardline automatically enrolls the customer so that future transactions accumulate history and behavioral baselines.
  3. Proceed without customer data: If no customer is found by either method, the analysis runs with the data provided in the request. Rules that depend on customer attributes will simply not match.
  4. Use request data: If you include the customer block in the request, that data takes precedence and is used directly.

The structure of each optional block (customer, counterPart, device, location, instantPayment, riskSignals, compliance) is defined by Guardline, but the integrator decides which blocks are relevant to their use case and which fields they can provide. Fraud rules are configured to work with the available data. Fields that are not sent are simply not evaluated.

The example below is a reference showing a realistic PIX Out scenario. The actual payload should be adapted to match the data available in the integrator’s systems.

{
"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": []
}
}
}

If the same transactionId is submitted more than once, Guardline returns the original decision without reprocessing. The response includes "idempotent_replay": true to indicate this.

This allows safe retries on network timeout without risk of duplicate processing.

All three scenarios (ALLOW, REVIEW, BLOCK) return the same response structure. This is the unified payload format used throughout the platform, both in synchronous responses and in webhooks.

API responses are wrapped in a standard envelope:

{
"error": false,
"data": { ... }
}

The data field contains the decision payload described below. Error responses use "error": true (see Error Handling).

FieldTypeAlways PresentDescription
idUUIDyesUnique decision identifier
transaction_idUUIDyesInternal transaction identifier
workflow_idUUIDyesWorkflow that processed the transaction
workflow_namestringyesWorkflow name
workflow_versionintegeryesWorkflow version
assessmentstringyesDecision result: ALLOW, REVIEW, BLOCK, or ESCALATE. Synchronous responses only ever carry ALLOW, REVIEW, or BLOCK (the engine does not produce ESCALATE). ESCALATE appears exclusively on the analyst-escalates-a-REVIEW-case webhook event (see When Webhooks Are Sent).
scorenumberyesFinal risk score (0-100)
thresholdsobjectyesThresholds applied (review and block)
resolution_sourcestringyesWho made the decision (see below)
reason_codestringnoStructured reason code for the decision (see below)
reason_descriptionstringnoHuman-readable description of the reason
actionsarraynoActions to execute (see below)
review_infoobjectnoPresent only when assessment is REVIEW
execution_time_msintegeryesEngine processing time in milliseconds
analysis_time_msintegeryesTotal analysis time including enrichment
created_atdatetimeyesISO 8601 timestamp
idempotent_replaybooleannotrue if this is a replayed response
sources_loadedobjectnoData sources successfully loaded
source_errorsobjectnoData sources that failed to load
explanationobjectyesScore breakdown by stage
ValueMeaning
ENGINEAutomatic decision by the fraud engine (synchronous response, and optionally a webhook when the workflow links send_webhook to the resolved decision type)
ANALYSTManual decision by an analyst in the operations desk (webhook)
SLA_TIMEOUTAutomatic fallback due to SLA expiration (webhook)

The reason_code and reason_description fields provide context about why the decision was made. This is critical for regulatory reporting (R6, MED) and for determining how to execute the signaled actions.

For synchronous responses (resolution_source: "ENGINE"), the reason code reflects the engine’s automated assessment. The same engine assessment can also be delivered as a webhook when the workflow links send_webhook to the resolved decision type, in which case the webhook body carries the same reason code as the synchronous response. For webhook resolutions (resolution_source: "ANALYST" or "SLA_TIMEOUT"), it reflects the analyst’s judgment or the timeout policy.

SourceExample reason_codeExample reason_description
ENGINEHIGH_RISK_SCORETransaction blocked due to high risk score
ENGINELOW_RISKTransaction approved with low risk
ANALYSTCONFIRMED_FRAUDAnalyst confirmed fraudulent activity
ANALYSTCUSTOMER_CONFIRMEDCustomer confirmed the transaction is legitimate
ANALYSTSUSPICIOUS_UNCONFIRMEDSuspicious activity, insufficient evidence to confirm fraud
ANALYSTFALSE_POSITIVEAnalysis determined the alert was a false positive
SLA_TIMEOUTSLA_TIMEOUT_AUTO_APPROVEDAutomatically approved due to SLA expiration

The set of reason codes is not fixed. New codes may be introduced as operational needs evolve. The integrator should treat reason_code as a free-form string and handle unknown values gracefully. The reason_description field always provides a human-readable explanation regardless of the code.

Both fields are null when not applicable (e.g., the initial synchronous REVIEW response, where the final reason is not yet known).

Actions represent side effects that the integrator should execute. Each action has a type and optional parameters.

Action TypeDescriptionParameters
CAUTIONARY_HOLDFreeze credited funds for up to 72 hours (BCB Resolution 142/2021). The account holder must be notified.duration_hours (integer)
ACCOUNT_BLOCKPreventive suspension of the account.none
BLOCK_BENEFICIARYBlock the counterpart (beneficiary) from future transactions.none
BLOCK_DEVICEBlock the device used in the transaction.none
ADD_TO_WATCHLISTAdd the customer to a monitoring watchlist for enhanced scrutiny on future transactions.none
CAUTIONARY_HOLD_CLEARRelease a previously applied cautionary hold; lift the temporary freeze on credited funds. Emitted on the analyst-clears-cautionary-hold webhook event and on analyst case resolutions where the analyst toggles the clear flag.none
ACCOUNT_BLOCK_CLEARRelease a previously applied preventive account block; restore the account to active status. Emitted on the analyst-clears-account-block webhook event and on analyst case resolutions where the analyst toggles the clear flag.none

Present only when assessment is REVIEW. Provides information for notifying the end user.

FieldTypeDescription
estimated_resolution_minutesintegerEstimated time for resolution (28 or 58 minutes)
review_reasonstringGeneric reason suitable for user-facing notification
tracking_idUUIDIdentifier for the user to track the case
{
"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
}
}

When the decision is REVIEW, the transaction is held for manual analysis. The integrator should not process the transaction and should inform the end user that it is under review.

{
"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
}
}
{
"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 are the asynchronous channel through which Guardline notifies the integrator about decision lifecycle events. The webhook subsystem covers two complementary pipelines:

  • Outcome-driven webhooks: emitted when a workflow has a send_webhook action linked to a given decision type via the workflow outcome configuration. They cover engine decisions, analyst case resolutions (approve, block, escalate), and SLA timeout auto-resolutions.
  • Analyst manual webhooks: emitted when an analyst applies or clears a cautionary hold or a preventive account block from the operations workbench, outside of any open case.

Webhook emission is gated by the workflow outcome configuration: a send_webhook action is linked to one or more decision types (allow, review, block, escalate), and the webhook only fires when the resolved decision matches a linked decision type. Linkages are configured during integration setup based on which events you want to receive.

This means there is no fixed rule like “webhooks only on REVIEW”. An ALLOW decision can fire a webhook if the workflow links send_webhook to allow; a BLOCK decision can fire a webhook if linked to block; and so on. Conversely, a REVIEW decision will not fire a webhook unless the workflow has the linkage. Your configuration choices drive the actual delivery set.

The events emitted by this pipeline are:

Eventresolution_sourceTypical assessment
Engine decides ALLOWENGINEALLOW
Engine decides REVIEWENGINEREVIEW
Engine decides BLOCKENGINEBLOCK
Analyst approves a REVIEW caseANALYSTALLOW
Analyst blocks a REVIEW caseANALYSTBLOCK
Analyst escalates a REVIEW caseANALYSTESCALATE
SLA expires and auto-resolvesSLA_TIMEOUTALLOW or BLOCK

The operations workbench supports four manual actions an analyst can take outside of an open REVIEW case. Each action emits a webhook so the integrator can apply or release the corresponding state on their side. Configuration is environment-global (a single destination URL shared across the four events) rather than per workflow.

EventTriggerSynthetic assessment
analyst_cautionary_hold_applyAnalyst applies a cautionary hold on a transactionBLOCK (with the applied action in actions)
analyst_cautionary_hold_clearAnalyst clears an active cautionary holdALLOW (with the clear action in actions)
analyst_account_block_applyAnalyst applies a preventive block on an accountBLOCK (with the applied action in actions)
analyst_account_block_clearAnalyst clears an active account blockALLOW (with the clear action in actions)

These four events use the same payload shape, headers, authentication modes, retry policy, and idempotency semantics described below for outcome-driven webhooks. The only operational difference is the destination: the analyst manual pipeline delivers to a single environment-wide endpoint configured at deploy time, separate from the per-workflow outcome configuration. Confirm the configured destination with your Guardline support contact during integration setup. The HMAC secret is shared with the outcome-driven pipeline by default.

The synthetic payload preserves the same top-level shape as outcome-driven webhooks, including resolution_source: "ANALYST", the actions array carrying the applied or cleared action, and all standard headers. The transaction_id field is populated for the cautionary hold events; for account block events it is the zero UUID, since the action targets the account directly rather than a specific transaction.

The webhook body uses the exact same structure as the synchronous API response (the decision payload), but without the {"error": false, "data": ...} envelope. The body is the raw decision payload sent directly as JSON.

This means the integrator can implement one parser for the decision payload and reuse it for both the synchronous response (extracting from .data) and the webhook body.

Webhook Example: Analyst Approves with Cautionary Hold

Seção intitulada “Webhook Example: Analyst Approves with Cautionary Hold”
{
"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
}
}
]
}
{
"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
}
}
]
}

Webhook Example: Analyst Blocks with Account Suspension

Seção intitulada “Webhook Example: Analyst Blocks with Account Suspension”
{
"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": {}
}
]
}

Every webhook request includes the following HTTP headers:

HeaderDescription
Content-TypeAlways application/json
X-Guardline-Delivery-IDStable UUID for this delivery, identical across retries. Use for deduplication
X-Guardline-Attempt-NumberSequential attempt number (1 for first delivery, 2 for first retry, etc.)
X-Guardline-TimestampUnix timestamp of the signature moment (when HMAC is enabled)
X-Guardline-SignatureHMAC-SHA256 signature in hexadecimal (when HMAC is enabled)
AuthorizationBearer token (when OAuth is enabled)

Guardline supports three authentication modes for webhook delivery. The mode is configured per webhook endpoint during integration setup. HMAC signature is always present regardless of the selected mode, providing message integrity verification on every delivery.

ModeHMAC SignatureOAuth BearerClient Certificate
HMAC only (default)YesNoNo
OAuth 2.0YesYesNo
mTLSYesNoYes
OAuth 2.0 + mTLSYesYesYes

HMAC authentication uses a shared secret provisioned during integrator setup.

Verification process on the receiver:

  1. Extract the X-Guardline-Timestamp header
  2. Reject if the timestamp is older than 5 minutes relative to the server clock
  3. Concatenate timestamp and request body: {timestamp}.{body}
  4. Compute HMAC-SHA256 of the concatenation using the shared secret
  5. Encode the result in hexadecimal
  6. Compare with the X-Guardline-Signature header using constant-time comparison
  7. Reject if there is a mismatch

Pseudocode:

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)

Mutual TLS authentication ensures Guardline’s identity at the transport layer, without requiring application-level validation.

Setup:

  1. During provisioning, Guardline provides the root CA certificate (guardline-ca.pem)
  2. The integrator configures their webhook server to require client certificates
  3. The integrator adds guardline-ca.pem to the server’s trusted CA list
  4. On each delivery, Guardline presents a client certificate signed by the root CA
  5. The integrator’s server validates the certificate chain automatically at the TLS layer

The CN (Common Name) field of the client certificate contains the integrator’s instance identifier. The integrator can optionally validate this field to ensure the request comes from the correct instance.

When mTLS is the only authentication mode (without HMAC), the X-Guardline-Signature and X-Guardline-Timestamp headers are not sent.

OAuth authentication allows Guardline to obtain an access token before each delivery, using the Client Credentials flow (RFC 6749, section 4.4).

Setup:

  1. The integrator provides during integration setup: token_endpoint, client_id, client_secret, and optionally scope
  2. Before each delivery, Guardline requests a token from the provided endpoint
  3. The token request follows the standard format:
POST {token_endpoint}
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials&client_id={client_id}&client_secret={client_secret}&scope={scope}
  1. Guardline includes the obtained token in the webhook authorization header:
Authorization: Bearer {access_token}
  1. The integrator validates the token at their webhook endpoint according to their OAuth implementation

Guardline caches the token respecting the expires_in field from the token endpoint response, with a 60-second safety margin. If the webhook receiver returns 401, the cached token is invalidated and a fresh token is acquired for a single retry.

If token acquisition fails due to invalid credentials (401 or 400 from the token endpoint), the first dispatch attempt records a failed delivery. The retry worker recognises the non-retryable auth error on its next tick and marks the delivery as exhausted without further attempts, so the integrator does not see a long backoff for a credential-misconfiguration failure. Transient token endpoint failures (500, timeout) follow the normal retry policy.

The webhook endpoint is configured during integration setup. Requirements:

RequirementDetail
ProtocolHTTPS required
TLS version1.2 or higher
Success responseAny 2xx code (body ignored)
TimeoutRespond within 10 seconds
IdempotencyDeduplicate deliveries using X-Guardline-Delivery-ID

Implementation recommendation: receive the webhook, enqueue for asynchronous processing, and respond immediately with 200. This avoids timeouts and ensures reliable delivery.

When OAuth credentials or mTLS certificates are rotated, in-flight retries for previously dispatched deliveries continue using the credentials that were active at the time of dispatch. New deliveries use the updated credentials immediately.

If failed deliveries need to be re-sent with the new credentials, a redispatch can be triggered from the Guardline operations side. The corresponding endpoint (POST /api/v2/webhooks/deliveries/{id}/redispatch) is administrator-only: it requires JWT authentication with the SUPERVISOR or ADMIN role and is not callable with an integrator API key. To trigger a redispatch after credential rotation, contact your Guardline support representative; they will run it on your behalf. The redispatch creates a new delivery using the latest configured credentials, preserving the original payload and decision context, and the original delivery is kept intact for audit purposes.

If Guardline does not receive an HTTP 2xx response, the webhook is retried with exponential backoff:

AttemptDelay After Failure
15 seconds
230 seconds
32 minutes
410 minutes
530 minutes
61 hour
72 hours
84 hours
98 hours
1012 hours

After 10 failed attempts, the delivery is marked as exhausted and an internal alert is generated. The notification can still be retrieved via the polling endpoint.

Timeout: Each delivery attempt has a 10-second timeout. Ensure your webhook handler responds within this window.

Expected response: Return HTTP 200 OK with any body. Only the status code matters.

Webhooks may be delivered more than once (due to retries after network issues). Use the X-Guardline-Delivery-ID header to deduplicate:

  1. Store each processed X-Guardline-Delivery-ID.
  2. On receiving a webhook, check if the delivery ID was already processed.
  3. If yes, respond 200 OK without reprocessing.

Retrieve the current state of a decision by its ID.

GET /api/v2/decisions/{id}

Headers:

X-API-Key: gl_live_a1b2c3d4e5f6g7h8i9j0

Response: Same envelope and decision payload structure as the analyze endpoint.

When a transaction in REVIEW is no longer relevant (user withdrawal, session expiry, duplicate, etc.), the integrator should cancel it so analysts stop working on it. No webhook is sent after cancellation.

POST /api/v2/decisions/{id}/cancel

Headers:

Content-Type: application/json
X-API-Key: gl_live_a1b2c3d4e5f6g7h8i9j0

Request:

{
"reason": "Client cancelled the transaction"
}
FieldTypeRequiredDescription
reasonstringyesCancellation reason (3 to 500 characters)

Response (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"
}
}

Behavior:

  • Returns 200 if the case is successfully cancelled.
  • Returns 200 if the case is already cancelled (idempotent).
  • Returns 409 if the case has already been resolved by an analyst or by SLA timeout.
  • Only cases in PENDING or IN_PROGRESS status can be cancelled.

If webhooks fail repeatedly (e.g., during extended downtime), the integrator can poll for undelivered notifications and acknowledge them after processing.

This is a fallback mechanism. The webhook is the primary delivery channel.

GET /api/v2/decisions/notifications

Headers:

X-API-Key: gl_live_a1b2c3d4e5f6g7h8i9j0

Query Parameters:

ParameterTypeDefaultDescription
sincestringnoneISO 8601 timestamp. Only return notifications created after this time.
statusstringnoneFilter by status: pending, failed, or exhausted
limitinteger50Maximum results (1 to 200)

Response (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
}
}

The payload field contains the same decision payload structure used in webhooks and synchronous responses.

After processing a notification retrieved via polling, acknowledge it so it is no longer returned in subsequent queries.

POST /api/v2/decisions/notifications/{delivery_id}/ack

Headers:

X-API-Key: gl_live_a1b2c3d4e5f6g7h8i9j0

Response (200 OK):

{
"error": false,
"data": {
"delivery_id": "aabbccdd-1122-3344-5566-778899001122",
"acknowledged": true
}
}

Behavior:

  • Returns 200 if successfully acknowledged.
  • Returns 200 if already acknowledged (idempotent).
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) |

Integrator responsibilities:

  • If ALLOW: authorize the PIX.
  • If BLOCK: reject the PIX and execute any actions (e.g., ACCOUNT_BLOCK).

Time budget: The Guardline response typically completes in under 100ms. The regulatory SLA for PIX is 40 seconds end-to-end, so the integrator has ample margin.

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 | |

Integrator responsibilities:

  • On REVIEW: hold the transaction, notify the end user using the review_info data.
  • On webhook: execute the final decision (ALLOW or BLOCK) and any actions.
  • Use review_info.estimated_resolution_minutes to inform the end user of the expected wait time.

SLA: If no analyst resolves the case within the regulatory deadline, Guardline automatically applies the configured fallback (typically ALLOW with CAUTIONARY_HOLD) and sends the webhook with resolution_source: "SLA_TIMEOUT".

PIX In follows the same API contract, but the semantics differ because the credit has already been settled.

  • ALLOW: no action required.
  • BLOCK: does not mean “reject” (the funds are already credited). It means “apply remediation”. Execute the signaled actions (typically CAUTIONARY_HOLD on the credited amount and/or ACCOUNT_BLOCK).
  • REVIEW: the credit has already occurred. This signals “under investigation”. The resolution and any remediation actions will arrive via webhook.

The metadata.direction field should be set to "IN" for PIX In transactions.

All errors follow this structure:

{
"error": true,
"message": "description of the error",
"code": "ERROR_CODE",
"details": "additional context (optional)",
"request_id": "550e8400-e29b-41d4-a716-446655440000"
}
CodeMeaning
200Success
400Invalid request (malformed JSON, validation failure)
401Authentication failed (invalid or missing API key)
404Resource not found (decision ID does not exist)
409Conflict (case already resolved, cannot cancel)
429Rate limited (too many requests)
500Internal server error
  • On 400: fix the request payload. Do not retry.
  • On 401: verify the API key. Do not retry.
  • On 404: verify the decision ID. Do not retry.
  • On 409: the case was already resolved. Treat as success.
  • On 429: back off and retry after the indicated delay.
  • On 500: retry with exponential backoff (up to 3 attempts).
  • On network timeout: retry. The transactionId idempotency guarantees no duplicate processing.

Retrieves the list of national and banking holidays used by Guardline for SLA windows and business-day logic. Useful for integrators that need to align their own scheduling with the same calendar Guardline uses.

GET /api/v2/holidays?year=<int>

Requires an API key with the holidays.read scope. Contact Guardline to enable this scope on your key.

ParameterTypeRequiredDescription
yearintegerNoYear to filter. Defaults to the current year. Valid range: 2000 to 2100.
{
"error": false,
"data": {
"items": [
{
"date": "2026-12-25",
"name": "Natal",
"type": "NATIONAL",
"created_at": "2025-01-01T00:00:00Z"
}
],
"total": 12
}
}
FieldTypeDescription
data.items[].datestringISO 8601 date (YYYY-MM-DD)
data.items[].namestringHoliday display name (in Portuguese)
data.items[].typestringNATIONAL (federal holidays) or BANKING (bank-specific closures observed by the Brazilian banking system)
data.items[].created_atstringISO 8601 timestamp when the entry was registered
data.totalintegerNumber of items returned
GET /api/v2/holidays?year=2026 HTTP/1.1
X-API-Key: gl_live_a1b2c3d4e5f6g7h8i9j0

The holiday list changes infrequently, typically once per year when new calendars are confirmed. Integrators are encouraged to cache the response on their side and refresh weekly or monthly rather than per request.

The Banco Central do Brasil mandates a 40-second end-to-end SLA for standard PIX transactions. The Guardline response time (typically under 100ms) is a small fraction of this budget.

When a transaction is held for fraud analysis (REVIEW decision), the regulatory SLA depends on when the transaction was retained:

Time of RetentionMaximum Hold Time
Business hours (business days, 08:00 to 20:00 BRT)30 minutes
Non-business hours (nights, weekends, holidays)60 minutes

Guardline applies a 2-minute safety margin, triggering the automatic fallback at 28 or 58 minutes respectively.

“Business day” follows the national holiday calendar of the Banco Central do Brasil. The full list is available via the Holiday Calendar endpoint.

A cautionary hold freezes credited funds for up to 72 hours when there is founded suspicion of fraud, per BCB Resolution 142/2021. The account holder must be notified about the hold.

The tables below document the fields available in each request block. All fields in the optional blocks are themselves optional. The integrator should send whichever fields are available in their systems. Guardline will use what is provided and skip what is absent.

FieldTypeDescription
keyTypestringPIX key type: cpf, cnpj, phone, email, evp
keyValuestringPIX key value
endToEndIdstringEnd-to-end identifier from the SPI
originalEndToEndIdstringOriginal E2E ID (for returns/reversals)
reconciliationIdstringReconciliation identifier (txid)
initiationMethodstringInitiation method (DICT, QRCODE, MANUAL)
transactionPurposestringTransaction purpose code
isQRCodebooleanWhether initiated via QR code
isScheduledbooleanWhether this is a scheduled payment
payerobjectPayer party data (see PixParty below)
receiverobjectReceiver party data (see PixParty below)
dictobjectDICT enrichment data (see below)
FieldTypeDescription
ispbstringISPB code of the institution
ispbNamestringInstitution name
documentstringCPF or CNPJ
branchstringBranch number
accountstringAccount number
namestringAccount holder name
FieldTypeDescription
keyCreationDatestringISO 8601 date when the PIX key was created
keyOwnershipDatestringISO 8601 date when ownership was established
accountTypestringAccount type (CACC, SVGS, etc.)
accountOpeningDatestringISO 8601 date when the account was opened
pspNamestringPSP institution name
pspIspbstringPSP ISPB code
fraudMarkersCountintegerNumber of fraud markers (infraction notifications)
infractionCountintegerNumber of infractions
lastFraudReportDatestringISO 8601 date of the last fraud report
isFlaggedbooleanWhether the key is currently flagged
flaggedSincestringISO 8601 date since when the key has been flagged
claimsCountintegerNumber of ownership claims
portabilityCountintegerNumber of portability events
correlationIdstringR6 correlation identifier
registeredAccountsstringNumber of accounts registered to this key holder
lastMarkFraudDatestringISO 8601 date of the last fraud mark
naturalPersonAntifraudPercentageintegerAntifraud percentage for natural persons
legalPersonAntifraudPercentageintegerAntifraud percentage for legal persons
spiobjectSPI statistics (see below)
reportsobjectInfraction reports (see below)
fraudsarrayFraud entries by type (see below)
FieldTypeDescription
d90stringSPI transactions in the last 90 days
m12stringSPI transactions in the last 12 months
m60stringSPI transactions in the last 60 months
FieldTypeDescription
openReportsstringNumber of open infraction reports
distinctReportsstringNumber of distinct reporting institutions
rejectedD90stringRejected transactions in the last 90 days
rejectedM12stringRejected transactions in the last 12 months
rejectedM60stringRejected transactions in the last 60 months
FieldTypeDescription
fraudTypestringFraud type (e.g., SCAMMER_ACCOUNT, MULE_ACCOUNT)
d90stringOccurrences in the last 90 days
m12stringOccurrences in the last 12 months
m60stringOccurrences in the last 60 months
FieldTypeDescription
ageintegerCustomer age
kycStatusstringKYC status (approved, pending, rejected)
kycLevelstringKYC level (basic, intermediate, complete)
riskScorenumberPre-existing risk score
riskLevelstringRisk level (low, medium, high)
isPEPbooleanPolitically Exposed Person flag
countrystringCustomer country (ISO 3166-1 alpha-2)
accountAgeDaysintegerAccount age in days
accountStatusstringAccount status (active, suspended, blocked)
hasNegativeBalancebooleanWhether the account has negative balance
isNewCustomerbooleanWhether this is a recently onboarded customer
FieldTypeDescription
directionstringTransaction direction: IN or OUT
statusstringTransaction status in the originating system
isInternationalbooleanWhether this is a cross-border transaction
originSystemstringOriginating system identifier
FieldTypeDescription
idstringDevice identifier
typestringDevice type (mobile, desktop, tablet)
osstringOperating system (android, ios, windows)
isNewDevicebooleanFirst time this device is seen
isTrustedDevicebooleanDevice is in the trusted list
hasScreenSharingbooleanScreen sharing detected
isEmulatorbooleanEmulator detected
isRootedJailbrokenbooleanRooted/jailbroken device detected
ipAddressstringSource IP address
FieldTypeDescription
namestringCounterpart name
taxIdentifierobject{ "taxId": "...", "country": "..." }
isNewCounterpartbooleanFirst transaction with this counterpart
riskScorenumberPre-existing risk score for the counterpart
transactionsCountintegerHistorical transaction count with this counterpart
isSanctionedEntitybooleanWhether the counterpart is on a sanctions list
isSameNetworkbooleanWhether the counterpart is within the same network
MethodPathAuthDescription
POST/api/v2/decisions/analyzeAPI KeySubmit transaction for fraud analysis
GET/api/v2/decisions/{id}API KeyRetrieve a decision by ID
POST/api/v2/decisions/{id}/cancelAPI KeyCancel a decision in REVIEW
GET/api/v2/decisions/notificationsAPI KeyList undelivered notifications (polling)
POST/api/v2/decisions/notifications/{delivery_id}/ackAPI KeyAcknowledge a polled notification
GET/api/v2/holidaysAPI Key (holidays.read)Retrieve national and banking holidays for a given year