This guide explains how to integrate external systems with Tracer, including the payload requirements, integration flow, and best practices for achieving optimal performance.
Integration overview
Tracer is designed to be called by authorization systems (payment gateways, workflow orchestrators, or transaction processors) that need real-time validation decisions. The integration follows a simple request-response pattern:
Key principle: Tracer does not fetch external data during validation. Your system is responsible for providing all context needed for rule evaluation.
Payload-Complete Pattern
Tracer uses the Payload-Complete Pattern, which means all context required for validation must be included in the request. This design ensures:
| Benefit | Description |
|---|
| Predictable latency | No external calls during validation; response time stays under 80ms |
| Simplicity | Single request contains everything needed for decision |
| Reliability | No dependency on external services during validation |
| Flexibility | Your system controls data freshness and enrichment logic |
Your responsibilities
As the integrating system, you are responsible for:
- Enriching the payload with account, segment, portfolio, and merchant data before calling Tracer
- Providing accurate context for rule and limit evaluation—Tracer cannot fetch missing data
- Handling the decision (ALLOW, DENY, or REVIEW) appropriately in your workflow
- Implementing retry logic if Tracer is temporarily unavailable
- Managing review workflows when Tracer returns
REVIEW—Tracer does not include case management
Tracer validates what you send. If your payload is missing context (e.g., account status, segment membership), rules that depend on that data cannot evaluate correctly. Always ensure payloads are complete before submission.
Tracer’s responsibilities
Tracer is responsible for:
- Evaluating rules against the provided context
- Checking limits against current usage
- Recording audit trail for compliance
- Returning decision with detailed information
Integration flow
Step 1: Prepare the transaction context
Before calling Tracer, gather all relevant data from your systems:
Step 2: Call Tracer API
Send a POST request to /v1/validations with the complete context:
POST /v1/validations
X-API-Key: {your_api_key}
Content-Type: application/json
{
"requestId": "unique-request-uuid",
"transactionType": "CARD",
"subType": "debit",
"amount": 150000,
"currency": "BRL",
"transactionTimestamp": "2026-01-30T10:30:00Z",
"account": {
"accountId": "acc-uuid-123",
"type": "checking",
"status": "active"
},
"segment": {
"segmentId": "segment-uuid-456"
},
"portfolio": {
"portfolioId": "portfolio-uuid-789"
},
"merchant": {
"merchantId": "merchant-uuid-abc",
"category": "5411",
"country": "BR"
},
"metadata": {
"channel": "MOBILE_APP",
"deviceId": "device-xyz"
}
}
Step 3: Handle the response
Process the decision based on the response:
{
"requestId": "unique-request-uuid",
"validationId": "val-uuid-generated",
"decision": "ALLOW",
"reason": "Transaction approved",
"matchedRuleIds": [],
"evaluatedRuleIds": ["rule-1", "rule-2"],
"limitUsageDetails": [
{
"limitId": "limit-uuid",
"limitAmount": 5000000,
"currentUsage": 1650000,
"exceeded": false
}
],
"processingTimeMs": 23
}
Decision handling:
| Decision | Action |
|---|
ALLOW | Proceed with the transaction |
DENY | Reject the transaction; show reason to user if appropriate |
REVIEW | Queue for manual review in your review system |
Request fields
Required fields
| Field | Type | Description |
|---|
requestId | UUID | Client-generated unique ID for idempotency |
transactionType | enum | CARD, WIRE, PIX, or CRYPTO |
amount | int64 | Transaction amount in smallest currency unit (e.g., centavos for BRL) |
currency | string | ISO 4217 code (e.g., BRL, USD). Must be uppercase |
transactionTimestamp | datetime | Transaction timestamp in RFC3339 format with timezone |
account | object | Account context (at minimum, accountId is required) |
Optional fields
| Field | Type | Description |
|---|
subType | string | Transaction subtype (e.g., “debit”, “credit”, “instant”) |
segment | object | Segment context for scope matching |
portfolio | object | Portfolio context for scope matching |
merchant | object | Merchant context (recommended for card transactions) |
metadata | object | Custom key-value pairs for rule expressions |
Account object
| Field | Type | Required | Description |
|---|
accountId | UUID | Yes | Account identifier |
type | string | No | Account type: checking, savings, credit |
status | string | No | Account status: active, suspended, closed |
Merchant object
| Field | Type | Required | Description |
|---|
merchantId | UUID | Yes (if merchant provided) | Merchant identifier |
category | string | No | MCC code (4 digits) |
country | string | No | ISO 3166-1 alpha-2 (e.g., BR, US) |
riskLevel | string | No | Risk classification |
Use metadata for custom fields that your rules need to evaluate:
{
"metadata": {
"channel": "MOBILE_APP",
"deviceId": "device-abc123",
"isFirstPurchase": true,
"customerTier": "gold"
}
}
Metadata keys must be alphanumeric with underscores only, maximum 64 characters. Maximum 50 entries per request.
Timeout budget
Tracer is designed to respond in under 80ms (p99). Configure your client timeout accordingly:
| Configuration | Recommended value |
|---|
| Client timeout | 100ms |
| Connection timeout | 50ms |
| Read timeout | 100ms |
Retry strategy
Implement retry logic for transient failures:
On 5xx error or timeout:
- Wait 10ms
- Retry once
- If still failing, apply fallback policy
Do not retry on 4xx errors—these indicate invalid requests that will fail again.
Fallback behavior
Decide what happens when Tracer is unavailable:
| Strategy | When to use |
|---|
| Fail-open | Allow transaction if Tracer is down (prioritize availability) |
| Fail-closed | Deny transaction if Tracer is down (prioritize security) |
| Queue for review | Queue transaction for manual review |
Your choice depends on your risk tolerance and business requirements.
Data freshness
Since you control the payload enrichment, data freshness is your responsibility. Tracer trusts the data you provide and cannot detect stale information.
| Data type | Freshness recommendation | Risk if stale |
|---|
| Account status | Real-time or near real-time | Transactions on suspended accounts may be allowed |
| Segment membership | Can be cached (changes infrequently) | Wrong limits or rules may apply |
| Portfolio assignment | Can be cached (changes infrequently) | Incorrect scope matching |
| Merchant data | Can be cached with periodic refresh | Risk rules may not trigger correctly |
Stale data leads to incorrect decisions. If an account was suspended but your cache shows it as active, Tracer will allow transactions that should be denied. Your enrichment layer is the source of truth for Tracer.
All datetime fields must use RFC3339 format with mandatory timezone:
Valid formats:
2026-01-30T10:30:00Z (UTC)
2026-01-30T10:30:00-03:00 (São Paulo timezone)
2026-01-30T00:00:00+00:00 (UTC explicit)
Invalid formats:
2026-01-30 (date only - rejected)
2026-01-30T10:30:00 (missing timezone - rejected)
Error handling
HTTP status codes
| Status | Meaning | Action |
|---|
200 | Success | Process the decision |
400 | Invalid request | Fix the request payload |
401 | Authentication failed | Check your API Key |
413 | Payload too large | Reduce payload size (max 100KB) |
500 | Server error | Retry with backoff |
503 | Service unavailable | Retry with backoff |
504 | Timeout | Retry or apply fallback |
Common errors
| Error | Cause | Resolution |
|---|
| Missing required field | Field not provided | Include all required fields |
| Invalid currency code | Lowercase or invalid code | Use uppercase ISO 4217 (BRL, USD) |
| Invalid timestamp | Wrong format | Use RFC3339 with timezone |
| Payload too large | Request > 100KB | Reduce metadata size |
Integration checklist
Before going to production, verify:
Example integration (pseudocode)
def validate_transaction(transaction):
# Step 1: Enrich payload
payload = {
"requestId": generate_uuid(),
"transactionType": transaction.type,
"amount": transaction.amount,
"currency": transaction.currency.upper(),
"timestamp": now_rfc3339(),
"account": get_account_context(transaction.account_id),
"segment": get_segment_context(transaction.segment_id),
"merchant": get_merchant_context(transaction.merchant_id),
"metadata": transaction.custom_fields
}
# Step 2: Call Tracer
try:
response = http_post(
url="https://tracer.example.com/v1/validations",
headers={"X-API-Key": API_KEY},
json=payload,
timeout_ms=100
)
except Timeout:
return apply_fallback_policy()
except ServerError:
return retry_once_or_fallback()
# Step 3: Handle decision
if response.decision == "ALLOW":
return proceed_with_transaction()
elif response.decision == "DENY":
return reject_transaction(response.reason)
elif response.decision == "REVIEW":
return queue_for_manual_review(response.validationId)
Next steps