Skip to main content
POST
/
transactions
Criar transação
curl --request POST \
  --url http://api.gu1.ai/transactions \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data '
{
  "externalId": "<string>",
  "type": "<string>",
  "amount": 123,
  "currency": "<string>",
  "exchangeRate": 123,
  "status": "<string>",
  "paymentMethod": "<string>",
  "description": "<string>",
  "category": "<string>",
  "transactedAt": "<string>",
  "executeRules": true,
  "asyncRules": true,
  "configRulesExecution": {},
  "validateExistingEntity": true,
  "riskMatrixId": [
    "<string>"
  ],
  "riskMatrixIds": [
    "<string>"
  ],
  "originEntityId": "<string>",
  "originExternalId": "<string>",
  "originTaxId": "<string>",
  "originName": "<string>",
  "originCountry": "<string>",
  "originDetails": {},
  "destinationEntityId": "<string>",
  "destinationExternalId": "<string>",
  "destinationTaxId": "<string>",
  "destinationName": "<string>",
  "destinationCountry": "<string>",
  "destinationDetails": {},
  "locationDetails": {},
  "deviceDetails": {},
  "channel": "<string>",
  "reason": "<string>",
  "timeZone": "<string>",
  "metadata": {}
}
'
import requests

url = "http://api.gu1.ai/transactions"

payload = {
"externalId": "<string>",
"type": "<string>",
"amount": 123,
"currency": "<string>",
"exchangeRate": 123,
"status": "<string>",
"paymentMethod": "<string>",
"description": "<string>",
"category": "<string>",
"transactedAt": "<string>",
"executeRules": True,
"asyncRules": True,
"configRulesExecution": {},
"validateExistingEntity": True,
"riskMatrixId": ["<string>"],
"riskMatrixIds": ["<string>"],
"originEntityId": "<string>",
"originExternalId": "<string>",
"originTaxId": "<string>",
"originName": "<string>",
"originCountry": "<string>",
"originDetails": {},
"destinationEntityId": "<string>",
"destinationExternalId": "<string>",
"destinationTaxId": "<string>",
"destinationName": "<string>",
"destinationCountry": "<string>",
"destinationDetails": {},
"locationDetails": {},
"deviceDetails": {},
"channel": "<string>",
"reason": "<string>",
"timeZone": "<string>",
"metadata": {}
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.text)
const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
externalId: '<string>',
type: '<string>',
amount: 123,
currency: '<string>',
exchangeRate: 123,
status: '<string>',
paymentMethod: '<string>',
description: '<string>',
category: '<string>',
transactedAt: '<string>',
executeRules: true,
asyncRules: true,
configRulesExecution: {},
validateExistingEntity: true,
riskMatrixId: ['<string>'],
riskMatrixIds: ['<string>'],
originEntityId: '<string>',
originExternalId: '<string>',
originTaxId: '<string>',
originName: '<string>',
originCountry: '<string>',
originDetails: {},
destinationEntityId: '<string>',
destinationExternalId: '<string>',
destinationTaxId: '<string>',
destinationName: '<string>',
destinationCountry: '<string>',
destinationDetails: {},
locationDetails: {},
deviceDetails: {},
channel: '<string>',
reason: '<string>',
timeZone: '<string>',
metadata: {}
})
};

fetch('http://api.gu1.ai/transactions', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));
<?php

$curl = curl_init();

