Autenticação

Gere suas credenciais no painel em Desenvolvedores > API Keys. Você receberá duas chaves:

ChaveFormatoUsoPermissões
Secret Key sk_live_... Apenas no backend Acesso total: criar, consultar, listar, configurar splits
Public Key pk_live_... Frontend (browser) Somente leitura: consultar e listar transações

Envie a chave no header x-api-key em todas as requisições:

# Backend (Secret Key - acesso total)
curl -H "x-api-key: sk_live_sua_chave_secreta" \
  https://api.owynd.com/api/v1/api-gateway/v1/transactions

# Frontend (Public Key - somente consulta)
curl -H "x-api-key: pk_live_sua_chave_publica" \
  https://api.owynd.com/api/v1/api-gateway/v1/transactions/uuid
⚠️ Importante: Nunca exponha sua Secret Key no frontend ou código público. Use a Public Key para consultas no browser.

Erros e HTTP Codes

CodeSignificadoQuando ocorre
200SucessoRequisição processada com sucesso
400Bad RequestDados inválidos ou campos obrigatórios ausentes
401UnauthorizedAPI Key inválida, expirada ou ausente
404Not FoundTransação ou recurso não encontrado
429Rate LimitedLimite de 5 requisições/segundo excedido
500Server ErrorErro interno (contate o suporte)

Formato de Erro

{
  "success": false,
  "error": {
    "message": "Valor mínimo: R$ 5,00 (500 centavos)",
    "statusCode": 400
  }
}

Status das Transações

StatusDescrição
pendingAguardando pagamento PIX (QR Code gerado)
processingPagamento em processamento pelo banco
paidPagamento confirmado — produto pode ser liberado
failedFalha no pagamento
expiredQR Code expirou (30 minutos)
refundedValor devolvido ao cliente

Criar Transação PIX

POST /v1/transactions

Cria uma cobrança PIX. Retorna o QR Code para o cliente pagar.

ℹ️ Valor mínimo: cada cobrança PIX precisa ser de pelo menos R$ 5,00 (500 centavos). O mínimo é definido nas configurações da plataforma e esta página mostra sempre o valor atual; abaixo dele a API responde 400 com o valor mínimo na mensagem.

Headers

HeaderTipoDescrição
x-api-key string obrigatório Sua Secret Key (sk_live_...)
x-idempotency-key string opcional Chave única para evitar cobranças duplicatas

Body (JSON)

CampoTipoDescrição
amount integer obrigatório Valor em centavos. Ex: R$ 100,00 = 10000. Mínimo: 500 (R$ 5,00), definido pela plataforma.
paymentMethod string obrigatório Método de pagamento: "pix"
customer object obrigatório Dados do cliente (veja abaixo)
customer.name string obrigatório Nome completo do cliente
customer.email string opcional E-mail do cliente
customer.phone string opcional Telefone com DDD
customer.document object opcional { "type": "cpf", "number": "12345678900" }
items array opcional [{ "title": "Produto", "unitPrice": 10000, "quantity": 1 }]
split array opcional novo Split inline: [{ "email": "parceiro@email.com", "percentage": "10" }]
postbackUrl string opcional URL HTTPS para webhook de confirmação
externalId string opcional Seu ID interno para referência
description string opcional Descrição da cobrança
tracking object opcional UTMs do clique para atribuição de campanha na UTMify: { "utm_source", "utm_campaign", "utm_medium", "utm_content", "utm_term", "src", "sck" }. Se omitido, a venda é enviada à UTMify sem origem.

Exemplo

curl -X POST https://api.owynd.com/api/v1/api-gateway/v1/transactions \
  -H "Content-Type: application/json" \
  -H "x-api-key: sk_live_sua_chave_secreta" \
  -d '{
  "paymentMethod": "pix",
  "amount": 10000,
  "customer": {
    "name": "João Silva",
    "email": "joao@email.com",
    "phone": "11999999999",
    "document": { "type": "cpf", "number": "12345678900" }
  },
  "items": [
    { "title": "Assinatura Premium", "unitPrice": 10000, "quantity": 1 }
  ],
  "postbackUrl": "https://meusite.com/webhook/owynd",
  "externalId": "pedido-123",
  "tracking": {
    "utm_source": "facebook",
    "utm_campaign": "campanha-verao",
    "utm_medium": "cpc",
    "utm_content": "criativo-a"
  }
}'

Resposta (200)

{
  "success": true,
  "data": {
    "id": "uuid-da-transacao",
    "status": "pending",
    "amount": 10000,
    "paymentMethod": "pix",
    "customer": {
      "name": "João Silva",
      "email": "joao@email.com"
    },
    "pixQrCode": "00020126580014br.gov.bcb.pix...",
    "pixQrCodeImage": "https://api.owynd.com/qrcode/xxx.png",
    "expiresAt": "2026-01-15T11:00:00.000Z",
    "createdAt": "2026-01-15T10:30:00.000Z"
  },
  "meta": {
    "timestamp": "2026-01-15T10:30:00.000Z",
    "version": "v1"
  }
}

Consultar Transação

GET /v1/transactions/:id

Consulta status e dados de uma transação. Aceita Secret Key ou Public Key.

curl https://api.owynd.com/api/v1/api-gateway/v1/transactions/uuid \
  -H "x-api-key: sk_live_sua_chave_secreta"

Resposta

{
  "success": true,
  "data": {
    "id": "uuid-da-transacao",
    "externalId": "pedido-123",
    "status": "paid",
    "amount": 10000,
    "paymentMethod": "pix",
    "customerName": "João Silva",
    "customerEmail": "joao@email.com",
    "expiresAt": "2026-01-15T11:00:00.000Z",
    "createdAt": "2026-01-15T10:30:00.000Z"
  }
}

Listar Transações

GET /v1/transactions?page=1&limit=20

Lista suas transações com paginação. Aceita Secret Key ou Public Key.

