API v1.6Sandbox disponível

Documentação da API SlacePay

Integre cobranças e saques Pix, consulte transações e valide todo o fluxo em um ambiente de testes isolado.

Base URL

https://api.slacepay.com

Primeira requisição no sandbox

bash
curl --request POST \
  --url https://api.slacepay.com/v1/cash-in \
  --header 'API-Key: sk_test_SUA_CHAVE' \
  --header 'Idempotency-Key: pedido-84721' \
  --header 'Content-Type: application/json' \
  --data '{"amount":"25.00"}'

Fundamentos

Autenticação

Todas as rotas públicas exigem uma chave no header API-Key. Chaves de produção começam com sk_live_ e chaves de teste com sk_test_. O ambiente é determinado automaticamente pela chave usada.

Produção — sk_live_
Movimenta saldo real e encaminha operações ao provedor Pix. Nunca exponha a chave no frontend.
Sandbox — sk_test_
Opera com saldo, transações e QR Codes de teste totalmente separados de produção.
javascript
fetch("https://api.slacepay.com/v1/account", {
  headers: { "API-Key": "sk_test_SUA_CHAVE" }
});

Ambiente de testes

Sandbox

Use sua sk_test para criar cash-ins e cash-outs sem chamar a rede Pix. Toda nova transação começa como PENDING e pode ser finalizada pelo endpoint de simulação.

Isolamento
Saldo, transações, splits e entregas são separados do ambiente live.
Simulação
Finalize como COMPLETED, FAILED, EXPIRED ou CANCELED.
Webhooks reais
O endpoint configurado recebe o mesmo payload e assinatura do ambiente live.

O QR Code do sandbox não é pagável. Uma transação finalizada não pode receber um segundo status.

Segurança operacional

Idempotência

Cash-in e cash-out exigem Idempotency-Key. Repetir a mesma chave com o mesmo corpo retorna a operação original; reutilizá-la com outro corpo retorna 409 IDEMPOTENCY_CONFLICT.

CampoTipoDescrição
Idempotency-Key*stringEntre 8 e 100 caracteres: letras, números, ponto, sublinhado, dois-pontos ou hífen.
API-Key*stringCredencial sk_live_ ou sk_test_ do merchant.

Eventos

Webhooks assinados

Informe webhookUrl ao criar um cash-in. A SlacePay envia payment.updated após cada mudança de status e considera a entrega concluída quando seu endpoint responde com qualquer status 2xx.

Assinatura HMAC-SHA256
A mensagem assinada é timestamp + ponto + corpo JSON bruto. Compare em tempo constante.
Entrega persistente
Até 8 tentativas, intervalo progressivo limitado a 15 minutos e histórico por 90 dias.

Headers enviados

CampoTipoDescrição
X-Wallet-Event-IdstringID estável do evento. Use para eliminar duplicidades.
X-Wallet-Timestampunix secondsMomento usado na assinatura. Recomendamos tolerância máxima de 5 minutos.
X-Wallet-Signaturesha256=<hex>Assinatura HMAC-SHA256 gerada com seu webhook secret.

Payload payment.updated

json
{
  "id": "evt_8c7e659318c04616a2a846895d8a52be",
  "type": "payment.updated",
  "createdAt": "2026-08-28T16:42:00.000Z",
  "environment": "test",
  "livemode": false,
  "data": {
    "transactionId": "txn_ef894b7f34554df18ddf11c1583f8217",
    "environment": "test",
    "livemode": false,
    "status": "COMPLETED",
    "operation": "CASH_IN",
    "amount": "100.00",
    "chargedAmount": "100.00",
    "merchantNetAmount": "99.10",
    "externalReference": "pedido-84721",
    "endToEndId": "E2E-SANDBOX-b34f7251d40a401f"
  }
}

Validação em Node.js

javascript
import { createHmac, timingSafeEqual } from "node:crypto";

export function validateSlacePayWebhook(req, rawBody, secret) {
  const timestamp = req.headers["x-wallet-timestamp"];
  const received = req.headers["x-wallet-signature"];
  const eventId = req.headers["x-wallet-event-id"];

  if (!timestamp || !received || !eventId) return false;

  const age = Math.abs(Date.now() / 1000 - Number(timestamp));
  if (!Number.isFinite(age) || age > 300) return false;

  const expected = "sha256=" + createHmac("sha256", secret)
    .update(timestamp + "." + rawBody)
    .digest("hex");

  const a = Buffer.from(received);
  const b = Buffer.from(expected);
  return a.length === b.length && timingSafeEqual(a, b);
}