curl_setopt_array($curl, [
CURLOPT_URL => "http://api.gu1.ai/transactions",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'externalId' => '<string>',
'type' => '<string>',
'amount' => 123,
'currency' => '<string>',
'exchangeRate' => 123,
'status' => '<string>',
'paymentMethod' => '<string>',
'description' => '<string>',
'category' => '<string>',
'transactedAt' => '<string>',
'executeRules' => true,
'asyncRules' => true,
'configRulesExecution' => [

],
'validateExistingEntity' => true,
'riskMatrixId' => [
'<string>'
],
'riskMatrixIds' => [
'<string>'
],
'originEntityId' => '<string>',
'originExternalId' => '<string>',
'originTaxId' => '<string>',
'originName' => '<string>',
'originCountry' => '<string>',
'originDetails' => [

],
'destinationEntityId' => '<string>',
'destinationExternalId' => '<string>',
'destinationTaxId' => '<string>',
'destinationName' => '<string>',
'destinationCountry' => '<string>',
'destinationDetails' => [

],
'locationDetails' => [

],
'deviceDetails' => [

],
'channel' => '<string>',
'reason' => '<string>',
'timeZone' => '<string>',
'metadata' => [

]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);

if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}
package main

import (
"fmt"
"strings"
"net/http"
"io"
)

func main() {

url := "http://api.gu1.ai/transactions"

payload := strings.NewReader("{\n \"externalId\": \"<string>\",\n \"type\": \"<string>\",\n \"amount\": 123,\n \"currency\": \"<string>\",\n \"exchangeRate\": 123,\n \"status\": \"<string>\",\n \"paymentMethod\": \"<string>\",\n \"description\": \"<string>\",\n \"category\": \"<string>\",\n \"transactedAt\": \"<string>\",\n \"executeRules\": true,\n \"asyncRules\": true,\n \"configRulesExecution\": {},\n \"validateExistingEntity\": true,\n \"riskMatrixId\": [\n \"<string>\"\n ],\n \"riskMatrixIds\": [\n \"<string>\"\n ],\n \"originEntityId\": \"<string>\",\n \"originExternalId\": \"<string>\",\n \"originTaxId\": \"<string>\",\n \"originName\": \"<string>\",\n \"originCountry\": \"<string>\",\n \"originDetails\": {},\n \"destinationEntityId\": \"<string>\",\n \"destinationExternalId\": \"<string>\",\n \"destinationTaxId\": \"<string>\",\n \"destinationName\": \"<string>\",\n \"destinationCountry\": \"<string>\",\n \"destinationDetails\": {},\n \"locationDetails\": {},\n \"deviceDetails\": {},\n \"channel\": \"<string>\",\n \"reason\": \"<string>\",\n \"timeZone\": \"<string>\",\n \"metadata\": {}\n}")

req, _ := http.NewRequest("POST", url, payload)

req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")

res, _ := http.DefaultClient.Do(req)

defer res.Body.Close()
body, _ := io.ReadAll(res.Body)

fmt.Println(string(body))

}
HttpResponse<String> response = Unirest.post("http://api.gu1.ai/transactions")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"externalId\": \"<string>\",\n \"type\": \"<string>\",\n \"amount\": 123,\n \"currency\": \"<string>\",\n \"exchangeRate\": 123,\n \"status\": \"<string>\",\n \"paymentMethod\": \"<string>\",\n \"description\": \"<string>\",\n \"category\": \"<string>\",\n \"transactedAt\": \"<string>\",\n \"executeRules\": true,\n \"asyncRules\": true,\n \"configRulesExecution\": {},\n \"validateExistingEntity\": true,\n \"riskMatrixId\": [\n \"<string>\"\n ],\n \"riskMatrixIds\": [\n \"<string>\"\n ],\n \"originEntityId\": \"<string>\",\n \"originExternalId\": \"<string>\",\n \"originTaxId\": \"<string>\",\n \"originName\": \"<string>\",\n \"originCountry\": \"<string>\",\n \"originDetails\": {},\n \"destinationEntityId\": \"<string>\",\n \"destinationExternalId\": \"<string>\",\n \"destinationTaxId\": \"<string>\",\n \"destinationName\": \"<string>\",\n \"destinationCountry\": \"<string>\",\n \"destinationDetails\": {},\n \"locationDetails\": {},\n \"deviceDetails\": {},\n \"channel\": \"<string>\",\n \"reason\": \"<string>\",\n \"timeZone\": \"<string>\",\n \"metadata\": {}\n}")
.asString();
require 'uri'
require 'net/http'

