Criar uma transação
Crie uma cobrança enviando o meio de pagamento (cartão, Pix, boleto, NuPay ou débito), o valor e os dados do cliente para POST /v1/transactions. A Selectwin processa o pagamento junto ao adquirente e
Crie uma cobrança enviando o meio de pagamento (cartão, Pix, boleto, NuPay ou débito), o valor e os dados do cliente para POST /v1/transactions. A Selectwin processa o pagamento junto ao adquirente e devolve a transação criada com seu id, status e os artefatos necessários para cobrar (QR Code Pix, linha digitável do boleto ou o resultado da autorização do cartão).
POST /v1/transactions
Como funciona
Uma transação é o registro de uma tentativa de cobrança. Quando você envia a requisição, a API:
- Valida o corpo (campos obrigatórios, formatos, faixas de valor).
- Resolve o cliente: usa
customer.idse informado, ou cria/atualiza um cliente a partir dos dados completos. - Calcula o valor: a partir de
amount(valor total em centavos) ou da soma dositems(ver Definição do valor). - Aciona o meio de pagamento correspondente ao
payment.methode registra o resultado. - Responde 201 Created com a transação e seu
statusinicial.
O status inicial depende do método e é assíncrono na maioria dos casos — você não deve assumir que a transação já está paga ao receber a resposta:
- Pix e boleto nascem em
pending: a resposta traz o QR Code / linha digitável, e a transação só viraapprovedquando o cliente paga. - Cartão com
capture: true(padrão) tenta autorizar e capturar de uma vez, indo direto paraapproved(ourefused). - Cartão com
capture: falseapenas autoriza (reserva o limite), ficandopre-authorizedaté você capturar ou o prazo do adquirente expirar.
Não faça polling
Nunca fique consultando GET /v1/transactions/{id} em loop para saber se a transação foi paga. Configure webhooks e reaja ao evento transaction.approved. Veja Proibição de polling.
Idempotência
Criar transação é uma operação de escrita: uma falha de rede pode deixar você sem saber se a cobrança aconteceu. Envie o header X-Idempotency-Key (um UUID v4 novo por tentativa de cobrança) para que, se você repetir a mesma requisição, a API retorne a transação original em vez de cobrar o cliente duas vezes. Reutilize a mesma chave apenas ao reenviar a mesma operação. Detalhes em Chave de idempotência.
Quando usar
Use POST /v1/transactions sempre que precisar cobrar um pagamento avulso (checkout, venda única, fatura). Para cobranças recorrentes com ciclo gerenciado pela plataforma, prefira as Assinaturas (Subscriptions). Para apenas autorizar agora e capturar depois (ex.: confirmar estoque antes de cobrar), use payment.capture: false e depois Capturar.
Requisição
Headers
| Header | Obrigatório | Descrição |
|---|---|---|
SelectKey | Sim | Sua chave de API. Produção: sl_live_…; sandbox: sl_test_…. Nunca use Authorization: Bearer/Basic. Veja Autenticação. |
Content-Type | Sim | application/json. |
X-Idempotency-Key | Recomendado | UUID v4 único por cobrança, para evitar duplicidade. Veja Idempotência. |
Definição do valor {#definicao-do-valor}
Há duas formas de definir o total da transação — escolha uma:
| Forma | Como | Quando |
|---|---|---|
amount | Inteiro em centavos com o total. Obrigatório quando items é omitido. | Cobrança simples sem detalhar produtos. |
items[] | Lista de linhas; o total é a soma de unitPrice × quantity. Obrigatório (≥1 linha) quando amount é omitido. | Carrinho com produtos discriminados. |
Faixa de
amount: mínimo500(R$ 5,00) e máximo20000000(R$ 200.000,00).
Corpo — campos de nível raiz
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
payment | object | Sim | Meio de pagamento (ver tabelas abaixo). |
customer | object | Sim | Cliente: por id ou com dados completos. |
amount | integer (500..20000000) | Condicional | Total em centavos (BRL). Obrigatório se items não for enviado. |
items | array | Condicional | Linhas do carrinho. Obrigatório (≥1) se amount não for enviado. |
description | string | Não | Descrição legível da transação (não confundir com a descrição de cada item). |
externalReference | string | Não | ID do pedido no seu sistema, para conciliação. |
metadata | object | Não | Pares chave/valor livres (máx. 40 chaves). Veja Metadata. |
tags | array (string) | Não | Etiquetas para filtros e relatórios (máx. 40). |
billing | object | Não | Endereço de cobrança (billing.address, com id para reutilizar um já salvo). |
shipping | object | Não | Dados de entrega (shipping.address, frete, rastreio). Veja Shipping. |
callback | object | Não | callback.webhookUrl (URI) para callbacks de status desta transação. |
geolocation | object | Não | Sinais antifraude do cliente. Recomendado para cartão (ver abaixo). |
discount | object | Não | Desconto aplicado à transação (ver Desconto). |
splits | array | Não | Regras de repasse (split) entre recebedores. |
Corpo — payment (obrigatório em todo método)
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
payment.method | string | Sim | Um de credit, billet, pix, nupay, debit. |
payment.currency | string | Sim | ISO 4217, atualmente BRL. |
payment.capture | boolean | Não | true (padrão) captura na hora; false apenas autoriza (cartão). |
payment.installments | number (1..12) | Cartão | Número de parcelas, de 1 a 12. |
Cartão — payment.card
Informe id (cartão tokenizado, recomendado) ou os dados completos. Nunca envie dados de cartão em claro a partir do seu servidor sem cumprir o escopo PCI — veja Segurança PCI.
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
payment.card.id | string (prefixo_valor) | Alternativa | ID público de um cartão já salvo. Quando presente, dispensa os demais campos. |
payment.card.holderName | string | Se sem id | Nome impresso no cartão. |
payment.card.numbering | string | Se sem id | Número do cartão (validado por Luhn). |
payment.card.expirationMonth | number (1..12) | Se sem id | Mês de expiração. |
payment.card.expirationYear | integer | Se sem id | Ano de expiração (2 ou 4 dígitos). |
payment.card.securityCode | string (^\d{3,4}$) | Se sem id | CVV/CVC (3 ou 4 dígitos). |
Pix — payment.pix
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
payment.pix.expiresInMinutes | integer (15..525600) | Não | Validade do QR Code em minutos (15 min a 1 ano). |
Boleto — payment.billet
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
payment.billet.instructions | string | Não | Instruções impressas no boleto. |
payment.billet.expirationDate | string (YYYY-MM-DD) | Não | Data de vencimento. |
payment.billet.paymentLimitDate | string (date-time) | Não | Data-hora limite para pagamento. |
payment.billet.expiresInDays | number (até 365) | Não | Dias até expirar (alternativa às datas fixas). |
Corpo — customer
Informe customer.id (cliente já cadastrado) ou os dados completos. Com dados completos, a API cria/atualiza o cliente automaticamente.
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
customer.id | string (cus_…) | Alternativa | ID de cliente existente; dispensa os campos abaixo. |
customer.firstName | string | Se sem id | Primeiro nome. |
customer.lastName | string | Se sem id | Sobrenome. |
customer.email | string (email) | Se sem id | E-mail. |
customer.document.type | string | Se sem id | cpf, cnpj ou passport. |
customer.document.number | string (^\d+$) | Se sem id | Número do documento (só dígitos para cpf/cnpj). |
customer.telephone.countryCode | string | Se sem id | Código do país (ex.: 55). |
customer.telephone.areaCode | string | Se sem id | DDD. |
customer.telephone.number | string | Se sem id | Número do telefone. |
customer.birthdate | string (YYYY-MM-DD) | Não | Data de nascimento. |
customer.gender | string | Não | male, female ou other. |
customer.externalReference | string | Não | Referência do cliente no seu CRM. |
customer.additionalEmails | array | Não | E-mails adicionais (máx. 20). |
customer.metadata | object | Não | Metadados do cliente (máx. 20 chaves). |
Para boleto, o endereço do cliente costuma ser exigido pelo emissor — envie
billing.address(ou umcustomercom endereço).
Corpo — discount {#desconto}
Desconto único aplicado à transação. Informe id (desconto já cadastrado na plataforma) ou os campos inline type + value.
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
discount.id | string (dis_…) | Alternativa | ID de um desconto da plataforma a reutilizar. |
discount.type | string | Inline | flat (valor fixo em centavos) ou percentage (percentual). |
discount.value | integer | Inline | Centavos quando flat; percentual quando percentage. |
Importante
O type aceita apenas flat ou percentage — não existe percent. Para flat, value é em centavos (500 = R$ 5,00).
Corpo — geolocation (recomendado para cartão)
Esses campos alimentam a análise antifraude e ajudam a aprovar pagamentos legítimos.
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
geolocation.ipAddress | string (IPv4) | Sim (se enviar o objeto) | IP do cliente. |
geolocation.latitude | number (-90..90) | Não | Latitude. |
geolocation.longitude | number (-180..180) | Não | Longitude. |
geolocation.userAgent | string | Não | User-Agent do navegador do cliente. |
geolocation.acceptLanguage | string | Não | Header Accept-Language (sinal de localidade). |
geolocation.deviceFingerprint | string | Não | Hash estável de dispositivo (fornecido pelo SDK do cliente). |
Exemplos de requisição
Pix (com cliente novo)
curl -X POST https://api.selectwin.io/v1/transactions \
-H "SelectKey: sl_live_aBcDeFgHiJkLmNoPqRsTuVwXyZ" \
-H "Content-Type: application/json" \
-H "X-Idempotency-Key: 6f9619ff-8b86-d011-b42d-00cf4fc964ff" \
-d '{
"amount": 5000,
"payment": { "method": "pix", "currency": "BRL", "pix": { "expiresInMinutes": 30 } },
"customer": {
"firstName": "João",
"lastName": "Silva",
"email": "[email protected]",
"document": { "type": "cpf", "number": "12345678901" },
"telephone": { "countryCode": "55", "areaCode": "11", "number": "999999999" }
},
"externalReference": "ORDER-1001"
}'Cartão tokenizado, capturando na hora, em 3x
{
"amount": 10000,
"payment": {
"method": "credit",
"currency": "BRL",
"capture": true,
"installments": 3,
"card": { "id": "card_abc123" }
},
"customer": { "id": "cus_01hqzvabc" },
"geolocation": { "ipAddress": "189.44.12.1" }
}Cartão com dados completos (autorizar agora, capturar depois)
{
"payment": {
"method": "credit",
"currency": "BRL",
"capture": false,
"installments": 1,
"card": {
"holderName": "JOAO SILVA",
"numbering": "4111111111111111",
"expirationMonth": 12,
"expirationYear": 2028,
"securityCode": "123"
}
},
"items": [
{ "name": "Produto Premium", "unitPrice": 10000, "quantity": 1, "currency": "BRL" }
],
"customer": { "id": "cus_01hqzvabc" }
}Com
capture: false, a transação voltapre-authorized. Capture depois comPOST /v1/transactions/{id}/capture.
Boleto
{
"amount": 18900,
"payment": {
"method": "billet",
"currency": "BRL",
"billet": { "instructions": "Pagar até o vencimento", "expiresInDays": 3 }
},
"customer": { "id": "cus_01hqzvabc" },
"billing": {
"address": {
"street": "Rua Augusta", "number": "500", "district": "Consolação",
"city": "São Paulo", "state": "SP", "country": "BR", "postcode": "01304-000"
}
}
}Resposta
Sucesso retorna 201 Created com a transação completa. Os artefatos de pagamento variam conforme o método: Pix preenche payment.pixQrCodeEmv/pixQrCodeUrl; boleto preenche payment.billetUrl/billetBarcode; cartão preenche payment.cardBrand/cardLastDigits/installments. Campos não aplicáveis vêm null.
{
"id": "tra_01hqzvabc",
"customId": "PEDIDO-1042",
"amount": 5000,
"originalAmount": 5000,
"status": "pending",
"method": "pix",
"currency": "BRL",
"payment": {
"provider": "selectwin",
"refused": null,
"reusable": false,
"pixQrCodeEmv": "00020126580014br.gov.bcb.pix0136a1b2c3d4-...6304ABCD",
"pixQrCodeUrl": "https://api.selectwin.io/pix/qr/tra_01hqzvabc.png",
"cardRegistered": false,
"installments": null,
"expirationDate": "2026-04-12T18:26:33.000Z",
"paidAt": null,
"allowRenewPayment": true,
"invoiceLink": "https://selectwin.io/invoices/tra_01hqzvabc"
},
"discount": null,
"customer": { "id": "cus_01hqzvabc", "firstName": "João", "lastName": "Silva", "email": "[email protected]" },
"items": [
{ "id": "item_01hqzvabc", "name": "Premium Plan", "unitPrice": 5000, "quantity": 1, "currency": "BRL" }
],
"externalReference": "ORDER-1001",
"shippable": false,
"spplited": false,
"timeline": [
{ "id": "tml_01hqzvabc", "message": "Transaction created", "type": "status", "createdAt": "2026-04-12T17:56:33.000Z" }
],
"callback": { "webhookUrl": "https://api.example.com/webhooks/transaction", "active": true },
"merchant": { "name": "Seller Name", "merchantId": "bus_1234567890", "isSubAccount": false },
"updatedAt": "2026-04-12T17:56:33.000Z",
"createdAt": "2026-04-12T17:56:33.000Z",
"_links": {
"self": { "href": "https://api.selectwin.io/v1/transactions/tra_01hqzvabc", "method": "GET", "description": "Read a transaction." }
}
}Campos-chave da resposta
| Campo | Descrição |
|---|---|
id | ID público da transação (tra_…). Trate como string opaca. |
customId | Identificador legível/curto da transação. |
status | Estado inicial: pending, pre-authorized, approved ou refused (ver ciclo de vida). |
method | Método efetivamente usado. |
amount | Total cobrado, em centavos. |
originalAmount | Total antes de descontos. |
payment.pixQrCodeEmv / pixQrCodeUrl | Copia-e-cola e imagem do QR para Pix. |
payment.billetUrl / billetBarcode | Link e linha digitável do boleto. |
payment.installments | Parcelas confirmadas (cartão). |
payment.expirationDate | Expiração do QR/boleto (ISO 8601 UTC). |
timeline[] | Histórico de eventos da transação. |
_links | Links HATEOAS para as próximas ações (ler, capturar, estornar, contestar). |
Dica
Em vez de montar URLs à mão, siga os _links da resposta — eles já apontam o método e o caminho de cada próxima ação (capturar, estornar, ler).
Erros
Trate sempre pelo error.code, nunca pela message. Os específicos de Transactions e os transversais mais comuns ao criar:
error.code | HTTP | Quando ocorre |
|---|---|---|
invalidParameters | 400 | Campo ausente/ inválido. Veja error.params para o campo. |
transactionCardInvalid | 400 | Dados do cartão inválidos (ex.: número falha no Luhn). |
transactionCardIdInvalid / cardIdIsInvalid | 400 | payment.card.id mal formado. |
cardExpired | 400 | Cartão expirado. |
invalidCardData | 422 | Dados do cartão não processáveis. |
cardBrandNotSupported | 422 | Bandeira não suportada. |
missingFeeConfiguration | 422 | Falta configuração de taxas para processar a cobrança. |
paymentProcessingFailed | 503 | Serviço de pagamento/adquirente indisponível — repita com backoff. |
unauthorized | 401 | SelectKey ausente, inválida ou revogada. |
forbidden | 403 | Autenticada, mas sem permissão / limite atingido. |
tooManyRequests | 429 | Rate limit. Respeite error.retryAfterMinutes. |
serverError | 500 | Erro interno — repita; se persistir, contate o suporte. |
Atenção
Uma transação pode ser criada com sucesso (201) e ainda assim ser recusada pelo adquirente — nesse caso status vem refused e payment.refused indica o motivo. Recusa de pagamento não é um erro HTTP. Veja Recusas de pagamento.
Lista completa em Códigos de erro e o envelope em Tratamento de erros.
Boas práticas
- Sempre envie
X-Idempotency-Key(UUID v4 por cobrança) para nunca cobrar o cliente duas vezes em reenvios. Guarde a chave junto ao pedido. - Prefira cartão tokenizado (
payment.card.id) a enviar dados em claro — reduz seu escopo PCI e melhora a aprovação. Veja Segurança PCI. - Use
capture: falsequando precisar confirmar algo (estoque, antifraude) antes de cobrar; capture só o que for vender. - Envie
geolocation(comipAddress) em pagamentos com cartão para melhorar a análise antifraude. - Reaja a webhooks, não a polling: confirme pagamento de Pix/boleto pelo evento
transaction.approved. Veja Proibição de polling. - Grave o
id(e useexternalReference) para conciliar a transação com o pedido no seu sistema. - Defina expiração realista para Pix (
expiresInMinutes) e boleto (expiresInDays) conforme seu fluxo de checkout. - Diferencie recusa de erro:
201comstatus: refusedé uma recusa do adquirente, não falha de integração — não retente cegamente.
Veja também
- Visão geral de Transações — objeto, estados e operações.
- Ler transação · Listar transações
- Capturar · Estornar · Contestar
- Chave de idempotência · Recusas de pagamento
- Convenções da API (centavos, datas UTC, IDs opacos)
How is this guide?