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.
Authentication
Seção intitulada “Authentication”All API requests must include a valid API key in the X-API-Key header.
X-API-Key: gl_live_a1b2c3d4e5f6g7h8i9j0API 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.
Analyzing Transactions
Seção intitulada “Analyzing Transactions”Submit a transaction for real-time fraud analysis. This is the primary integration endpoint.
Endpoint
Seção intitulada “Endpoint”POST /api/v2/decisions/analyzeRequest
Seção intitulada “Request”Content-Type: application/json
Required Fields
Seção intitulada “Required Fields”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.
| Field | Type | Description |
|---|---|---|
transactionId | string | Unique transaction identifier in your system. Used for idempotency (duplicate requests return the original decision). We recommend a pattern like TX-YYYYMMDD-NNNNNNNN. |
accountId | string | Account identifier in your system. Used to look up customer data (if previously registered) and to correlate transactions for velocity and behavior analysis. |
transactionType | string | Transaction 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. |
transactionDate | string | ISO 8601 timestamp with timezone (e.g., 2026-03-08T14:30:00-03:00). Used for temporal analysis and SLA calculation. |
totalAmount | string | Transaction amount as decimal string (e.g., "15000.00"). Use dot as decimal separator, no thousands separator. |
Optional Fields
Seção intitulada “Optional Fields”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.
| Field | Type | Description |
|---|---|---|
accountHolderId | string | Strongly 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. |
currency | string | ISO 4217 currency code (default: BRL) |
channel | string | Origination channel (MOBILE, WEB, API) |
country | string | ISO 3166-1 alpha-2 country code |
metadata | object | Transaction metadata (direction, status) |
customer | object | Customer profile data |
counterPart | object | Counterpart (beneficiary) information |
device | object | Device fingerprint and signals |
location | object | Geolocation and IP intelligence |
instantPayment | object | PIX-specific data, including DICT (see below) |
riskSignals | object | Pre-existing risk scores and signals |
compliance | object | Compliance 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.
Input Payload Flexibility
Seção intitulada “Input Payload Flexibility”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:
- Enrich automatically: If a customer with the given
accountIdexists in Guardline’s database (from previous registrations or syncs), their profile data will be used to enhance the analysis. - Resolve by document: If no customer matches the
accountIdbutaccountHolderIdcontains 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. - 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.
- Use request data: If you include the
customerblock 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.
Request Example (PIX Out)
Seção intitulada “Request Example (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": [] } }}Idempotency
Seção intitulada “Idempotency”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.
Understanding the Response
Seção intitulada “Understanding the Response”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.
Response Envelope
Seção intitulada “Response Envelope”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).
Decision Payload Structure
Seção intitulada “Decision Payload Structure”| Field | Type | Always Present | Description |
|---|---|---|---|
id | UUID | yes | Unique decision identifier |
transaction_id | UUID | yes | Internal transaction identifier |
workflow_id | UUID | yes | Workflow that processed the transaction |
workflow_name | string | yes | Workflow name |
workflow_version | integer | yes | Workflow version |
assessment | string | yes | Decision 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). |
score | number | yes | Final risk score (0-100) |
thresholds | object | yes | Thresholds applied (review and block) |
resolution_source | string | yes | Who made the decision (see below) |
reason_code | string | no | Structured reason code for the decision (see below) |
reason_description | string | no | Human-readable description of the reason |
actions | array | no | Actions to execute (see below) |
review_info | object | no | Present only when assessment is REVIEW |
execution_time_ms | integer | yes | Engine processing time in milliseconds |
analysis_time_ms | integer | yes | Total analysis time including enrichment |
created_at | datetime | yes | ISO 8601 timestamp |
idempotent_replay | boolean | no | true if this is a replayed response |
sources_loaded | object | no | Data sources successfully loaded |
source_errors | object | no | Data sources that failed to load |
explanation | object | yes | Score breakdown by stage |
Resolution Source
Seção intitulada “Resolution Source”| Value | Meaning |
|---|---|
ENGINE | Automatic decision by the fraud engine (synchronous response, and optionally a webhook when the workflow links send_webhook to the resolved decision type) |
ANALYST | Manual decision by an analyst in the operations desk (webhook) |
SLA_TIMEOUT | Automatic fallback due to SLA expiration (webhook) |
Reason Code
Seção intitulada “Reason Code”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.
| Source | Example reason_code | Example reason_description |
|---|---|---|
ENGINE | HIGH_RISK_SCORE | Transaction blocked due to high risk score |
ENGINE | LOW_RISK | Transaction approved with low risk |
ANALYST | CONFIRMED_FRAUD | Analyst confirmed fraudulent activity |
ANALYST | CUSTOMER_CONFIRMED | Customer confirmed the transaction is legitimate |
ANALYST | SUSPICIOUS_UNCONFIRMED | Suspicious activity, insufficient evidence to confirm fraud |
ANALYST | FALSE_POSITIVE | Analysis determined the alert was a false positive |
SLA_TIMEOUT | SLA_TIMEOUT_AUTO_APPROVED | Automatically 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
Seção intitulada “Actions”Actions represent side effects that the integrator should execute. Each action has a type and optional parameters.
| Action Type | Description | Parameters |
|---|---|---|
CAUTIONARY_HOLD | Freeze credited funds for up to 72 hours (BCB Resolution 142/2021). The account holder must be notified. | duration_hours (integer) |
ACCOUNT_BLOCK | Preventive suspension of the account. | none |
BLOCK_BENEFICIARY | Block the counterpart (beneficiary) from future transactions. | none |
BLOCK_DEVICE | Block the device used in the transaction. | none |
ADD_TO_WATCHLIST | Add the customer to a monitoring watchlist for enhanced scrutiny on future transactions. | none |
CAUTIONARY_HOLD_CLEAR | Release 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_CLEAR | Release 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 |
Review Info
Seção intitulada “Review Info”Present only when assessment is REVIEW. Provides information for notifying the end user.
| Field | Type | Description |
|---|---|---|
estimated_resolution_minutes | integer | Estimated time for resolution (28 or 58 minutes) |
review_reason | string | Generic reason suitable for user-facing notification |
tracking_id | UUID | Identifier for the user to track the case |
Response Example: ALLOW
Seção intitulada “Response Example: 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 }}Response Example: REVIEW
Seção intitulada “Response Example: REVIEW”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 }}Response Example: BLOCK
Seção intitulada “Response Example: 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
Seção intitulada “Webhooks”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_webhookaction 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.
When Webhooks Are Sent
Seção intitulada “When Webhooks Are Sent”Outcome-driven webhooks
Seção intitulada “Outcome-driven webhooks”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:
| Event | resolution_source | Typical assessment |
|---|---|---|
| Engine decides ALLOW | ENGINE | ALLOW |
| Engine decides REVIEW | ENGINE | REVIEW |
| Engine decides BLOCK | ENGINE | BLOCK |
| Analyst approves a REVIEW case | ANALYST | ALLOW |
| Analyst blocks a REVIEW case | ANALYST | BLOCK |
| Analyst escalates a REVIEW case | ANALYST | ESCALATE |
| SLA expires and auto-resolves | SLA_TIMEOUT | ALLOW or BLOCK |
Analyst manual webhooks
Seção intitulada “Analyst manual webhooks”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.
| Event | Trigger | Synthetic assessment |
|---|---|---|
analyst_cautionary_hold_apply | Analyst applies a cautionary hold on a transaction | BLOCK (with the applied action in actions) |
analyst_cautionary_hold_clear | Analyst clears an active cautionary hold | ALLOW (with the clear action in actions) |
analyst_account_block_apply | Analyst applies a preventive block on an account | BLOCK (with the applied action in actions) |
analyst_account_block_clear | Analyst clears an active account block | ALLOW (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.
Payload Format
Seção intitulada “Payload Format”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 } } ]}Webhook Example: SLA Timeout Auto-Approval
Seção intitulada “Webhook Example: SLA Timeout Auto-Approval”{ "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": {} } ]}Headers
Seção intitulada “Headers”Every webhook request includes the following HTTP headers:
| Header | Description |
|---|---|
Content-Type | Always application/json |
X-Guardline-Delivery-ID | Stable UUID for this delivery, identical across retries. Use for deduplication |
X-Guardline-Attempt-Number | Sequential attempt number (1 for first delivery, 2 for first retry, etc.) |
X-Guardline-Timestamp | Unix timestamp of the signature moment (when HMAC is enabled) |
X-Guardline-Signature | HMAC-SHA256 signature in hexadecimal (when HMAC is enabled) |
Authorization | Bearer token (when OAuth is enabled) |
Webhook Authentication
Seção intitulada “Webhook Authentication”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.
| Mode | HMAC Signature | OAuth Bearer | Client Certificate |
|---|---|---|---|
| HMAC only (default) | Yes | No | No |
| OAuth 2.0 | Yes | Yes | No |
| mTLS | Yes | No | Yes |
| OAuth 2.0 + mTLS | Yes | Yes | Yes |
HMAC-SHA256 Authentication
Seção intitulada “HMAC-SHA256 Authentication”HMAC authentication uses a shared secret provisioned during integrator setup.
Verification process on the receiver:
- Extract the
X-Guardline-Timestampheader - Reject if the timestamp is older than 5 minutes relative to the server clock
- Concatenate timestamp and request body:
{timestamp}.{body} - Compute
HMAC-SHA256of the concatenation using the shared secret - Encode the result in hexadecimal
- Compare with the
X-Guardline-Signatureheader using constant-time comparison - 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)mTLS Authentication
Seção intitulada “mTLS Authentication”Mutual TLS authentication ensures Guardline’s identity at the transport layer, without requiring application-level validation.
Setup:
- During provisioning, Guardline provides the root CA certificate (
guardline-ca.pem) - The integrator configures their webhook server to require client certificates
- The integrator adds
guardline-ca.pemto the server’s trusted CA list - On each delivery, Guardline presents a client certificate signed by the root CA
- 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 2.0 Authentication
Seção intitulada “OAuth 2.0 Authentication”OAuth authentication allows Guardline to obtain an access token before each delivery, using the Client Credentials flow (RFC 6749, section 4.4).
Setup:
- The integrator provides during integration setup:
token_endpoint,client_id,client_secret, and optionallyscope - Before each delivery, Guardline requests a token from the provided endpoint
- 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}- Guardline includes the obtained token in the webhook authorization header:
Authorization: Bearer {access_token}- 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.
Endpoint Configuration
Seção intitulada “Endpoint Configuration”The webhook endpoint is configured during integration setup. Requirements:
| Requirement | Detail |
|---|---|
| Protocol | HTTPS required |
| TLS version | 1.2 or higher |
| Success response | Any 2xx code (body ignored) |
| Timeout | Respond within 10 seconds |
| Idempotency | Deduplicate 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.
Credential Rotation
Seção intitulada “Credential Rotation”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.
Retry Policy
Seção intitulada “Retry Policy”If Guardline does not receive an HTTP 2xx response, the webhook is retried with exponential backoff:
| Attempt | Delay After Failure |
|---|---|
| 1 | 5 seconds |
| 2 | 30 seconds |
| 3 | 2 minutes |
| 4 | 10 minutes |
| 5 | 30 minutes |
| 6 | 1 hour |
| 7 | 2 hours |
| 8 | 4 hours |
| 9 | 8 hours |
| 10 | 12 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.
Idempotency
Seção intitulada “Idempotency”Webhooks may be delivered more than once (due to retries after network issues). Use the X-Guardline-Delivery-ID header to deduplicate:
- Store each processed
X-Guardline-Delivery-ID. - On receiving a webhook, check if the delivery ID was already processed.
- If yes, respond
200 OKwithout reprocessing.
Managing Decisions
Seção intitulada “Managing Decisions”Retrieving a Decision
Seção intitulada “Retrieving a Decision”Retrieve the current state of a decision by its ID.
GET /api/v2/decisions/{id}Headers:
X-API-Key: gl_live_a1b2c3d4e5f6g7h8i9j0Response: Same envelope and decision payload structure as the analyze endpoint.
Cancelling a Decision in REVIEW
Seção intitulada “Cancelling a Decision in REVIEW”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}/cancelHeaders:
Content-Type: application/jsonX-API-Key: gl_live_a1b2c3d4e5f6g7h8i9j0Request:
{ "reason": "Client cancelled the transaction"}| Field | Type | Required | Description |
|---|---|---|---|
reason | string | yes | Cancellation 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
200if the case is successfully cancelled. - Returns
200if the case is already cancelled (idempotent). - Returns
409if the case has already been resolved by an analyst or by SLA timeout. - Only cases in
PENDINGorIN_PROGRESSstatus can be cancelled.
Notification Polling (Fallback)
Seção intitulada “Notification Polling (Fallback)”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.
Listing Pending Notifications
Seção intitulada “Listing Pending Notifications”GET /api/v2/decisions/notificationsHeaders:
X-API-Key: gl_live_a1b2c3d4e5f6g7h8i9j0Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
since | string | none | ISO 8601 timestamp. Only return notifications created after this time. |
status | string | none | Filter by status: pending, failed, or exhausted |
limit | integer | 50 | Maximum 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.
Acknowledging a Notification
Seção intitulada “Acknowledging a Notification”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}/ackHeaders:
X-API-Key: gl_live_a1b2c3d4e5f6g7h8i9j0Response (200 OK):
{ "error": false, "data": { "delivery_id": "aabbccdd-1122-3344-5566-778899001122", "acknowledged": true }}Behavior:
- Returns
200if successfully acknowledged. - Returns
200if already acknowledged (idempotent).
Integration Flows
Seção intitulada “Integration Flows”PIX Out: Direct Decision (ALLOW or BLOCK)
Seção intitulada “PIX Out: Direct Decision (ALLOW or 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) |Integrator responsibilities:
- If
ALLOW: authorize the PIX. - If
BLOCK: reject the PIX and execute anyactions(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.
PIX Out: Review Flow
Seção intitulada “PIX Out: Review Flow”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 thereview_infodata. - On webhook: execute the final decision (
ALLOWorBLOCK) and anyactions. - Use
review_info.estimated_resolution_minutesto 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 signaledactions(typicallyCAUTIONARY_HOLDon the credited amount and/orACCOUNT_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.
Error Handling
Seção intitulada “Error Handling”Error Response Format
Seção intitulada “Error Response Format”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"}HTTP Status Codes
Seção intitulada “HTTP Status Codes”| Code | Meaning |
|---|---|
| 200 | Success |
| 400 | Invalid request (malformed JSON, validation failure) |
| 401 | Authentication failed (invalid or missing API key) |
| 404 | Resource not found (decision ID does not exist) |
| 409 | Conflict (case already resolved, cannot cancel) |
| 429 | Rate limited (too many requests) |
| 500 | Internal server error |
Recommended Error Handling
Seção intitulada “Recommended Error Handling”- 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
transactionIdidempotency guarantees no duplicate processing.
Holiday Calendar
Seção intitulada “Holiday Calendar”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.
Endpoint
Seção intitulada “Endpoint”GET /api/v2/holidays?year=<int>Authentication
Seção intitulada “Authentication”Requires an API key with the holidays.read scope. Contact Guardline to enable this scope on your key.
Query Parameters
Seção intitulada “Query Parameters”| Parameter | Type | Required | Description |
|---|---|---|---|
year | integer | No | Year to filter. Defaults to the current year. Valid range: 2000 to 2100. |
Response
Seção intitulada “Response”{ "error": false, "data": { "items": [ { "date": "2026-12-25", "name": "Natal", "type": "NATIONAL", "created_at": "2025-01-01T00:00:00Z" } ], "total": 12 }}| Field | Type | Description |
|---|---|---|
data.items[].date | string | ISO 8601 date (YYYY-MM-DD) |
data.items[].name | string | Holiday display name (in Portuguese) |
data.items[].type | string | NATIONAL (federal holidays) or BANKING (bank-specific closures observed by the Brazilian banking system) |
data.items[].created_at | string | ISO 8601 timestamp when the entry was registered |
data.total | integer | Number of items returned |
Example
Seção intitulada “Example”GET /api/v2/holidays?year=2026 HTTP/1.1X-API-Key: gl_live_a1b2c3d4e5f6g7h8i9j0Caching
Seção intitulada “Caching”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.
Appendix A: SLA Reference
Seção intitulada “Appendix A: SLA Reference”Standard PIX Transaction
Seção intitulada “Standard PIX Transaction”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.
Intelligent Transfer (REVIEW Retention)
Seção intitulada “Intelligent Transfer (REVIEW Retention)”When a transaction is held for fraud analysis (REVIEW decision), the regulatory SLA depends on when the transaction was retained:
| Time of Retention | Maximum 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.
Cautionary Hold
Seção intitulada “Cautionary Hold”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.
Appendix B: Field Reference
Seção intitulada “Appendix B: Field Reference”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.
Analyze Request: instantPayment Object
Seção intitulada “Analyze Request: instantPayment Object”| Field | Type | Description |
|---|---|---|
keyType | string | PIX key type: cpf, cnpj, phone, email, evp |
keyValue | string | PIX key value |
endToEndId | string | End-to-end identifier from the SPI |
originalEndToEndId | string | Original E2E ID (for returns/reversals) |
reconciliationId | string | Reconciliation identifier (txid) |
initiationMethod | string | Initiation method (DICT, QRCODE, MANUAL) |
transactionPurpose | string | Transaction purpose code |
isQRCode | boolean | Whether initiated via QR code |
isScheduled | boolean | Whether this is a scheduled payment |
payer | object | Payer party data (see PixParty below) |
receiver | object | Receiver party data (see PixParty below) |
dict | object | DICT enrichment data (see below) |
Analyze Request: payer / receiver (PixParty)
Seção intitulada “Analyze Request: payer / receiver (PixParty)”| Field | Type | Description |
|---|---|---|
ispb | string | ISPB code of the institution |
ispbName | string | Institution name |
document | string | CPF or CNPJ |
branch | string | Branch number |
account | string | Account number |
name | string | Account holder name |
Analyze Request: dict Object
Seção intitulada “Analyze Request: dict Object”| Field | Type | Description |
|---|---|---|
keyCreationDate | string | ISO 8601 date when the PIX key was created |
keyOwnershipDate | string | ISO 8601 date when ownership was established |
accountType | string | Account type (CACC, SVGS, etc.) |
accountOpeningDate | string | ISO 8601 date when the account was opened |
pspName | string | PSP institution name |
pspIspb | string | PSP ISPB code |
fraudMarkersCount | integer | Number of fraud markers (infraction notifications) |
infractionCount | integer | Number of infractions |
lastFraudReportDate | string | ISO 8601 date of the last fraud report |
isFlagged | boolean | Whether the key is currently flagged |
flaggedSince | string | ISO 8601 date since when the key has been flagged |
claimsCount | integer | Number of ownership claims |
portabilityCount | integer | Number of portability events |
correlationId | string | R6 correlation identifier |
registeredAccounts | string | Number of accounts registered to this key holder |
lastMarkFraudDate | string | ISO 8601 date of the last fraud mark |
naturalPersonAntifraudPercentage | integer | Antifraud percentage for natural persons |
legalPersonAntifraudPercentage | integer | Antifraud percentage for legal persons |
spi | object | SPI statistics (see below) |
reports | object | Infraction reports (see below) |
frauds | array | Fraud entries by type (see below) |
Analyze Request: dict.spi Object
Seção intitulada “Analyze Request: dict.spi Object”| Field | Type | Description |
|---|---|---|
d90 | string | SPI transactions in the last 90 days |
m12 | string | SPI transactions in the last 12 months |
m60 | string | SPI transactions in the last 60 months |
Analyze Request: dict.reports Object
Seção intitulada “Analyze Request: dict.reports Object”| Field | Type | Description |
|---|---|---|
openReports | string | Number of open infraction reports |
distinctReports | string | Number of distinct reporting institutions |
rejectedD90 | string | Rejected transactions in the last 90 days |
rejectedM12 | string | Rejected transactions in the last 12 months |
rejectedM60 | string | Rejected transactions in the last 60 months |
Analyze Request: dict.frauds Array Items
Seção intitulada “Analyze Request: dict.frauds Array Items”| Field | Type | Description |
|---|---|---|
fraudType | string | Fraud type (e.g., SCAMMER_ACCOUNT, MULE_ACCOUNT) |
d90 | string | Occurrences in the last 90 days |
m12 | string | Occurrences in the last 12 months |
m60 | string | Occurrences in the last 60 months |
Analyze Request: customer Object
Seção intitulada “Analyze Request: customer Object”| Field | Type | Description |
|---|---|---|
age | integer | Customer age |
kycStatus | string | KYC status (approved, pending, rejected) |
kycLevel | string | KYC level (basic, intermediate, complete) |
riskScore | number | Pre-existing risk score |
riskLevel | string | Risk level (low, medium, high) |
isPEP | boolean | Politically Exposed Person flag |
country | string | Customer country (ISO 3166-1 alpha-2) |
accountAgeDays | integer | Account age in days |
accountStatus | string | Account status (active, suspended, blocked) |
hasNegativeBalance | boolean | Whether the account has negative balance |
isNewCustomer | boolean | Whether this is a recently onboarded customer |
Analyze Request: metadata Object
Seção intitulada “Analyze Request: metadata Object”| Field | Type | Description |
|---|---|---|
direction | string | Transaction direction: IN or OUT |
status | string | Transaction status in the originating system |
isInternational | boolean | Whether this is a cross-border transaction |
originSystem | string | Originating system identifier |
Analyze Request: device Object
Seção intitulada “Analyze Request: device Object”| Field | Type | Description |
|---|---|---|
id | string | Device identifier |
type | string | Device type (mobile, desktop, tablet) |
os | string | Operating system (android, ios, windows) |
isNewDevice | boolean | First time this device is seen |
isTrustedDevice | boolean | Device is in the trusted list |
hasScreenSharing | boolean | Screen sharing detected |
isEmulator | boolean | Emulator detected |
isRootedJailbroken | boolean | Rooted/jailbroken device detected |
ipAddress | string | Source IP address |
Analyze Request: counterPart Object
Seção intitulada “Analyze Request: counterPart Object”| Field | Type | Description |
|---|---|---|
name | string | Counterpart name |
taxIdentifier | object | { "taxId": "...", "country": "..." } |
isNewCounterpart | boolean | First transaction with this counterpart |
riskScore | number | Pre-existing risk score for the counterpart |
transactionsCount | integer | Historical transaction count with this counterpart |
isSanctionedEntity | boolean | Whether the counterpart is on a sanctions list |
isSameNetwork | boolean | Whether the counterpart is within the same network |
Endpoint Summary
Seção intitulada “Endpoint Summary”| Method | Path | Auth | Description |
|---|---|---|---|
| POST | /api/v2/decisions/analyze | API Key | Submit transaction for fraud analysis |
| GET | /api/v2/decisions/{id} | API Key | Retrieve a decision by ID |
| POST | /api/v2/decisions/{id}/cancel | API Key | Cancel a decision in REVIEW |
| GET | /api/v2/decisions/notifications | API Key | List undelivered notifications (polling) |
| POST | /api/v2/decisions/notifications/{delivery_id}/ack | API Key | Acknowledge a polled notification |
| GET | /api/v2/holidays | API Key (holidays.read) | Retrieve national and banking holidays for a given year |