url = URI("http://api.gu1.ai/transactions")

http = Net::HTTP.new(url.host, url.port)

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"externalId\": \"<string>\",\n \"type\": \"<string>\",\n \"amount\": 123,\n \"currency\": \"<string>\",\n \"exchangeRate\": 123,\n \"status\": \"<string>\",\n \"paymentMethod\": \"<string>\",\n \"description\": \"<string>\",\n \"category\": \"<string>\",\n \"transactedAt\": \"<string>\",\n \"executeRules\": true,\n \"asyncRules\": true,\n \"configRulesExecution\": {},\n \"validateExistingEntity\": true,\n \"riskMatrixId\": [\n \"<string>\"\n ],\n \"riskMatrixIds\": [\n \"<string>\"\n ],\n \"originEntityId\": \"<string>\",\n \"originExternalId\": \"<string>\",\n \"originTaxId\": \"<string>\",\n \"originName\": \"<string>\",\n \"originCountry\": \"<string>\",\n \"originDetails\": {},\n \"destinationEntityId\": \"<string>\",\n \"destinationExternalId\": \"<string>\",\n \"destinationTaxId\": \"<string>\",\n \"destinationName\": \"<string>\",\n \"destinationCountry\": \"<string>\",\n \"destinationDetails\": {},\n \"locationDetails\": {},\n \"deviceDetails\": {},\n \"channel\": \"<string>\",\n \"reason\": \"<string>\",\n \"timeZone\": \"<string>\",\n \"metadata\": {}\n}"

response = http.request(request)
puts response.read_body
{
  "transaction": {},
  "rulesExecutionSummary": {},
  "asyncRules": true,
  "rulesEvaluationStatus": "<string>"
}

Visão geral

Cria uma nova transação. Com executeRules: true (padrão), o motor de regras roda de forma síncrona e a resposta inclui rulesExecutionSummary completo quando as regras terminam na mesma request. Sem enviar asyncRules (padrão false), o comportamento permanece o mesmo — integrações existentes não mudam.

Endpoint

POST http://api.gu1.ai/transactions

Autenticação

Requer uma API key válida no header Authorization:
Authorization: Bearer YOUR_API_KEY

Parâmetros de query

asyncRules
boolean
default:"false"
Com true e executeRules diferente de false, a transação é criada na hora e a avaliação de regras é enfileirada em background. A resposta HTTP retorna antes das regras terminarem. O query param tem precedência sobre o mesmo campo no body JSON.Valores truthy aceitos: true, 1, "true", "1", "yes".Não se aplica a endpoints batch — apenas POST /transactions (criação unitária).

Corpo da requisição

Campos obrigatórios

externalId
string
required
Seu identificador único para esta transação no seu sistema
type
string
required
Tipo da transação. Opções:
  • PAYMENT - Pagamento
  • TRANSFER - Transferência
  • WITHDRAWAL - Saque
  • DEPOSIT - Depósito
  • REFUND - Reembolso
  • CHARGEBACK - Chargeback
  • REVERSAL - Estorno
  • FEE - Taxa
  • ADJUSTMENT - Ajuste
  • OTHER - Outro
amount
number
required
Valor (deve ser zero ou positivo)
currency
string
required
Código da moeda (3-4 caracteres, ex.: “USD”, “EUR”, “BRL”)
exchangeRate
number
Taxa de câmbio opcional, usada somente quando a conversão automática para a moeda base da organização não está disponível (erro do provedor, timeout ou par não suportado). Se omitir este campo, o comportamento permanece o mesmo — o Gueno consulta o serviço de moedas como hoje.Semântica: unidades da moeda base por 1 unidade de currency. Valor normalizado na moeda base da org: valorNormalizado = amount × exchangeRate.Ignorada quando a conversão automática tem sucesso (prevalece a taxa do provedor).Necessária quando a conversão automática não está disponível para moedas não conversíveis (ver abaixo). Ver Conversão de moeda.