Leia o corpo bruto antes de converter o JSON. Salve o event ID processado e responda rapidamente com 2xx.

Referência

Status, limites e erros

O campo status representa o estado atual da transação. Em caso de falha, a API sempre retorna um código estável, mensagem legível e requestId para suporte.

INITIATED

Registro criado; processamento ainda não iniciado.

PENDING

Aguardando pagamento ou processamento.

COMPLETED

Operação concluída e contabilizada.

CANCELED

Operação cancelada.

WAITING_FOR_REFUND

Aguardando confirmação de estorno.

REFUNDED

Valor estornado; pode exigir conciliação.

EXPIRED

Prazo da cobrança encerrado.

FAILED

Operação falhou de forma conclusiva.

PROVIDER_UNKNOWN

Resultado incerto; aguarde conciliação e não repita a operação.

Limite global
120 requisições por minuto por API key.
Cash-in
Até 60 criações por minuto.
Cash-out
Até 10 criações por minuto.

Formato de erro

json
{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Requisição inválida",
    "details": []
  },
  "requestId": "req-21f7a064-4aa3-488f-a96f-3d48b48a9c03"
}
CampoTipoDescrição
400Bad RequestBody, parâmetros ou chave Pix inválidos.
401UnauthorizedAPI key ausente, inválida, revogada ou expirada.
403ForbiddenEscopo ausente, conta bloqueada ou chave live usada no simulador.
404Not FoundRecurso não encontrado ou não pertencente ao merchant.
409ConflictConflito de idempotência ou transação sandbox já finalizada.
422Unprocessable EntityLimite, saldo ou regra de negócio não atendida.
429Too Many RequestsLimite de requisições excedido.

Referência de endpoints

API pública

GET/v1/account

Consultar conta

Retorna cadastro, ambiente, taxas, limites e saldo da conta autenticada. O saldo retornado sempre corresponde ao ambiente da API key.

Escopo necessário: account:read

Resposta 200

json
{
  "merchant": {
    "id": "mrc_0f3c6a9e5d8146d0b18b84fa6c88ed72",
    "environment": "test",
    "livemode": false,
    "fullName": "Maria Oliveira",
    "merchantName": "Loja Exemplo",
    "operationType": "ECOMMERCE",
    "splitEnabled": true,
    "status": "ACTIVE",
    "blocked": false,
    "fees": {
      "cashIn": { "percentage": "0.00", "fixed": "0.90" },
      "cashOut": { "percentage": "2.00", "fixed": "3.00" }
    },
    "limits": {
      "minTicket": "1.00",
      "maxTicket": "5000.00",
      "minCashOutPerTransaction": "10.00",
      "maxCashOutPerTransaction": "1000.00"
    },
    "balance": {
      "available": "950.00",
      "reserved": "50.00",
      "total": "1000.00"
    },
    "createdAt": "2026-08-20T14:20:00.000Z",
    "updatedAt": "2026-08-28T16:40:00.000Z"
  }
}
GET/v1/transactions

Listar transações

Lista as transações do ambiente autenticado, em ordem decrescente de criação.

Escopo necessário: transactions:read

CampoTipoDescrição
pageintegerPágina atual. Padrão: 1.
limitintegerItens por página, entre 1 e 100. Padrão: 20.
statusenumFiltra por um status de transação.
typeCASH_IN | CASH_OUTFiltra pelo tipo da operação.
externalReferencestringBusca pela referência externa exata.
dateFrom / dateToISO 8601Intervalo inclusivo pela data de criação.

Resposta 200

json
{
  "data": [
    {
      "id": "txn_ef894b7f34554df18ddf11c1583f8217",
      "environment": "test",
      "livemode": false,
      "type": "CASH_IN",
      "status": "COMPLETED",
      "amount": "25.00",
      "chargedAmount": "25.00",
      "merchantNetAmount": "24.10",
      "merchantFee": "0.90",
      "feePassedToCustomer": false,
      "externalReference": "pedido-84721",
      "endToEndId": "E2E-SANDBOX-31f94e5f",
      "requiresReconciliation": false,
      "createdAt": "2026-08-28T16:40:00.000Z",
      "updatedAt": "2026-08-28T16:41:10.000Z"
    }
  ],
  "pagination": { "page": 1, "limit": 20, "total": 1, "pages": 1 }
}
GET/v1/transactions/:transactionId

Obter uma transação

Retorna uma transação pertencente ao merchant. Para cash-ins, esta consulta também inclui qrCodeText e qrCodeBase64.

