Letztech

API Letztech — Documentação para Parceiros

Referência de integração para marketplaces parceiros: criação de cobranças via Pix e Boleto, e consulta de status de uma transação. Cobre apenas os endpoints acessíveis via API key de marketplace (HTTP Basic Auth).

Base URL: https://api.letztech.com.br

Postman collection

Baixe a collection completa do Postman com todos os endpoints desta documentação já montados (autenticação HTTP Basic, headers de idempotência e exemplos de corpo prontos). Importe no Postman via Import → File e preencha as variáveis da collection.

Variáveis a preencher: apiKey, marketplaceId e sellerId (on_behalf_of). O baseUrl já vem preenchido com https://api.letztech.com.br, e o id da transação criada é salvo automaticamente em transactionId para reuso nas chamadas de consulta, refund e páginas públicas.

0. Antes de começar — API key e marketplaceId

Para autenticar, você precisa de dois valores, ambos obtidos dentro do painel Letztech (https://letztech.com.br/login), não por esta documentação:

  • API key: um segredo gerado no painel, com confirmação por código enviado por e-mail (MFA). O valor em texto puro só é mostrado uma vez, no momento em que é gerado — a API guarda só um hash, sem como recuperá-lo depois. Se perder, gere outra: a chave anterior continua valendo por 24 horas, para você trocar sem parar a integração, e então deixa de funcionar. Gerar de novo em menos de 1 minuto é recusado (409).
  • marketplaceId: é o dono da chave, o mesmo identificador exibido/copiável no painel. Vai na URL de cada chamada (:marketplaceId), não é um dado secreto.

Há dois tipos de chave:

ChaveOnde gerarmarketplaceIdOpera
De sellerTela inicial do seller (/dashboard/seller)id do sellerSó esse seller
De revendaPainel da revenda, tela Integração (só o dono da revenda)id da revendaTodos os sellers da revenda, indicados em on_behalf_of

A conta precisa estar active (aprovada) para gerar uma chave. As duas chaves convivem: o seller de uma revenda pode ter a própria chave, e a revenda a dela.

Chave de revenda

  • on_behalf_of aceita qualquer seller da revenda. Um seller de outra revenda, ou que não existe, retorna 404.
  • A revenda consulta e devolve qualquer transação dos sellers dela feita com o preço da revenda, inclusive as criadas pela chave do próprio seller. Fora disso, 404.
  • Com a revenda suspensa, a chave dela não cria cobranças (403), mas continua consultando e devolvendo.
  • Os compradores (customer) criados com a chave da revenda são da revenda e servem para todos os sellers dela; não aparecem para a chave do seller, e vice-versa.
Não existe hoje um ambiente de sandbox para o parceiro testar sem movimentar dinheiro de verdade — toda chamada desta documentação é contra produção.

1. Autenticação

Todas as chamadas usam HTTP Basic Auth, com a API key do marketplace como usuário e senha vazia:

Authorization: Basic base64("<API_KEY>:")

A API key é vinculada a um marketplaceId específico (o dono da chave, um seller ou uma revenda). Toda chamada cujo :marketplaceId na URL não corresponda à API key usada retorna 403.

SituaçãoStatus
Header ausente ou malformado401
API key inválida, revogada, inativa ou anterior já fora das 24h401
marketplaceId da URL não pertence à API key403

2. Idempotência

Envie o header X-Idempotency-Key (qualquer string única por tentativa lógica) em toda chamada de criação. Reenvios com a mesma chave e mesmo payload retornam o resultado original, sem duplicar a cobrança.

Além disso, o campo reference_id (obrigatório) funciona como chave de deduplicação por seller: reenviar o mesmo reference_id para o mesmo on_behalf_of devolve a transação já criada, sem criar outra cobrança. Vale para as duas chaves: se a revenda e o seller usarem o mesmo reference_id para o mesmo seller, recebem a mesma transação. O mesmo reference_id em sellers diferentes cria cobranças diferentes. Se a transação já criada não puder ser vista por quem reenviou (por exemplo, a revenda reenviando um reference_id que o seller usou antes de entrar nela), a resposta é 409 Conflict, sem dados da transação.

3. Rate limit

Por chave, a cada minuto:

ChaveLimite
De seller300 requisições
De revenda1.200 requisições no total, e no máximo 300 criações de cobrança por seller (on_behalf_of)

Acima disso: 429 Too Many Requests.

Limites transacionais do seller

Cada seller pode ter limites de valor para Pix e boleto somados: por cobrança, por dia e por mês (dia e mês de Brasília). Contam as cobranças criadas no período que não falharam nem expiraram; uma devolução não libera limite. A cobrança que passaria do limite é recusada com 422, sem ser emitida, e a message diz qual limite foi atingido e quanto resta, por exemplo Limite diário excedido: restam R$ 300,00 hoje (limite R$ 1.000,00). Os limites são definidos pela Letztech e pela revenda; o seller vê os dele em Configurações, no painel.

4. Criar cobrança Pix

POST/v1/marketplaces/:marketplaceId/transactions
Authorization: Basic base64("<API_KEY>:")
Content-Type: application/json
X-Idempotency-Key: <opcional, recomendado>

Corpo da requisição

{
  "amount": 15000,
  "currency": "BRL",
  "payment_type": "pix",
  "on_behalf_of": "<seller_id>",
  "reference_id": "order-1234",
  "customer": "customer-abc-123",
  "description": "Pagamento do pedido #1234",
  "postback_url": "https://parceiro.com.br/webhooks/letztech",
  "payment_method": {
    "pix_expiration_date_time": "2025-12-31T23:59:59Z"
  }
}
CampoTipoObrigatórioDescrição
amountintegersimValor em centavos, inteiro positivo
currencystringsimCódigo ISO 4217, ex: "BRL"
payment_typestringsimFixo: "pix"
on_behalf_ofstringsimID do seller no Letztech, dono da cobrança
reference_idstringsimChave de deduplicação, única por seller
customerstringnãoIdentificador do comprador (referência livre)
descriptionstringnãoDescrição da cobrança
postback_urlstring (URL, HTTPS)nãoURL do parceiro que recebe webhooks de mudança de status (seção 7)
split_rulesarraynãoDivisão da venda entre sellers da mesma revenda (seção 7.1)
payment_method.pix_expiration_date_timestring (ISO 8601)nãoExpiração do QR code (padrão: 1 hora). Sem pagamento até o prazo, a transação expira e o webhook transaction.expired é enviado

Resposta — 201 Created

{
  "id": "txn_...",
  "resource": "transaction",
  "amount": 15000,
  "original_amount": 15000,
  "currency": "BRL",
  "description": "Pagamento do pedido #1234",
  "transaction_number": "...",
  "on_behalf_of": "<seller_id>",
  "refunded": false,
  "voided": false,
  "captured": false,
  "status": "pending",
  "payment_type": "pix",
  "payment_method": {
    "id": "<txid Sicredi>",
    "provider": "SICREDI",
    "type": "DYNAMIC",
    "reusable": false,
    "qr_code": {
      "emv": "<pix copia-e-cola>"
    }
  },
  "fees": "150",
  "metadata": {},
  "webhook_secret": "<presente apenas se postback_url foi informado>",
  "created_at": "2026-09-22T12:00:00.000Z",
  "updated_at": "2026-09-22T12:00:00.000Z"
}
O QR code visual não é retornado como imagem — apenas o payload EMV (payment_method.qr_code.emv, o "PIX copia e cola"). Gere a imagem do QR code a partir desse payload do seu lado (qualquer lib de QR code padrão).

fees é a taxa cobrada do seller nesta cobrança, em centavos, definida no momento da criação pelo plano de taxas do seller. Se o plano mudar depois, as cobranças já criadas mantêm essa taxa.

Erros

StatusSituação
400Validação do payload, ou (chave de seller) on_behalf_of não corresponde a um seller conhecido
401API key ausente/inválida
400O valor da cobrança é menor ou igual à taxa do seller
403marketplaceId não corresponde à API key; (chave de seller) on_behalf_of é outro seller; ou o seller, a revenda dele ou a revenda dona da chave não está ativo
404(chave de revenda) on_behalf_of não é um seller da revenda
409reference_id já usado para esse seller numa transação que quem chamou não pode ver
422O seller ainda não tem plano de taxas configurado (fale com a Letztech)
422Limite transacional do seller atingido (por cobrança, diário ou mensal; ver seção 3)
429Rate limit excedido
502Erro de comunicação com o provedor de pagamento

5. Criar cobrança Boleto

POST/v1/marketplaces/:marketplaceId/transactions

Mesmo endpoint da criação de Pix — o tipo é definido por payment_type.

Corpo da requisição

{
  "amount": 25000,
  "currency": "BRL",
  "payment_type": "boleto",
  "on_behalf_of": "<seller_id>",
  "reference_id": "invoice-2026-001",
  "customer": "customer-abc-123",
  "description": "Mensalidade Janeiro/2026",
  "postback_url": "https://parceiro.com.br/webhooks/letztech",
  "logo": "https://minha-empresa.com/logo.png",
  "payment_method": {
    "expiration_date": "2025-12-31",
    "payment_limit_date": "2026-01-15",
    "buyer": {
      "first_name": "João",
      "last_name": "Silva",
      "email": "joao@email.com",
      "phone_number": "5199999999",
      "taxpayer_id": "12345678901",
      "birthdate": "1990-05-15",
      "address": {
        "line1": "Rua das Flores",
        "line2": "123",
        "line3": "Sala 4",
        "neighborhood": "Centro",
        "city": "Porto Alegre",
        "state": "RS",
        "postal_code": "90000000"
      }
    },
    "body_instructions": [
      "Não receber após vencimento",
      "Juros de 1% ao mês"
    ],
    "billing_instructions": {
      "late_fee": { "mode": "PERCENTAGE", "percentage": 2.0, "start_date": "2026-01-01" },
      "interest": { "mode": "PERCENTAGE", "percentage": 1.0, "start_date": "2026-01-01" },
      "discount": [
        { "mode": "FIXED", "amount": 500, "limit_date": "2025-12-20" }
      ]
    }
  }
}
CampoTipoObrigatórioDescrição
amountintegersimValor em centavos, inteiro positivo
currencystringsimCódigo ISO 4217, ex: "BRL"
payment_typestringsimFixo: "boleto"
on_behalf_ofstringsimID do seller no Letztech, dono da cobrança
reference_idstringsimChave de deduplicação, única por seller
customerstringnãoIgnorado em boleto — o pagador vem sempre de payment_method.buyer
descriptionstringnãoDescrição da cobrança
postback_urlstring (URL, HTTPS)nãoURL do parceiro que recebe webhooks de mudança de status (seção 7)
split_rulesarraynãoDivisão da venda entre sellers da mesma revenda (seção 7.1)
logostring (URL)nãoLogo impresso no boleto — ainda não aplicado (aceito e ignorado; ver aviso abaixo)
payment_method.expiration_datestring (YYYY-MM-DD)nãoData de vencimento
payment_method.payment_limit_datestring (YYYY-MM-DD)nãoData limite para pagamento após o vencimento — ainda não aplicado (aceito e ignorado; ver aviso abaixo)
payment_method.buyerobjetosimDados do pagador/sacado — ver abaixo
payment_method.body_instructionsstring[]nãoAté 5 linhas de instrução impressas no boleto — ainda não aplicado (aceito e ignorado; ver aviso abaixo)
payment_method.billing_instructionsobjetonãoMulta, juros e descontos — ainda não aplicado (aceito e ignorado; ver aviso abaixo)

payment_method.buyer (obrigatório)

CampoTipoObrigatórioDescrição
first_namestringsimNome do pagador
last_namestringsimSobrenome do pagador
emailstringsimE-mail do pagador
phone_numberstringsimTelefone com DDD, apenas dígitos
taxpayer_idstringsimCPF ou CNPJ, apenas dígitos
birthdatestring (YYYY-MM-DD)nãoData de nascimento
address.line1stringsimLogradouro
address.line2stringsimNúmero
address.line3stringnãoComplemento
address.neighborhoodstringsimBairro
address.citystringsimCidade
address.statestringsimUF (2 letras)
address.postal_codestringsimCEP, apenas dígitos

payment_method.billing_instructions (opcional): late_fee e interest aceitam { mode, amount, percentage, start_date }; discount é uma lista de { mode: "FIXED" | "PERCENTAGE", amount, limit_date }.

Ainda não aplicados: billing_instructions (multa, juros e desconto), body_instructions, payment_limit_date e logo são aceitos sem erro, mas não são repassados ao banco: o boleto é emitido sem multa, sem juros, sem desconto e sem instruções personalizadas. Não dependa desses campos até esta nota ser removida.

Resposta — 201 Created

Mesmo formato da criação de Pix (seção 4), com payment_type: "boleto". payment_method.barcode traz a linha digitável do boleto. payment_method.pix.qr_code.emv pode vir preenchido — veja o aviso abaixo antes de exibi-lo ao pagador.

"payment_method": {
  "id": "<nosso número>",
  "zoop_boleto_id": "<nosso número>",
  "resource": "boleto",
  "document_number": "<nosso número>",
  "barcode": "<linha digitável>",
  "status": "not_paid",
  "url": "https://api.letztech.com.br/v1/pay/<id>/pdf",
  "expiration_date": "2026-10-20",
  "pix": { "qr_code": { "emv": "<pix copia-e-cola, se o BolePix foi emitido>" } }
}
Não exiba o Pix do boleto ao pagador por enquanto. Hoje o boleto e o Pix em payment_method.pix são duas cobranças independentes no banco: um pagamento feito por esse Pix não confirma a transação (ela continua pending e nenhum webhook é enviado), e o pagador pode acabar pagando os dois. A página pública e o PDF da Letztech já não mostram esse Pix. Oriente o pagamento pela linha digitável. Esta nota será atualizada quando o boleto híbrido (boleto e Pix como o mesmo título) estiver ativo.

payment_method.url é o link absoluto e público do PDF do boleto, e payment_method.expiration_date o vencimento (AAAA-MM-DD; null se desconhecido). Os dois vêm também na consulta e no replay. Os endpoints públicos por trás:

EndpointDescrição
GET/v1/pay/:id
Página pública (JSON) com os dados mínimos da cobrança, linha digitável e vencimento, sem autenticação
GET/v1/pay/:id/pdf
PDF do boleto, também público

Erros

Mesma tabela da seção 4.

Consultar o boleto

GET/v1/marketplaces/:marketplaceId/boletos/:id

Devolve o objeto boleto no formato da Zoop. :id aceita o id do boleto (payment_method.id) ou o id da transação. Mesmo escopo da consulta de transação (seção 6): outro seller, outra revenda ou uma transação que não é boleto (Pix, por exemplo) retornam 404.

{
  "id": "<nosso número>",
  "zoop_boleto_id": "<nosso número>",
  "resource": "boleto",
  "status": "not_paid",
  "reference_number": "<reference_id>",
  "document_number": "<nosso número>",
  "expiration_date": "2026-10-20",
  "bank_code": "748",
  "url": "https://api.letztech.com.br/v1/pay/<id da transação>/pdf",
  "barcode": "<linha digitável>",
  "paid_at": null,
  "transaction_id": "<id da transação>",
  "on_behalf_of": "<seller>",
  "uri": "/v1/marketplaces/<marketplaceId>/boletos/<nosso número>",
  "metadata": {},
  "created_at": "2026-10-17T12:00:00.000",
  "updated_at": "2026-10-17T12:00:00.000"
}

status é paid ou not_paid. recipient, sequence e fingerprint vêm null; accepted, printed e downloaded vêm false (não são rastreados).

5.1 Cartão de crédito (por token)

O cartão é processado na Zoop: a Letztech recebe só o token do cartão e repassa a venda. Número, CVV e validade nunca passam pela Letztech: um corpo com esses campos é recusado (400).

Disponível só para sellers habilitados (sellers da Letztech importados da Zoop); para os demais, a resposta é 422. Uma chave de revenda ainda não vende cartão (403).
POST/v1/marketplaces/:marketplaceId/transactions
Authorization: Basic base64("<API_KEY>:")
Content-Type: application/json
{
  "payment_type": "credit",
  "on_behalf_of": "<id do seller>",
  "amount": 9990,
  "currency": "BRL",
  "capture": true,
  "reference_id": "pedido-5678",
  "token": "<token do cartão gerado na Zoop>",
  "installment_plan": { "mode": "interest_free", "number_installments": 3 },
  "statement_descriptor": "LOJA X",
  "postback_url": "https://parceiro.com.br/webhooks/letztech"
}
  • amount em centavos; currency só BRL. Parcelas: até 24.
  • O token vai em token ou em source.card.id, nunca nos dois.
  • capture: false só pré-autoriza; capture depois.
  • reference_id é obrigatório e único por seller: repetir devolve a mesma venda, sem cobrar de novo.

Respostas

  • 201: venda criada. O corpo é o objeto de transação da Zoop (id é o da Zoop), com o seu reference_id e o webhook_secret se houver postback_url.
  • 202: a Zoop não respondeu a tempo. A venda fica pending e é conferida na Zoop em alguns minutos; consulte (seção 6) ou aguarde o webhook. Não reenvie com outro reference_id: repita com o mesmo, que nunca cobra duas vezes.
  • 4xx da Zoop (ex.: cartão negado): repassado com o mesmo status e corpo.

Capturar uma pré-autorização

POST/v1/marketplaces/:marketplaceId/transactions/:id/capture
{ "amount": 9990 }

Sem amount, captura o total autorizado.

Cancelar ou estornar

POST/v1/marketplaces/:marketplaceId/transactions/:id/void
X-Idempotency-Key: <obrigatório>
{ "amount": 3000 }

Total ou parcial (sem amount, o restante). :id aceita o id da Zoop ou o nosso. Uma operação por venda por vez: outra captura ou cancelamento em andamento dá 409. 202 significa que a Zoop não respondeu: a operação é conferida depois e nunca repetida sozinha.

6. Consultar status de uma transação

GET/v1/marketplaces/:marketplaceId/transactions/:id
Authorization: Basic base64("<API_KEY>:")

Retorna a transação no mesmo formato da criação (Pix ou Boleto), com o status atualizado. :id é o id retornado na resposta de criação. A chave de seller vê todas as transações dele, inclusive as criadas pela chave da revenda; a chave de revenda vê as dos sellers dela feitas com o preço da revenda. Qualquer outra retorna 404.

Use este endpoint para reconciliar o estado real de uma transação, principalmente como fallback caso uma entrega de webhook não chegue.

StatusSituação
200Transação encontrada
401API key ausente/inválida
403marketplaceId não corresponde à API key
404Transação não encontrada, ou fora do que a chave enxerga

Valores possíveis de status

ValorSignificado
pendingAguardando pagamento
succeededPago e confirmado
failedFalhou
refundedDevolvido (total ou parcial)

7. Devolver transação (Pix)

POST/v1/marketplaces/:marketplaceId/transactions/:id/refund
Authorization: Basic base64("<API_KEY>:")
Content-Type: application/json
X-Idempotency-Key: <opcional, recomendado>
Esta rota é só para Pix já liquidado (succeeded). Cartão se cancela ou estorna pelo /void (seção 5.1). Boleto não tem devolução via API.

Corpo da requisição

{
  "amount": 150.00,
  "reason": "Produto não entregue"
}
CampoTipoObrigatórioDescrição
amountnumber (2 casas)nãoValor a devolver em reais (ex: 150.00). Se omitido, devolve o valor restante integral
reasonstringnãoMotivo da devolução (máx 500 caracteres)
Atenção à unidade: diferente da criação (onde amount é em centavos, ex: 15000), no refund o amount vai em reais com 2 casas decimais (ex: 150.00).

Autenticada apenas pela API key (server-to-server), sem MFA — a própria API key é o fator de segurança. Aceita X-Idempotency-Key: retentativas com a mesma chave retornam a resposta original em vez de devolver duas vezes.

Com a chave de revenda, a devolução sai do saldo do seller, como pela chave do seller, e o dono do seller recebe um e-mail avisando. Vale também com a revenda suspensa.

A devolução pode ser confirmada na hora ou ficar em processamento até o Sicredi confirmar (alguns minutos). Nos dois casos a resposta é 200 e o valor já fica reservado. O webhook transaction.refunded só é enviado quando o Sicredi confirma. Se o Sicredi não realizar a devolução depois, o valor volta a ficar disponível para devolver e nenhum webhook transaction.refunded é enviado.

StatusSituação
200Devolução aceita (confirmada ou em processamento)
400Transação não é Pix, não está liquidada, valor inválido ou saldo insuficiente do seller (ou de um destinatário do split, seção 7.1)
401API key ausente/inválida
403marketplaceId não corresponde à API key
404Transação não encontrada, ou fora do que a chave enxerga (seção 6)
422O Sicredi recusou a devolução

7.1 Split entre sellers (split_rules)

Uma cobrança Pix ou boleto pode ser dividida entre o seller da transação (on_behalf_of, o principal) e até 10 outros sellers da mesma revenda, com o campo split_rules no corpo da criação (seções 4 e 5). As regras valem só na criação: não há como incluir ou mudar split depois.

"split_rules": [
  { "recipient": "<seller_id>", "amount": 3000, "charge_processing_fee": true },
  { "recipient": "<outro_seller_id>", "percentage": 10, "liable": false }
]
CampoTipoObrigatórioDescrição
recipientstringsimId do seller que recebe a parte (ou o id dele na Zoop). Precisa estar ativo, ser da mesma revenda e ser diferente do principal
amountintegerum dos doisValor fixo do destinatário, em centavos (como o amount da transação)
percentagenumber (2 casas)um dos doisPercentual do valor da transação (2.5 = 2,5%), arredondado para baixo em centavos
liablebooleannão (padrão true)Se o destinatário responde pela devolução na proporção do que recebeu. Com false, a parte dele sai do principal
charge_processing_feebooleannão (padrão false)Se o destinatário paga parte da taxa, proporcional ao valor dele. Com false, recebe o valor inteiro e o principal paga a taxa toda

A taxa é uma só, calculada pelo plano do seller principal. O principal fica com o valor da venda menos as partes dos destinatários e menos a taxa que eles não pagam. A resposta da criação e da consulta devolve split_rules com o amount de cada destinatário em centavos (já calculado, quando a regra foi enviada em percentual). Sem split, o campo não aparece.

Na devolução, cada destinatário com liable: true devolve a fração dele do valor devolvido, e o principal o resto. Se o principal ou algum destinatário não tiver saldo para a parte dele, a devolução inteira é recusada com 400, sem chamar o banco.

Diferenças em relação à Zoop

Recusadas com 400, com a mensagem dizendo o campo: mais de 10 destinatários, charge_recipient_processing_fee, is_gross_amount e POST /v1/marketplaces/:marketplaceId/transactions/:id/split_rules (split depois da criação). Nenhum campo de split é aceito e ignorado.

StatusSituação
400Destinatário inválido (inativo, de outra revenda, repetido ou o próprio principal), regra com amount e percentage juntos, soma acima do valor, principal sem valor para pagar a taxa, ou campo não suportado

8. Notificações (webhooks)

Se postback_url foi informado na criação da transação (Pix, Boleto ou cartão), a Letztech faz POST nessa URL a cada mudança de status relevante: transaction.completed, transaction.failed, transaction.expired (Pix não pago dentro da validade, ou boleto não pago até 1 dia após o vencimento; se for pago depois, ainda é liquidado e gera transaction.completed), transaction.refunded (no cartão, a cada cancelamento ou estorno) e, só no cartão, transaction.charged_back (chargeback ou disputa aberta na venda).

Valide sempre o header X-Letztech-Signature (HMAC-SHA256 do corpo bruto, assinado com o webhook_secret retornado na criação/consulta) antes de confiar no conteúdo — qualquer um pode chamar sua postback_url sem essa verificação.

O segredo é da chave que criou a transação: uma transação criada pela chave da revenda é assinada com o segredo da revenda, e uma criada pela chave do seller, com o do seller. Por isso o webhook_secret só vem na resposta para quem criou a transação — numa consulta pela outra chave, o campo não vem.

O webhook não é fonte de verdade: trate-o sempre como notificação de conveniência e reconcilie via consulta (seção 6) quando em dúvida.

9. Formato padrão de erro

{
  "statusCode": 400,
  "error": "Bad Request",
  "message": "Validation failed",
  "timestamp": "2026-09-22T12:00:00.000Z",
  "path": "/marketplaces/abc/transactions",
  "requestId": "3f1c9e2a-..."
}

message pode ser string ou array de strings (múltiplos erros de validação). requestId identifica a requisição nos logs internos da Letztech — inclua-o ao reportar um erro pra suporte. Também vem no header X-Request-Id em toda chamada (não só erros); se você mesmo enviar um X-Request-Id/X-Correlation-Id na requisição, a Letztech reaproveita esse valor em vez de gerar um novo.