Campos opcionais

status
string
default:"CREATED"
Status. Opções: CREATED, PROCESSING, SUSPENDED, SENT, EXPIRED, DECLINED, REFUNDED, SUCCESSFUL
paymentMethod
string
Método de pagamento. Opções: CARD, ACH, PIX, TED, BOLETO, WALLET, SWIFT, IBAN, CBU, CVU, DEBIN, etc.
description
string
Descrição ou notas
category
string
Categoria da transação
transactedAt
string
Data/hora ISO 8601 do fato (padrão: momento da criação). Gravado em UTC. Use Z ou offset ±HH:MM no string, ou datetime sem offset junto com timeZone (horário local nesse fuso).
executeRules
boolean
default:"true"
Se o motor de regras deve rodar. Com false, pula regras por completo (sync e async).
asyncRules
boolean
default:"false"
Mesma semântica do query asyncRules. Para ingestão em alto volume: persistir a transação rápido e revisar alertas depois no gu1. Requer executeRules: true (padrão). Ignorado se executeRules for false.
configRulesExecution
object
Ajuste opcional da execução de regras após a criação (sync ou async). Não desativa ações createAlert nem a consolidação de investigações.
CampoTipoPadrão
notificationsbooleantrue na maioria das organizações; false na Paytime prod (3bc1f621-27d4-423e-9d64-86680bec2388) quando omitido
Com notifications: false, o gu1 não envia notificações in-app da avaliação de regras (matriz de risco / mudanças de status). Alertas e investigações seguem o fluxo normal.Legacy KYT POST /legacy/kyt/verifyTransaction: mesmo objeto no body Gu2 como configRulesExecution; se omitido, Paytime prod recebe notifications: false por padrão (igual a POST /transactions).
validateExistingEntity
boolean
default:"false"
Com false (padrão): se você enviar originExternalId / destinationExternalId (ou tax na raiz) e não houver entidade, a transação ainda é criada (sem vínculo), como antes.Com true: cada lado (origem / destino) só é validado se você enviar pelo menos um identificador daquele lado (originEntityId, originExternalId ou originTaxId; o mesmo para destino). Cada campo enviado deve resolver para uma pessoa/empresa existente na organização; caso contrário a API retorna 400 com INVALID_ENTITY_REFERENCES e não cria a transação. Se não enviar identificadores de origem (ou destino), esse lado não é validado.

Matrizes de risco (opcional)

riskMatrixId
string | string[]
Compatível com clientes antigos: um UUID ou um array de UUIDs de matrizes da organização. Se enviar lista não vazia, apenas regras ativas ligadas a essas matrizes são avaliadas (sem misturar com regras “soltas” só por triggers). Omita riskMatrixId e riskMatrixIds para manter o comportamento histórico por triggers.
riskMatrixIds
string[]
Preferido para várias matrizes: lista ordenada de UUIDs. Tem precedência sobre riskMatrixId quando informado e não vazio.

Origem (entidade)

Como a origem é vinculada no gu1 (em ordem; para no primeiro sucesso):
  1. ID da entidade — com originEntityId, a transação usa essa entidade (deve existir na org).
  2. ID externo — sem originEntityId, com originExternalId, se houver pessoa/empresa com o mesmo externalId, a transação vincula automaticamente.
  3. Terceiro fallback: documento / tax ID (raiz) — ainda sem vínculo, com originTaxId no raiz do corpo, o API procura pessoa/empresa cujo taxId coincida após normalizar (apenas letras e números, ignorando pontuação; comparação em maiúsculas no match).