Escopo necessário: transactions:read

CampoTipoDescrição
transactionId*txn_<32 hex>ID público retornado na criação.

Resposta 200

json
{
  "transaction": {
    "id": "txn_ef894b7f34554df18ddf11c1583f8217",
    "environment": "test",
    "livemode": false,
    "type": "CASH_IN",
    "status": "PENDING",
    "amount": "100.00",
    "chargedAmount": "100.00",
    "merchantNetAmount": "99.10",
    "merchantFee": "0.90",
    "feePassedToCustomer": false,
    "externalReference": "pedido-84721",
    "pix": {
      "qrCodeText": "SLACEPAY-SANDBOX:txn_ef894b7f...",
      "qrCodeBase64": "PHN2ZyB4bWxucz0iLi4u"
    },
    "webhook": {
      "configured": true,
      "host": "merchant.example.com"
    },
    "split": {
      "originAmount": "79.28",
      "recipients": [
        {
          "merchantId": "mrc_914bd6cf4a4d4cf5a0cfb8637a580777",
          "percentage": "20.00",
          "amount": "19.82"
        }
      ]
    },
    "requiresReconciliation": false,
    "createdAt": "2026-08-28T16:40:00.000Z",
    "updatedAt": "2026-08-28T16:40:00.000Z"
  }
}
POST/v1/cash-in

Criar cobrança Pix

Cria uma cobrança Pix. Somente amount é obrigatório no body; Idempotency-Key é obrigatório no header. Quando passFeeToCustomer=true, amount representa o valor líquido desejado pelo merchant.

Escopo necessário: cash-in:write

CampoTipoDescrição
amount*decimalValor com até duas casas decimais, respeitando minTicket e maxTicket.
passFeeToCustomerbooleanSe true, adiciona a taxa ao valor cobrado. Padrão: false.
externalReferencestringReferência do seu sistema, até 120 caracteres.
webhookUrlHTTPS URLEndpoint público que receberá payment.updated.
payer.namestringNome do pagador, entre 2 e 120 caracteres.
payer.documentCPF | CNPJ11 ou 14 dígitos.
payer.emailemailE-mail válido, até 254 caracteres.
split[]arrayAté 10 destinatários com merchantId e percentage de 0,01 a 100,00.

Body

json
{
  "amount": "100.00",
  "passFeeToCustomer": false,
  "externalReference": "pedido-84721",
  "webhookUrl": "https://merchant.example.com/webhooks/slacepay",
  "payer": {
    "name": "Cliente Exemplo",
    "document": "12345678901",
    "email": "cliente@example.com"
  },
  "split": [
    {
      "merchantId": "mrc_914bd6cf4a4d4cf5a0cfb8637a580777",
      "percentage": "20.00"
    }
  ]
}

Resposta 201

json
{
  "transaction": {
    "id": "txn_ef894b7f34554df18ddf11c1583f8217",
    "environment": "test",
    "livemode": false,
    "type": "CASH_IN",
    "status": "PENDING",
    "amount": "100.00",
    "chargedAmount": "100.00",
    "merchantNetAmount": "99.10",
    "merchantFee": "0.90",
    "feePassedToCustomer": false,
    "externalReference": "pedido-84721",
    "pix": {
      "qrCodeText": "SLACEPAY-SANDBOX:txn_ef894b7f...",
      "qrCodeBase64": "PHN2ZyB4bWxucz0iLi4u"
    },
    "webhook": {
      "configured": true,
      "host": "merchant.example.com"
    },
    "split": {
      "originAmount": "79.28",
      "recipients": [
        {
          "merchantId": "mrc_914bd6cf4a4d4cf5a0cfb8637a580777",
          "percentage": "20.00",
          "amount": "19.82"
        }
      ]
    },
    "requiresReconciliation": false,
    "createdAt": "2026-08-28T16:40:00.000Z",
    "updatedAt": "2026-08-28T16:40:00.000Z"
  }
}

A resposta pode ser 202 quando o resultado do provedor estiver incerto. Nesse caso, status será PROVIDER_UNKNOWN e a transação não deve ser repetida.

POST/v1/cash-out

Criar saque Pix

Cria um saque e reserva imediatamente o valor total debitado. merchantDebitAmount representa amount somado à taxa do merchant.

Escopo necessário: cash-out:write