Query ParamTipoPadrãoDescrição
pageinteger1Número da página
limitinteger20Itens por página (máx: 100)

Saques (Withdrawals) novo

A API de saques permite que sellers solicitem transferências PIX diretamente via API, sem precisar acessar o painel. Por padrão, os saques são criados como PENDING e processados após aprovação manual do administrador. Se o admin ativar a auto-aprovação de saque via API para a sua conta, o saque é processado e enviado na hora (veja abaixo).

⚠️ Pré-requisitos obrigatórios:
1. Saque via API habilitado — precisa ser ativado pelo admin em Usuários > (seu usuário) > Ações > Saque via API
2. Destino do saque — configurar uma conta bancária cadastrada em Financeiro > Conta Bancária, OU enviar uma chave PIX externa diretamente na requisição (pixKey, pixKeyType, holderName, holderDocument).
3. CPF/CNPJ do titular — obrigatório em todo saque. As adquirentes validam o documento contra o dono da chave PIX. No modo PIX externo, envie holderDocument. No modo conta bancária, cadastre o CPF/CNPJ no seu perfil (ou na conta bancária) — sem um documento válido a requisição é recusada com 400.
4. IP na whitelist — o IP que faz a requisição deve estar cadastrado em Desenvolvedores > IPs Autorizados
ℹ️ Dois modos de destino:
Modo padrão — envie apenas amount; o saque é direcionado para a conta bancária cadastrada do seller. O CPF/CNPJ do titular é obtido do cadastro (conta bancária ou perfil) e precisa estar preenchido e válido.
Modo PIX externo — envie amount + pixKey + pixKeyType + holderName + holderDocument; o saque é direcionado para a chave PIX informada (independente da conta bancária cadastrada). Funciona com todas as adquirentes configuradas na plataforma.
⚡ Auto-aprovação de saque via API (opcional):
Quando o admin ativa Auto-aprovar saque para a sua conta (em Usuários > (seu usuário) > Ações > ↳ Auto-aprovar saque, logo abaixo de Saque via API), cada saque criado via POST /v1/withdrawals é processado e enviado imediatamente, sem passar por aprovação manual — o retorno já vem com status: "PAID" ou "PROCESSING" (e o campo autoApproved: true). Requisitos: saque via API habilitado, senha de saque configurada na plataforma e CPF/CNPJ válido do titular. Se algum requisito faltar, o saque cai no fluxo normal e fica PENDING para aprovação manual. Sem esse recurso ativo, todo saque continua PENDING.
ℹ️ Como funciona a taxa de saque:
O campo amount é o valor bruto do saque: é o que sai do seu saldo. A taxa de saque sai de dentro dele, e o que cai no PIX de destino é o netAmount (amount − fee). Exemplo: se você solicitar R$ 50,00 e a taxa for R$ 2,00, serão debitados R$ 50,00 do saldo e você receberá R$ 48,00. Se a taxa for igual ou maior que o valor, a resposta é 400 com a taxa e o menor valor aceito.

Status dos Saques

StatusDescrição
PENDINGAguardando aprovação do administrador
PROCESSINGEnviado à adquirente, aguardando confirmação (aparece na auto-aprovação)
PAIDSaque aprovado e PIX enviado para sua conta
REJECTEDSaque reprovado pelo admin (ver campo rejectionReason)
FAILEDRecusado pela adquirente — o valor é devolvido ao saldo automaticamente
UNDER_REVIEWEnvio sem confirmação (timeout) — em conferência; sem reenvio nem estorno até resolver

Criar Saque

POST /v1/withdrawals

Solicita um saque. O valor de amount (bruto, com a taxa dentro) é debitado imediatamente do saldo disponível. O saque fica como PENDING até aprovação manual pelo admin (ou é processado na hora, com a auto-aprovação descrita acima).

Headers

HeaderTipoDescrição
x-api-key string obrigatório Sua Secret Key (sk_live_...). Public Key não é aceita aqui.
Content-Type string obrigatório application/json

Body (JSON)