Nos passos 2 e 3, o API preenche originEntityId e, se você não enviou, pode preencher name e country a partir da entidade.Denormalização canônica (origem vinculada): quando a origem está vinculada a pessoa/empresa — você enviou originEntityId, ou o auto-link resolveu por originExternalId / originTaxId — o gu1 sincroniza as colunas denormalizadas a partir da entidade antes do insert:
Campo na transaçãoOrigem na entidadeValor do cliente é mantido?
originEntityIdentities.idDefinido no auto-link; inalterado se você já enviou UUID válido
originTaxIdentities.tax_idNão — sempre sobrescrito pela entidade vinculada
originExternalIdentities.external_idNão — sempre sobrescrito pela entidade vinculada
Se a entidade não tem taxId ou externalId, a coluna correspondente na transação fica null, mesmo que você tenha enviado valores no body.Nota para integradores: você pode enviar qualquer combinação de identificadores para vincular (precedência: originEntityIdoriginExternalIdoriginTaxId). Após o vínculo, originTaxId / originExternalId persistidos refletem a entidade no gu1, não necessariamente o que digitou. Isso alinha regras transacionais com eventos de usuário.Sem match, a transação é criada mesmo assim, com os campos enviados, sem vínculo.
(originDetails.taxId ajuda no grafo mas não vincula entidade; use originTaxId na raiz para vincular por documento.)
originEntityId
string
UUID da entidade de origem no gu1
originExternalId
string
Seu ID externo da entidade de origem. Segundo critério de vínculo sem originEntityId. Após vincular, o valor gravado é entities.external_id (valor do cliente não é mantido se diferir).
originTaxId
string
CPF/CNPJ ou outro tax ID de origem no raiz da requisição. Terceiro critério após originEntityId e originExternalId. Comparação com entity.taxId de forma normalizada. Se achar, preenche vínculo, nome e país. Após vincular, gravado como entities.tax_id. Opcional, máx. 50 caracteres.
originName
string
Nome da origem
originCountry
string
Código de país ISO 2 da origem (ex.: “US”, “BR”, “AR”)
originDetails
object
Detalhes da origem (dispositivo, conta, etc.). Ver Schema de payment details. Campos extras permitidos. Se a origem não for uma entidade no gu1, envie identificadores em originDetails.paymentDetails para agrupar nós pseudo (taxId, cbu, cvu, pixKey, clabe, alias, iban, holderId, debinId, cardFingerprint, accountNumber + bankCode opcional — ver prioridade no schema).

Destino (entidade)

Vínculo do destino: mesma precedência da origem: destinationEntityIddestinationExternalIddestinationTaxId.Com destino vinculado, o gu1 sempre sincroniza destinationTaxId e destinationExternalId a partir da entidade (mesmas regras da origem). Sem vínculo, mantém os valores enviados.
destinationEntityId
string
UUID da entidade de destino no gu1
destinationExternalId
string
Seu ID externo da entidade de destino. Após vincular, gravado como entities.external_id.
destinationTaxId
string
Tax / documento do destino no raiz; terceiro fallback depois de destinationEntityId e destinationExternalId. Mesma regra de originTaxId. Após vincular, gravado como entities.tax_id. Opcional, máx. 50 caracteres.
destinationName
string
Nome do destino
destinationCountry
string
Código de país ISO 2 do destino
destinationDetails
object
Detalhes do destino (comerciante, conta, etc.). Campos opcionais; extras permitidos. Se o destino não for uma entidade no gu1, envie os mesmos identificadores em destinationDetails.paymentDetails para agrupar nós pseudo (mesma prioridade que origem — ver Payment Details Schema).

Localização e dispositivo

locationDetails
object
Localização: country, city, region, address, latitude, longitude, postalCode, etc.
deviceDetails
object
Dispositivo: deviceId, platform, osName, model, ipAddress, isVpn, isTor, etc.
channel
string
Canal (máx. 50 caracteres): mobile_app, web_browser, pos_terminal, api, atm, etc.
reason
string
Motivo do resultado (opcional). Ver Enum de motivos. Se omitido, usa WITHOUT_REASON.
timeZone
string
Fuso horário IANA opcional (independente de operationalHours da entidade). Valores de transaction_time_zone. Se omitido, fica null.Normalização de transactedAt: se transactedAt tiver Z (como exige o validador deste endpoint), esse instante é gravado em UTC; timeZone é metadata opcional e não entra no parse. Com datetime local + timeZone (ferramentas internas/lote), a API pode converter horário local para UTC. Integrações que não enviam timeZone continuam como antes. Regras de horário operacional usam o instante gravado + operationalHours.timezone da entidade, não transaction.timeZone.Lista completa: Enum fuso horário.
metadata
object
Metadados adicionais: tags, purpose, enhanced_due_diligence, block_reason, compliance_alert, etc.