CampoTipoDescrição
amount*decimalValor que o destinatário receberá.
pixKey*stringChave Pix compatível com pixType.
pixType*cpf | cnpj | email | phone | evpTelefone deve usar +55; evp deve ser UUID válido.
externalReferencestringReferência do seu sistema, até 120 caracteres.

Body

json
{
  "amount": "50.00",
  "pixKey": "cliente@example.com",
  "pixType": "email",
  "externalReference": "saque-1921"
}

Resposta 201

json
{
  "transaction": {
    "id": "txn_6bbec9e80eb74291a7cf142737185da2",
    "environment": "test",
    "livemode": false,
    "type": "CASH_OUT",
    "status": "PENDING",
    "amount": "50.00",
    "chargedAmount": "50.00",
    "merchantNetAmount": "50.00",
    "merchantDebitAmount": "54.00",
    "merchantFee": "4.00",
    "feePassedToCustomer": false,
    "externalReference": "saque-1921",
    "pix": {
      "pixKeyMasked": "cli***com",
      "pixType": "email"
    },
    "requiresReconciliation": false,
    "createdAt": "2026-08-28T17:00:00.000Z",
    "updatedAt": "2026-08-28T17:00:00.000Z"
  }
}
POST/v1/sandbox/transactions/:transactionId/simulate

Simular transação

Finaliza uma transação PENDING criada com sk_test. Não chama o provedor nem movimenta saldo real, mas aplica a contabilização de teste e dispara o webhook configurado.

Escopo necessário: sandbox:write

CampoTipoDescrição
transactionId*txn_<32 hex>Transação criada no sandbox.
status*COMPLETED | FAILED | EXPIRED | CANCELEDResultado final a simular.

Body

json
{
  "status": "COMPLETED"
}

Resposta 200

json
{
  "transaction": {
    "id": "txn_ef894b7f34554df18ddf11c1583f8217",
    "environment": "test",
    "livemode": false,
    "type": "CASH_IN",
    "status": "COMPLETED",
    "amount": "100.00",
    "chargedAmount": "100.00",
    "merchantNetAmount": "99.10",
    "merchantFee": "0.90",
    "endToEndId": "E2E-SANDBOX-b34f7251d40a401f",
    "requiresReconciliation": false,
    "createdAt": "2026-08-28T16:40:00.000Z",
    "updatedAt": "2026-08-28T16:42:00.000Z"
  }
}
GET/v1/splits

Listar splits recebidos

Lista repasses destinados ao merchant autenticado. O ambiente é isolado pela chave utilizada.

Escopo necessário: transactions:read

CampoTipoDescrição
pageintegerPágina atual. Padrão: 1.
limitintegerItens por página, entre 1 e 100. Padrão: 20.
statusenumFiltra pelo status da transação de origem.

Resposta 200

json
{
  "data": [
    {
      "transactionId": "txn_ef894b7f34554df18ddf11c1583f8217",
      "environment": "test",
      "livemode": false,
      "sourceMerchantId": "mrc_0f3c6a9e5d8146d0b18b84fa6c88ed72",
      "status": "COMPLETED",
      "percentage": "20.00",
      "amount": "19.82",
      "createdAt": "2026-08-28T16:40:00.000Z",
      "completedAt": "2026-08-28T16:42:00.000Z"
    }
  ],
  "pagination": { "page": 1, "limit": 20, "total": 1, "pages": 1 }
}
GET/v1/webhook-deliveries

Listar entregas de webhook

Consulta tentativas e resultados de entrega dos eventos do merchant no ambiente autenticado.

Escopo necessário: transactions:read

CampoTipoDescrição
pageintegerPágina atual. Padrão: 1.
limitintegerItens por página, entre 1 e 100. Padrão: 20.
statusPENDING | PROCESSING | DELIVERED | FAILED | DEADFiltra pelo estado da entrega.

Resposta 200

json
{
  "data": [
    {
      "eventId": "evt_8c7e659318c04616a2a846895d8a52be",
      "transactionId": "txn_ef894b7f34554df18ddf11c1583f8217",
      "environment": "test",
      "livemode": false,
      "status": "DELIVERED",
      "attempts": 1,
      "urlHost": "merchant.example.com",
      "responseStatus": 204,
      "lastError": null,
      "deliveredAt": "2026-08-28T16:42:01.000Z",
      "createdAt": "2026-08-28T16:42:00.000Z"
    }
  ],
  "pagination": { "page": 1, "limit": 20, "total": 1, "pages": 1 }
}

Pronto para integrar?

Crie sua conta pelo Discord, obtenha uma sk_test e execute a primeira cobrança em poucos minutos.

Criar conta