📄 CPF/CNPJ do titular é sempre necessário. No modo PIX externo (com pixKey), envie no campo holderDocument abaixo. No modo conta bancária (só amount), o documento não vai no body mas precisa estar cadastrado e válido no seu perfil ou na conta bancária — sem ele o saque é recusado com 400. Os badges condicional abaixo se referem ao que vai no corpo da requisição, não à obrigatoriedade do documento em si.
CampoTipoDescrição
amount integer obrigatório Valor bruto do saque em centavos, debitado do saldo (a taxa sai de dentro; o que cai é o netAmount). Ex: R$ 50,00 = 5000. Mínimo da API: 100 (R$ 1,00). O mínimo de saque da sua conta pode ser maior ou menor que o padrão da plataforma; abaixo dele a resposta é 400 com o valor. O máximo é definido pela plataforma; acima dele a resposta também é 400 com o valor.
pixKey string opcional Chave PIX de destino. Quando presente, ativa o modo PIX externo e os 3 campos abaixo passam a ser obrigatórios. Sem este campo, o saque vai para a conta bancária cadastrada do seller.
pixKeyType enum condicional Obrigatório quando pixKey é enviado. Valores: CPF · CNPJ · EMAIL · PHONE · RANDOM
holderName string condicional Nome completo do titular da chave PIX. Obrigatório quando pixKey é enviado. Apenas letras, espaços e pontuação simples (. , - '). Mín. 3, máx. 120 caracteres.
holderDocument string condicional CPF (11 dígitos) ou CNPJ (14 dígitos) do titular, somente números. Obrigatório quando pixKey é enviado. No modo conta bancária (sem pixKey) o documento não vai no body, mas precisa estar cadastrado e válido no seu perfil ou na conta bancária — o saque é recusado se não houver.
postbackUrl string opcional URL HTTPS que recebe o webhook deste saque (withdrawal.paid / withdrawal.rejected). Se ausente, o webhook vai para os endpoints configurados em Desenvolvedores > Webhooks que escutam esses eventos.
externalReference string opcional Chave de idempotência (recomendado; pode também ser enviada no header x-idempotency-key). 6–64 caracteres: letras, números, hífen, underscore. Única por conta. Retry com a mesma chave retorna o MESMO saque (campo idempotentReplay: true na resposta) em vez de criar — e debitar — outro. Use sempre que sua integração tiver retry automático/timeout.

Validação de pixKey por tipo

pixKeyTypeFormato exigidoExemplo
CPFExatamente 11 dígitos. Validado com algoritmo de dígitos verificadores."12345678909"
CNPJExatamente 14 dígitos. Validado com algoritmo de dígitos verificadores."12345678000190"
EMAILE-mail válido, máx. 100 caracteres. Convertido para minúsculas."joao@email.com"
PHONE10 a 13 dígitos. Números BR sem código de país recebem prefixo +55 automaticamente."+5511999998888"
RANDOMUUID v4 — 32 hex sem hífens, ou 36 chars no formato 8-4-4-4-12."550e8400-e29b-41d4-a716-446655440000"

Exemplo 1 — Saque para conta bancária cadastrada

curl -X POST https://api.owynd.com/api/v1/api-gateway/v1/withdrawals \
  -H "Content-Type: application/json" \
  -H "x-api-key: sk_live_sua_chave_secreta" \
  -d '{ "amount": 5000 }'

Exemplo 2 — Saque para chave PIX externa

curl -X POST https://api.owynd.com/api/v1/api-gateway/v1/withdrawals \
  -H "Content-Type: application/json" \
  -H "x-api-key: sk_live_sua_chave_secreta" \
  -d '{
    "amount": 5000,
    "pixKey": "joao@email.com",
    "pixKeyType": "EMAIL",
    "holderName": "João da Silva",
    "holderDocument": "12345678909"
  }'

Resposta (200) — Modo padrão (conta bancária)

{
  "success": true,
  "data": {
    "id": "uuid-do-saque",
    "amount": 50.00,
    "fee": 2.00,
    "netAmount": 48.00,
    "status": "PENDING",
    "destination": "BANK_ACCOUNT",
    "pixKey": null,
    "pixKeyType": null,
    "holderName": null,
    "holderDocument": null,
    "createdAt": "2026-05-04T12:00:00.000Z",
    "updatedAt": "2026-05-04T12:00:00.000Z",
    "paidAt": null,
    "rejectionReason": null,
    "autoApproved": false
  }
}
/* amount      = total debitado do saldo (bruto solicitado)
   fee         = taxa de saque cobrada (sai de dentro de amount)
   netAmount   = valor líquido que será creditado no PIX (amount − fee)
   autoApproved = true quando a auto-aprovação processou o saque na hora (status vem "PAID"/"PROCESSING") */

Resposta (200) — Modo PIX externo