Resposta

transaction
object
A transação criada (objeto). Inclui: id, externalId, organizationId, type, amount (string), currency, status, riskScore (string), flagged, channel, reason, timeZone (string | null), originDetails, destinationDetails, locationDetails, deviceDetails, processingTimeMs, processedAt, transactedAt, createdAt, updatedAt.
rulesExecutionSummary
object
Presente quando executeRules é true.Síncrono (padrão): completo após as regras terminarem na mesma request.Async (asyncRules=true): placeholder com success: true, rulesHit / rulesNoHit vazios e matchedRulesCount: 0. Alertas e score atualizam quando o processamento em background termina.Omitido se executeRules for false. Ver Resumo de Execução de Regras.
asyncRules
boolean
Presente e true apenas quando as regras foram enfileiradas. Omitido no fluxo síncrono padrão.
rulesEvaluationStatus
string
No modo async: "queued". Omitido quando as regras rodaram de forma síncrona.

Exemplo básico

curl -X POST http://api.gu1.ai/transactions \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "externalId": "txn_12345",
    "type": "PAYMENT",
    "amount": 150.50,
    "currency": "USD",
    "originExternalId": "customer_001",
    "destinationExternalId": "merchant_456",
    "description": "Compra online"
  }'
const response = await fetch('http://api.gu1.ai/transactions', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    externalId: 'txn_12345',
    type: 'PAYMENT',
    amount: 150.50,
    currency: 'USD',
    originExternalId: 'customer_001',
    destinationExternalId: 'merchant_456',
    description: 'Compra online'
  })
});
const data = await response.json();
console.log(data.transaction);
import requests
response = requests.post(
    'http://api.gu1.ai/transactions',
    headers={
        'Authorization': 'Bearer YOUR_API_KEY',
        'Content-Type': 'application/json'
    },
    json={
        'externalId': 'txn_12345',
        'type': 'PAYMENT',
        'amount': 150.50,
        'currency': 'USD',
        'originExternalId': 'customer_001',
        'destinationExternalId': 'merchant_456',
        'description': 'Compra online'
    }
)
transaction = response.json()['transaction']
print(transaction)

Regras async (ingestão em alto volume)

Para respostas rápidas e revisar alertas depois no gu1. As regras rodam em background; rulesExecutionSummary.rulesHit vem vazio na resposta HTTP.
curl -X POST "http://api.gu1.ai/transactions?asyncRules=true" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "externalId": "txn_nightly_001",
    "type": "PAYMENT",
    "amount": 150.50,
    "currency": "BRL",
    "destinationExternalId": "merchant_456"
  }'
{
  "transaction": { "id": "...", "externalId": "txn_nightly_001", "status": "SUCCESSFUL" },
  "rulesExecutionSummary": {
    "success": true,
    "rulesHit": [],
    "rulesNoHit": [],
    "totalScore": 0,
    "matchedRulesCount": 0,
    "executionTimeMs": 0
  },
  "asyncRules": true,
  "rulesEvaluationStatus": "queued"
}
Não use a resposta síncrona para aprovar ou bloquear pagamentos quando asyncRules=true. Não há segundo webhook ao terminar as regras em background — monitore alertas no gu1 ou consulte APIs de transação/investigação.

Conversão de moeda

Quando currency difere da moeda base da organização (padrão USD), o Gueno busca a taxa automaticamente. O comportamento não muda se você omitir exchangeRate.

Ordem de resolução