{
  "success": true,
  "data": {
    "id": "uuid-do-saque",
    "amount": 50.00,
    "fee": 2.00,
    "netAmount": 48.00,
    "status": "PENDING",
    "destination": "EXTERNAL_PIX",
    "pixKey": "joao@email.com",
    "pixKeyType": "EMAIL",
    "holderName": "João da Silva",
    "holderDocument": "12345678909",
    "createdAt": "2026-05-04T12:00:00.000Z",
    "updatedAt": "2026-05-04T12:00:00.000Z",
    "paidAt": null,
    "rejectionReason": null,
    "autoApproved": false
  }
}
⚡ Resposta com auto-aprovação ativa: quando o admin habilitou Auto-aprovar saque via API para a conta, o mesmo endpoint devolve o saque já processado — "status": "PAID" (ou "PROCESSING" enquanto a adquirente confirma) e "autoApproved": true, com paidAt preenchido. Nenhuma ação manual é necessária. Se a adquirente recusar, o status volta "FAILED" e o valor é devolvido ao saldo automaticamente.
ℹ️ Segurança — IP Whitelist: O IP da requisição deve estar cadastrado em Desenvolvedores > IPs Autorizados. Requisições de IPs não cadastrados retornam 401 Unauthorized. Você pode adicionar até 10 IPs por conta.
🛡️ Validações anti-injection (modo PIX externo): os campos pixKey, holderName e holderDocument são validados contra:
  • caracteres de controle (newline, null byte, tab) — bloqueia log forging;
  • caracteres invisíveis (zero-width, RTL/LTR override, BOM) — bloqueia homoglyph attacks;
  • tags HTML (<, >) e padrões script-like (javascript:, vbscript:, data:, <script>, on*=);
  • backticks e template literals (`, ${});
  • tamanhos máximos: pixKey 140, holderName 120, holderDocument 18.
Inputs que falham qualquer validação retornam 400 Bad Request com mensagem específica.

Erros comuns

HTTPMensagemCausa
400É necessário um CPF/CNPJ válido do titular para saque via API...Modo conta bancária sem CPF/CNPJ válido no perfil nem na conta bancária. Cadastre o documento ou use o modo PIX externo com holderDocument.
400Para saque em chave PIX externa, os campos são obrigatórios: pixKeyType, holderName...Você enviou pixKey mas faltou algum dos demais campos do holder.
400pixKey do tipo CPF deve conter exatamente 11 dígitosFormato da chave PIX não bate com o pixKeyType declarado.
400CPF/CNPJ informado em holderDocument é inválidoDocumento falhou na validação de dígitos verificadores.
400Nome do titular inválidoO holderName contém caracteres fora da whitelist (números, símbolos, etc.).
400Campo X contém caracteres de controle não permitidosAlgum campo trouxe newline, null byte ou outro caractere de controle.
400Saldo insuficienteSaldo disponível menor que amount.
401IP não autorizado para esta contaAdicione o IP em Desenvolvedores > IPs Autorizados.
403Saque via API não está habilitadoPedir ao admin para habilitar em Usuários > (seu usuário) > Ações > Saque via API.

Listar Saques

GET /v1/withdrawals

Lista todos os saques da conta com paginação. Aceita Secret Key ou Public Key.

Query ParamTipoPadrãoDescrição
pageinteger1Número da página
limitinteger20Itens por página (máx: 100)
curl "https://api.owynd.com/api/v1/api-gateway/v1/withdrawals?page=1&limit=20" \
  -H "x-api-key: sk_live_sua_chave_secreta"

Resposta (200)

{
  "success": true,
  "data": [
    {
      "id": "uuid-do-saque",
      "amount": 52.00,
      "fee": 2.00,
      "netAmount": 50.00,
      "status": "PENDING",
      "createdAt": "2026-04-13T12:00:00.000Z",
      "paidAt": null,
      "rejectionReason": null
    }
  ],
  "meta": {
    "total": 5,
    "page": 1,
    "limit": 20
  }
}

Consultar Saque

GET /v1/withdrawals/:id

Consulta detalhes de um saque específico. Aceita Secret Key ou Public Key.

curl "https://api.owynd.com/api/v1/api-gateway/v1/withdrawals/uuid-do-saque" \
  -H "x-api-key: sk_live_sua_chave_secreta"

Resposta (200)

{
  "success": true,
  "data": {
    "id": "uuid-do-saque",
    "amount": 52.00,
    "fee": 2.00,
    "netAmount": 50.00,
    "status": "PAID",
    "createdAt": "2026-04-13T12:00:00.000Z",
    "updatedAt": "2026-04-13T14:30:00.000Z",
    "paidAt": "2026-04-13T14:30:00.000Z",
    "rejectionReason": null
  }
}

Split de Pagamento novo

O Split de Pagamento permite dividir automaticamente o valor de cada venda com parceiros, afiliados ou sócios. Ao criar uma transação, envie o campo split com os destinatários e porcentagens. Quando o pagamento é confirmado, os valores são creditados automaticamente.

Como funciona:
1. Ao criar a transação, envie o campo split com e-mail e porcentagem de cada destinatário
2. O cliente paga normalmente via PIX
3. Após a taxa da plataforma, o valor líquido é dividido automaticamente
4. Parceiro recebe sua porcentagem e você recebe o restante — tudo automático
ℹ️ Regras: A soma de todos os splits não pode ultrapassar 100%. O destinatário precisa ter uma conta na plataforma Owynd.

Split na Transação

Envie o campo split ao criar uma transação para dividir o valor automaticamente:

POST /v1/transactions com split

Exemplo com Split Inline

curl -X POST https://api.owynd.com/api/v1/api-gateway/v1/transactions \
  -H "Content-Type: application/json" \
  -H "x-api-key: sk_live_sua_chave_secreta" \
  -d '{
  "paymentMethod": "pix",
  "amount": 10000,
  "customer": {
    "name": "João Silva",
    "email": "joao@email.com"
  },
  "split": [
    { "email": "parceiro@email.com", "percentage": "10" },
    { "email": "afiliado@email.com", "percentage": "5" }
  ],
  "postbackUrl": "https://meusite.com/webhook",
  "externalId": "pedido-456"
}'

Campos do Split

CampoTipoDescrição
split[].email string obrigatório E-mail do destinatário (deve ter conta na plataforma)
split[].percentage string obrigatório Porcentagem do valor líquido. Ex: "10" = 10%

Exemplo de divisão:

Venda: R$ 100,00
Taxa plataforma (6%): - R$ 6,00
Valor líquido: R$ 94,00

Split parceiro (10%): R$ 9,40 → creditado para parceiro@email.com
Split afiliado (5%):  R$ 4,70 → creditado para afiliado@email.com
Você recebe (85%):    R$ 79,90

Assinaturas

Cobrança recorrente no cartão de crédito ou no Pix Automático. Você cria um link de assinatura pela API e envia ao cliente; ele abre o checkout Owynd e assina. No cartão, informa o cartão, que nunca passa pelo seu servidor. No Pix Automático, paga o 1º ciclo com um QR Code e, no mesmo passo, autoriza os débitos seguintes no app do banco. A cada ciclo a cobrança é automática e você recebe um webhook.

ℹ️ Liberação: cada forma de pagamento precisa estar habilitada na sua conta (cartão ativo ou Pix Automático liberado). Sem isso a criação responde 403. Fale com o suporte para ativar.

Regras

Status do link

StatusDescrição
openAguardando o cliente assinar.
expiredPassou do prazo, ou foi cancelado, sem assinatura.
pendingCliente assinou; primeira cobrança em análise.
activeAssinatura ativa, cobrando a cada ciclo.
canceledAssinatura encerrada; não cobra mais.
POST /v1/subscriptions

Cria um link de checkout para o cliente assinar. Envie o checkoutUrl ao cliente.

Body (JSON)

CampoTipoDescrição
amountintegerobrigatórioValor de cada ciclo em centavos.
periodstringobrigatórioweekly (só pix_automatico), monthly, quarterly, semiannual ou annual.
namestringobrigatórioNome do plano, de 2 a 64 caracteres. Aparece no checkout e no app do banco do cliente.
paymentMethodstringopcionalcredit_card (padrão) ou pix_automatico.
descriptionstringopcionalDescrição do plano.
externalIdstringopcionalSeu ID, usado para idempotência.
postbackUrlstringopcionalURL http(s) que recebe os eventos subscription.*.
returnUrlstringopcionalPara onde o cliente volta depois de assinar.
expiresInHoursintegeropcionalValidade do link, de 1 a 720. Padrão: 72.
customerobjectopcionalPré-preenche o checkout: { name, email, phone }.

Exemplo

curl -X POST https://api.owynd.com/api/v1/api-gateway/v1/subscriptions \
  -H "Content-Type: application/json" \
  -H "x-api-key: sk_live_sua_chave_secreta" \
  -d '{
    "amount": 4990,
    "period": "monthly",
    "name": "Clube VIP",
    "paymentMethod": "pix_automatico",
    "externalId": "cliente-123",
    "postbackUrl": "https://seu-site.com/webhooks/owynd",
    "returnUrl": "https://seu-site.com/obrigado",
    "customer": { "name": "João da Silva", "email": "joao@email.com" }
  }'

Resposta (200)

{
  "success": true,
  "data": {
    "id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
    "status": "open",
    "checkoutUrl": "https://checkout.owynd.com/pay/ass-3f9a1c2b7d4e?assinatura=7c9e6679-7425-40de-944b-e07fc1f90ae7",
    "name": "Clube VIP",
    "amount": 4990,
    "period": "monthly",
    "paymentMethod": "pix_automatico",
    "externalId": "cliente-123",
    "expiresAt": "2026-09-30T18:00:00.000Z",
    "createdAt": "2026-09-27T18:00:00.000Z",
    "subscription": null
  }
}

Erros

HTTPQuando
400Campo inválido (valor, período, URL...).
401x-api-key ausente, inválida ou pública.
403A forma de pagamento escolhida não está habilitada na conta.
409externalId já usado com outro valor, período ou forma de pagamento.
POST /v1/subscriptions

Modo direto (Pix Automático): com mode: "direct" a assinatura nasce na hora e a resposta traz o QR Code, sem link de checkout. Você mostra o QR ao seu cliente no seu app, site ou bot.

⚠️ Em liberação: o modo direto ainda não está disponível. Enquanto isso, a chamada responde 503. Use o modo link, descrito acima, que já funciona no Pix Automático.

Campos do modo direto

CampoTipoDescrição
modestringobrigatóriodirect. Exige paymentMethod: "pix_automatico".
customer.namestringobrigatórioNome completo do cliente, de 2 a 140 caracteres.
customer.documentstringobrigatórioCPF ou CNPJ válido do cliente.
customer.emailstringobrigatórioE-mail real do cliente.
customer.addressobjectobrigatórioEndereço completo do cliente: zipCode (8 dígitos), street, number, district, city, state (UF com 2 letras) e complement (opcional).
expiresInMinutesintegeropcionalPrazo do QR, de 5 a 60 minutos. Padrão: 60. É o prazo que informamos, não uma garantia de validade.

Exemplo

curl -X POST https://api.owynd.com/api/v1/api-gateway/v1/subscriptions \
  -H "Content-Type: application/json" \
  -H "x-api-key: sk_live_sua_chave_secreta" \
  -d '{
    "mode": "direct",
    "paymentMethod": "pix_automatico",
    "amount": 4990,
    "period": "monthly",
    "name": "Clube VIP",
    "externalId": "pedido-123",
    "customer": {
      "name": "João da Silva",
      "document": "12345678909",
      "email": "joao@email.com",
      "address": {
        "zipCode": "01310100", "street": "Avenida Paulista", "number": "1000",
        "district": "Bela Vista", "city": "São Paulo", "state": "SP"
      }
    }
  }'

Resposta: campos a mais

CampoDescrição
data.statuspending até o QR ser pago, depois active.
data.modedirect. Nesse modo não há checkoutUrl.
data.pix{ qrCode, qrCodeImage, expiresAt }: copia-e-cola, imagem PNG em data URL e prazo do QR. Vem null se você repetir a chamada e o QR já foi pago.
data.firstAutomaticDebitData (AAAA-MM-DD) do 1º débito automático, depois do ciclo pago agora.

O que você precisa fazer

  • Aviso ao cliente (obrigatório): exiba, junto do QR, algo como "Ao pagar, você autoriza a cobrança automática de R$ X/<período>; pode cancelar no app do seu banco."
  • Exiba só o QR mais recente. Um QR antigo pode continuar pagável depois que você gerou outro. Se ele for pago, o dinheiro entra e você recebe subscription.paid, com o status da assinatura no corpo, que pode vir canceled. Concilie pelo seu externalId.
  • externalId: repetir a chamada com os mesmos dados devolve o mesmo QR enquanto ele vale. Se o QR venceu sem pagamento ou a tentativa falhou, o mesmo externalId gera uma tentativa nova. Com outro valor, período ou documento, responde 409. Duas chamadas ao mesmo tempo resultam numa só assinatura, e a segunda responde 409 "em processamento".
  • Acompanhe o resultado pelo webhook ou consultando a assinatura, respeitando o limite de 10 consultas por segundo.

Erros do modo direto

HTTPQuando
400Dado inválido ou faltando, como CPF, e-mail ou endereço.
403Pix Automático não habilitado na conta.
409Mesmo externalId com outros dados, ou chamada anterior ainda em processamento.
429Limite de 5 criações por segundo por chave, ou teto de assinaturas diretas atingido.
503Modo indisponível, ou não foi possível gerar o Pix Automático agora. Nenhuma assinatura fica criada para o cliente pagar. Tente de novo; quando houver prazo sugerido, ele vem no cabeçalho Retry-After, em segundos.
GET /v1/subscriptions/:id

Consulta uma assinatura. Aceita o id do link, recebido na criação, ou o id da assinatura, recebido no webhook.

{
  "success": true,
  "data": {
    "id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
    "status": "active",
    "amount": 4990,
    "period": "monthly",
    "externalId": "cliente-123",
    "subscription": {
      "id": "b1f0c2d3-0000-4000-8000-000000000001",
      "status": "active",
      "amount": 4990,
      "period": "monthly",
      "paidCycles": 3,
      "currentPeriodEnd": "2026-10-27T23:59:59.000Z",
      "paymentMethod": "pix_automatico",
      "card": null,
      "customer": { "name": "João da Silva", "email": "joao@email.com" }
    }
  }
}
GET /v1/subscriptions

Lista os links criados pela API, do mais recente para o mais antigo. Parâmetros: page (padrão 1), limit (padrão 20, máximo 100) e externalId.

POST /v1/subscriptions/:id/cancel

Assinatura ativa: para as próximas cobranças, sem estornar o que já foi pago, e dispara subscription.canceled. Link ainda aberto: invalida o link. Se a operadora recusar o cancelamento, a resposta é erro e a assinatura continua ativa; tente de novo.

No Pix Automático, um QR já emitido pode continuar pagável por um curto período, então esconda-o do seu cliente. Se ele for pago, o dinheiro entra e você recebe subscription.paid com o status canceled no corpo.

Webhook de assinatura

Enviado ao postbackUrl do link e aos webhooks cadastrados no painel que escutam o evento. Use estes eventos para liberar ou bloquear o acesso do seu cliente.

EventoDescrição
subscription.paidCiclo cobrado, inclusive o primeiro. Traz data.cycle, data.renewal e data.orderId.
subscription.payment_failedRenovação recusada. Traz data.failureReason e data.willRetry (true = vai tentar de novo).
subscription.canceledAssinatura encerrada. Bloqueie o acesso ao fim de data.currentPeriodEnd.

O corpo traz event e data, com os campos da assinatura mostrados na consulta, mais data.linkId e o seu data.externalId. data.cancelReason pode ser seller, inadimplencia, pagarme, admin ou pagador.

Infrações (MED) novo

Uma infração (MED, Mecanismo Especial de Devolução) é aberta quando o pagador contesta um PIX no banco dele. Nossa equipe faz a defesa por você, 24 horas por dia: você não precisa contestar nada. Pela API você acompanha as suas infrações no seu sistema, com as mesmas informações da tela MEDs do painel.

🔑 Só a Secret Key. As rotas de infração trazem nome, e-mail e CPF/CNPJ do pagador, então exigem a sk_live_.... Use sempre do seu servidor, nunca do navegador.

Status da infração

statusstatusTextoO que significa
em_analiseEm análiseMED aberto. Nossa equipe cuida da defesa. Se houver valor em valorBloqueado, ele fica preso no seu saldo até a decisão.
defendidaDefendidaDefesa aceita: a venda continua sua e o valor bloqueado volta para o saldo.
devolvidaDevolvido ao pagadorMED perdido: o valor foi devolvido ao pagador e saiu do seu saldo.
encerradaEncerradaA infração foi cancelada ou encerrada sem devolução.

Campos da infração

CampoTipoDescrição
idstringId da infração na Owynd
status / statusTextostringStatus (tabela acima) e o texto que aparece no painel
valornumberValor contestado, em reais (ex.: 49.90)
valorBloqueadonumberQuanto desta infração está preso no seu saldo agora, em reais. 0 quando nada está retido ou a infração já foi decidida
motivo / detalheMotivostring | nullMotivo da contestação
e2eIdstring | nullEnd-to-end do PIX contestado. null enquanto ainda não foi informado
venda.idstring | nullId da venda na Owynd. Para venda feita pela API, é o mesmo id de /v1/transactions
venda.origemstringapi, checkout, telegram, deposito ou manual
venda.criadaEm / venda.pagaEmISO 8601 | nullQuando a venda foi criada e paga
pagadorobject | nullnome, email e documento (cada um pode ser null). null quando a venda não tem esses dados
contestadaEmISO 8601Quando o pagador abriu a contestação
defesaobject | nulltexto e enviadaEm da defesa feita pela nossa equipe
decisaoobject | nullobservacao e decididaEm, depois do desfecho
taxaDefesaobject | nullvalor e pagaEm da taxa de defesa, só depois de paga
criadaEm / atualizadaEmISO 8601Registro da infração na Owynd

Listar Infrações

GET /v1/infracoes

Lista as infrações da sua conta, da contestação mais recente para a mais antiga. Só Secret Key.

Query ParamTipoPadrãoDescrição
statusstringtodosUm ou mais, separados por vírgula: em_analise, defendida, devolvida, encerrada
origemstringtodasUm ou mais, separados por vírgula: api, checkout, telegram, deposito, manual
desdedata—Contestadas a partir de. AAAA-MM-DD (dia no horário de Brasília) ou data ISO 8601
atedata—Contestadas até. AAAA-MM-DD inclui o dia inteiro
pageinteger1Número da página
limitinteger20Itens por página (máx: 100)

Um parâmetro inválido responde 400 com a explicação (ele nunca é ignorado em silêncio).

curl "https://api.owynd.com/api/v1/api-gateway/v1/infracoes?status=em_analise&desde=2026-11-01" \
  -H "x-api-key: sk_live_sua_chave_secreta"

Resposta (200)

{
  "success": true,
  "data": [
    {
      "id": "b3f1c2a4-7d1e-4c55-9a3b-1f2e3d4c5b6a",
      "status": "em_analise",
      "statusTexto": "Em análise",
      "valor": 49.90,
      "valorBloqueado": 49.90,
      "motivo": "Contestação do pagador (MED)",
      "detalheMotivo": null,
      "e2eId": "E1234567820261108123456789012345",
      "venda": {
        "id": "uuid-da-transacao",
        "origem": "api",
        "criadaEm": "2026-11-05T14:02:11.000Z",
        "pagaEm": "2026-11-05T14:03:40.000Z"
      },
      "pagador": { "nome": "João Silva", "email": "joao@email.com", "documento": "123.456.789-00" },
      "contestadaEm": "2026-11-07T09:15:00.000Z",
      "defesa": { "texto": "Produto entregue conforme combinado.", "enviadaEm": "2026-11-07T09:16:02.000Z" },
      "decisao": null,
      "taxaDefesa": null,
      "criadaEm": "2026-11-07T09:15:30.000Z",
      "atualizadaEm": "2026-11-07T09:16:02.000Z"
    }
  ],
  "meta": { "page": 1, "limit": 20, "total": 1, "totalPages": 1 }
}

Consultar Infração

GET /v1/infracoes/:id

Uma infração da sua conta. Só Secret Key. Id que não existe (ou de outra conta) responde 404.

curl "https://api.owynd.com/api/v1/api-gateway/v1/infracoes/b3f1c2a4-7d1e-4c55-9a3b-1f2e3d4c5b6a" \
  -H "x-api-key: sk_live_sua_chave_secreta"

Resposta (200) — infração defendida

{
  "success": true,
  "data": {
    "id": "b3f1c2a4-7d1e-4c55-9a3b-1f2e3d4c5b6a",
    "status": "defendida",
    "statusTexto": "Defendida",
    "valor": 49.90,
    "valorBloqueado": 0,
    "motivo": "Contestação do pagador (MED)",
    "detalheMotivo": null,
    "e2eId": "E1234567820261108123456789012345",
    "venda": { "id": "uuid-da-transacao", "origem": "api", "criadaEm": "2026-11-05T14:02:11.000Z", "pagaEm": "2026-11-05T14:03:40.000Z" },
    "pagador": { "nome": "João Silva", "email": "joao@email.com", "documento": "123.456.789-00" },
    "contestadaEm": "2026-11-07T09:15:00.000Z",
    "defesa": { "texto": "Produto entregue conforme combinado.", "enviadaEm": "2026-11-07T09:16:02.000Z" },
    "decisao": { "observacao": null, "decididaEm": "2026-11-09T18:00:00.000Z" },
    "taxaDefesa": { "valor": 2.00, "pagaEm": "2026-11-09T18:00:00.000Z" },
    "criadaEm": "2026-11-07T09:15:30.000Z",
    "atualizadaEm": "2026-11-09T18:00:00.000Z"
  }
}

Webhook de Infração

Cadastre a URL em Desenvolvedores > Webhooks e marque os eventos de Infrações (MED) que quiser receber. A assinatura, o X-Webhook-Event-Id e as novas tentativas são os mesmos dos outros webhooks (veja Webhooks). O aviso sai em até 1 minuto depois da mudança.

EventoQuando
infracao.abertaUm MED novo chegou na sua conta
infracao.defesa_enviadaNossa equipe enviou a defesa (o status continua em_analise; o texto vem em data.defesa)
infracao.saldo_retidoO valor do MED ficou bloqueado no seu saldo (data.valorBloqueado)
infracao.saldo_liberadoO valor bloqueado voltou para o saldo e o MED continua em análise
infracao.defendidaDefesa aceita: a venda continua sua
infracao.devolvidaMED perdido: o valor foi devolvido ao pagador e saiu do saldo
infracao.encerradaInfração cancelada ou encerrada

Quando várias coisas mudam juntas, os eventos chegam nesta ordem (ex.: infracao.aberta e logo depois infracao.saldo_retido). Em todo evento, data traz a infração inteira e atualizada, igual à consulta. Para saber o estado atual, use sempre data.status.

Exemplo — infracao.aberta

{
  "event": "infracao.aberta",
  "data": {
    "id": "b3f1c2a4-7d1e-4c55-9a3b-1f2e3d4c5b6a",
    "status": "em_analise",
    "statusTexto": "Em análise",
    "valor": 49.90,
    "valorBloqueado": 0,
    "motivo": "Contestação do pagador (MED)",
    "detalheMotivo": null,
    "e2eId": "E1234567820261108123456789012345",
    "venda": { "id": "uuid-da-transacao", "origem": "api", "criadaEm": "2026-11-05T14:02:11.000Z", "pagaEm": "2026-11-05T14:03:40.000Z" },
    "pagador": { "nome": "João Silva", "email": "joao@email.com", "documento": "123.456.789-00" },
    "contestadaEm": "2026-11-07T09:15:00.000Z",
    "defesa": null,
    "decisao": null,
    "taxaDefesa": null,
    "criadaEm": "2026-11-07T09:15:30.000Z",
    "atualizadaEm": "2026-11-07T09:15:30.000Z"
  }
}

Exemplo — infracao.devolvida

{
  "event": "infracao.devolvida",
  "data": {
    "id": "b3f1c2a4-7d1e-4c55-9a3b-1f2e3d4c5b6a",
    "status": "devolvida",
    "statusTexto": "Devolvido ao pagador",
    "valor": 49.90,
    "valorBloqueado": 0,
    "decisao": { "observacao": null, "decididaEm": "2026-11-09T18:00:00.000Z" },
    "...": "demais campos iguais à consulta"
  }
}

Exemplo — tratando no seu servidor

app.post('/webhook/owynd', express.raw({ type: 'application/json' }), (req, res) => {
  if (!assinaturaValida(req.body, req.get('X-Webhook-Signature'), 'whsec_seu_secret')) {
    return res.status(401).end();
  }
  const { event, data } = JSON.parse(req.body.toString('utf8'));
  if (event.startsWith('infracao.')) {
    // Guarde pelo id; um mesmo X-Webhook-Event-Id pode chegar mais de uma vez.
    salvarInfracao(data.id, data.status, data.valor, data.valorBloqueado);
  }
  res.status(200).json({ received: true });
});

Webhooks

Receba notificações em tempo real quando transações mudam de status. Configure via painel (Desenvolvedores > Webhooks) ou envie postbackUrl na transação.

Payload do Webhook

{
  "event": "transaction.paid",
  "data": {
    "id": "uuid-da-transacao",
    "externalId": "pedido-123",
    "amount": 10000,
    "status": "paid",
    "paymentMethod": "pix",
    "customerName": "João Silva",
    "paidAt": "2026-01-15T10:35:00.000Z"
  }
}

Eventos disponíveis

EventoCategoriaDescrição
transaction.paidPIXPagamento PIX confirmado
transaction.createdPIXCobrança PIX criada
withdrawal.paidSaqueSaque aprovado e PIX enviado para sua conta
withdrawal.rejectedSaqueSaque reprovado pelo administrador
subscription.paid / .payment_failed / .canceledAssinaturaVer Webhook de Assinatura
infracao.*Infração (MED)Aberta, defesa enviada, saldo retido/liberado, defendida, devolvida, encerrada. Ver Webhook de Infração

Payload — withdrawal.paid / withdrawal.rejected

{
  "event": "withdrawal.paid",
  "data": {
    "id": "uuid-do-saque",
    "amount": 52.00,
    "fee": 2.00,
    "netAmount": 50.00,
    "status": "PAID",
    "paidAt": "2026-04-13T14:30:00.000Z",
    "rejectionReason": null,
    "createdAt": "2026-04-13T12:00:00.000Z",
    "updatedAt": "2026-04-13T14:30:00.000Z"
  }
}

/* Para withdrawal.rejected:
   "event": "withdrawal.rejected",
   "data.status": "REJECTED",
   "data.paidAt": null,
   "data.rejectionReason": "Dados bancários inválidos" */

Validação de Assinatura (HMAC-SHA256)

O corpo do webhook é { "event": "...", "data": { ... } }. Cada webhook cadastrado no painel tem um segredo (whsec_...). Todo envio leva os cabeçalhos:

CabeçalhoDescrição
X-Webhook-Signaturesha256= + HMAC-SHA256 em hexadecimal do corpo inteiro, exatamente como chegou, com o segredo do webhook
X-Webhook-Event-IdId único do envio. O mesmo evento pode chegar mais de uma vez: use este id para não processar em dobro

Calcule a assinatura sobre os bytes recebidos, antes de converter o JSON: reconverter (JSON.stringify) pode mudar espaços e acentos e a conta deixa de bater. O envio para o postbackUrl de uma transação não tem segredo, então não leva assinatura: confirme consultando a transação pela API.

const crypto = require('crypto');

function assinaturaValida(corpoBruto, cabecalho, segredo) {
  const esperado = 'sha256=' + crypto.createHmac('sha256', segredo).update(corpoBruto).digest('hex');
  const a = Buffer.from(esperado);
  const b = Buffer.from(String(cabecalho || ''));
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}

// Express.js — express.raw() guarda o corpo exatamente como chegou
app.post('/webhook/owynd', express.raw({ type: 'application/json' }), (req, res) => {
  if (!assinaturaValida(req.body, req.get('X-Webhook-Signature'), 'whsec_seu_secret')) {
    return res.status(401).json({ error: 'Invalid signature' });
  }

  const { event, data } = JSON.parse(req.body.toString('utf8'));
  if (event === 'transaction.paid') {
    // Pagamento confirmado! Liberar produto.
    console.log(`Pago: ${data.id} - R$ ${(data.amount/100).toFixed(2)}`);
  }

  res.status(200).json({ received: true });
});
ℹ️ Novas tentativas: se o seu servidor não responder 2xx em até 10 segundos, enviamos de novo cerca de 1, 2, 10 e 30 minutos depois (até 5 envios no total).

Exemplo Completo

Fluxo de integração ponta a ponta com Node.js + Express:

1. Criar cobrança PIX (com split)

const axios = require('axios');

const API_KEY = 'sk_live_sua_chave_secreta';
const BASE_URL = 'https://api.owynd.com/api/v1/api-gateway';

app.post('/criar-pagamento', async (req, res) => {
  const { nome, email, valor } = req.body;

  const { data } = await axios.post(`${BASE_URL}/v1/transactions`, {
    paymentMethod: 'pix',
    amount: Math.round(valor * 100),
    customer: { name: nome, email },
    items: [{ title: 'Meu Produto', unitPrice: Math.round(valor * 100), quantity: 1 }],
    split: [
      { email: 'parceiro@email.com', percentage: '10' }
    ],
    postbackUrl: 'https://meusite.com/webhook/owynd',
    externalId: `pedido-${Date.now()}`,
  }, {
    headers: { 'x-api-key': API_KEY },
  });

  res.json({
    transactionId: data.data.id,
    pixCode: data.data.pixQrCode,
    pixImage: data.data.pixQrCodeImage,
    expiresAt: data.data.expiresAt,
  });
});

2. Receber webhook de pagamento

app.post('/webhook/owynd', express.raw({ type: 'application/json' }), (req, res) => {
  // Validar assinatura (recomendado) — assinaturaValida() está em "Webhooks"
  if (!assinaturaValida(req.body, req.get('X-Webhook-Signature'), 'whsec_...')) {
    return res.status(401).end();
  }
  const { event, data } = JSON.parse(req.body.toString('utf8'));

  if (event === 'transaction.paid') {
    console.log('Pagamento confirmado:', data.id);
    console.log('Valor:', (data.amount / 100).toFixed(2));
    console.log('Pedido:', data.externalId);
    // Liberar acesso ao produto/serviço
    liberarAcesso(data.externalId);
  }

  res.status(200).json({ received: true });
});

3. Exibir QR Code no frontend

<div id="pix-container">
  <h2>Escaneie o QR Code para pagar</h2>
  <img id="qr-image" src="" alt="QR Code PIX" />
  <p>Ou copie o código PIX:</p>
  <input id="pix-code" type="text" readonly />
  <button onclick="navigator.clipboard.writeText(
    document.getElementById('pix-code').value
  )">Copiar</button>
</div>

<script>
async function checkPayment(transactionId) {
  const res = await fetch(
    `/api/check-payment/${transactionId}`
  );
  const data = await res.json();
  if (data.status === 'paid') {
    window.location.href = '/obrigado';
  } else {
    setTimeout(() => checkPayment(transactionId), 3000);
  }
}
</script>

Owynd © 2026 · Voltar ao painel · Testar Transação