EtapaCondiçãoResultado
1currency igual à baserateSource: no-conversion, exchangeRate: 1
2Conversão automática com sucessoTaxa do provedor (ms-provider, cache, etc.)
3Conversão falha e você enviou exchangeRaterateSource: client-provided
4Conversão falha, sem exchangeRaterateSource: conversion-unavailable; sem valor normalizado na moeda base

Semântica de exchangeRate

  • Direção: unidades da moeda base por 1 unidade de currency (igual às taxas do provedor).
  • Fórmula: valorNormalizado = amount × exchangeRate (persistido na moeda base da org).
  • Não é override: se a etapa 2 tiver sucesso, exchangeRate do cliente é ignorado.

Moedas não conversíveis (conversão automática)

O Gueno não obtém taxa de câmbio automática para estes códigos hoje. A conversão automática fica unavailable salvo se você enviar exchangeRate:
MoedaCódigoNotas
WorldcoinWLDO cliente deve enviar exchangeRate para valor normalizado na base
EthereumETHO cliente deve enviar exchangeRate para valor normalizado na base
Demais códigos ISO seguem o fluxo automático usual (provedor ou histórico com transactedAt). Envie exchangeRate se precisar de valor normalizado na base para regras e relatórios.

Exemplo — WLD com taxa do cliente

{
  "externalId": "txn-wld-001",
  "type": "PAYMENT",
  "amount": 26.16,
  "currency": "WLD",
  "exchangeRate": 2.41,
  "destinationExternalId": "merchant_001"
}
Resposta (base USD — valor normalizado 63.05, rateSource: client-provided):
{
  "transaction": {
    "amount": "26.16",
    "currency": "WLD",
    "exchangeRate": "2.41",
    "rateSource": "client-provided",
    "currenciesExchange": [
      { "currency": "USD", "exchangeRate": 2.41, "value": 63.05 }
    ]
  }
}
O batch (POST /transactions/batch, upload, JSON) aceita o mesmo exchangeRate opcional em cada linha, com a mesma semântica.
Com Redis configurado, os jobs vão para a fila transaction-rules-eval (workers dedicados se DISABLE_INPROCESS_BULL_WORKERS=true). Se Redis não existir ou o enqueue falhar, a API ainda responde 200 com asyncRules: true e executa as regras no processo dessa instância (adequado para dev ou instância única; alto volume multi-instância: Redis + workers).

Exemplo de resposta

{
  "transaction": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "externalId": "txn_67890",
    "organizationId": "8e2f89ab-c216-4eb4-90eb-ca5d44499aaa",
    "type": "TRANSFER",
    "status": "CREATED",
    "amount": "1000.00",
    "currency": "BRL",
    "amountInUsd": "1000.00",
    "paymentMethod": "PIX",
    "riskScore": "15",
    "flagged": false,
    "channel": "mobile_app",
    "reason": "WITHOUT_REASON",
    "originDetails": {},
    "destinationDetails": {},
    "processingTimeMs": "120",
    "processedAt": "2024-10-03T14:30:00.000Z",
    "createdAt": "2024-10-03T14:30:00.000Z",
    "updatedAt": "2024-10-03T14:30:00.000Z"
  },
  "rulesExecutionSummary": {
    "rulesHit": [],
    "rulesNoHit": [],
    "actionsExecuted": {},
    "totalScore": 15
  }
}

Erros

400 - Dados inválidos

{
  "success": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Validation failed",
    "details": ["Amount must be zero or a positive number", "Currency must be at least 3 characters"]
  }
}

409 - Transação duplicada

{
  "success": false,
  "error": {
    "code": "DUPLICATE_TRANSACTION",
    "message": "Transaction with this external_id already exists",
    "details": { "field": "external_id", "value": "txn_12345" }
  }
}

429 - Limite de taxa

{
  "error": "Rate limit exceeded",
  "code": "RATE_LIMIT_EXCEEDED",
  "retryAfter": 3600
}

Próximos passos