Documentação da API LaranjaPay
API pública

Documentação da API

Receba, envie e concilie pagamentos PIX direto no seu sistema. REST + JSON, autenticação OAuth2.

Introdução

A API LaranjaPay permite que você integre pagamentos PIX à sua plataforma de forma programática. Todas as requisições são feitas via HTTPS e retornam JSON.

Base URL

https://api.laranja.site/api/v2

Version

v2

Autenticação

OAuth2 Bearer

Autenticação

A API usa OAuth2 com o fluxo client_credentials. Use seu Client ID e Client Secret para obter um access token. O token expira em 1 hora.

Obter token de acesso

POST/api/v2/oauth/token
HeaderValor
AuthorizationBasic {base64(client_id:client_secret)}
Content-Typeapplication/x-www-form-urlencoded
auth.sh
curl -X POST https://api.laranja.site/api/v2/oauth/token \
  -H "Authorization: Basic czBtZUNsaWVudElk..." \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d 'grant_type=client_credentials'

# 200 OK
{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "expires_in": 3600
}

Use o token retornado no header Authorization: Bearer {token} em todas as requisições subsequentes.

Login Mobile

Fluxo de autenticação separado, pensado para apps mobile: em vez de client_id/client_secret, o próprio USUÁRIO autentica com email e senha (mais um código 2FA, se ativado). O resultado é um par de tokens de sessão — access_token (JWT de curta duração) e refresh_token (opaco, de longa duração) — bem diferente do access_token de aplicativo obtido via oauth_token.

Limitação atual

O access_token mobile É um Bearer token válido — mesmo header Authorization: Bearer {token} usado pelos apps servidor-a-servidor. Mas hoje os endpoints v2 pré-existentes (balance, profile, cashin, cashout, account/transactions/list) ainda o REJEITAM com 403 FORBIDDEN, mesmo com o token válido e não expirado: cada um deles só aceita o token opaco de aplicativo obtido via oauth_token. Na prática, hoje o access_token mobile só serve para chamar os próprios endpoints de auth abaixo (login/refresh/logout). Habilitar os demais endpoints para aceitar o token mobile é trabalho já mapeado, mas ainda não implementado.

Login do usuário (mobile)

POST/api/v2/auth/login

Autentica o usuário com email e senha. Se a conta tiver 2FA ativado, twoFactorCode é obrigatório (senão a resposta é TWO_FACTOR_REQUIRED).

CampoTipoObrigatórioDescrição
emailstringrequiredE-mail cadastrado do usuário
passwordstringrequiredSenha do usuário
twoFactorCodestringoptionalCódigo 2FA — obrigatório somente se a conta tiver 2FA ativado
login.sh
curl -X POST https://api.laranja.site/api/v2/auth/login \
  -H "Content-Type: application/json" \
  -d '{
    "email": "fulano@example.com",
    "password": "Senha-Forte!123"
  }'

# 200 OK
{
  "success": true,
  "access_token": "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1c2VyLXV1aWQi...(15min)",
  "refresh_token": "9f2b8c1a7e4d6f0b3c5a8e1d2f4b6c9a0e3d5f7b...(30d)",
  "user": {
    "id": "usr_7NpXqRmL",
    "email": "fulano@example.com",
    "fullName": "Fulano da Silva",
    "username": "fulaninho"
  },
  "request_id": "req_2mKpXvRq",
  "timestamp": "2026-06-17T14:30:00.000Z"
}
HTTPCodeDescrição
401INVALID_CREDENTIALSE-mail ou senha incorretos
401TWO_FACTOR_REQUIREDCódigo 2FA ausente ou inválido
423ACCOUNT_SUSPENDEDConta suspensa
429RATE_LIMITEDMuitas tentativas — 5 tentativas falhas em 15 min

Renovar tokens

POST/api/v2/auth/refresh

Troca um refresh_token válido por um novo par access_token + refresh_token. O refresh_token usado é revogado atomicamente antes do novo par ser emitido (rotação de token) — reutilizá-lo depois (ex: duas chamadas concorrentes, ou um replay) falha com REFRESH_INVALID. Chame este endpoint proativamente pouco antes dos 15 minutos do access_token expirarem.

CampoTipoObrigatórioDescrição
refresh_tokenstringrequiredO refresh_token retornado por auth_login ou por uma chamada anterior a este endpoint
refresh.sh
curl -X POST https://api.laranja.site/api/v2/auth/refresh \
  -H "Content-Type: application/json" \
  -d '{
    "refresh_token": "9f2b8c1a7e4d6f0b3c5a8e1d2f4b6c9a0e3d5f7b..."
  }'

# 200 OK
{
  "success": true,
  "access_token": "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1c2VyLXV1aWQi...(new, 15min)",
  "refresh_token": "a1c3e5f7b9d1c3e5f7b9d1c3e5f7b9d1...(new, 30d)",
  "request_id": "req_5qLmXpVr",
  "timestamp": "2026-06-17T14:45:00.000Z"
}
HTTPCodeDescrição
400MISSING_REQUIRED_FIELDrefresh_token ausente
401REFRESH_INVALIDToken já revogado, expirado ou inválido — trate como sessão encerrada e refaça o login

Encerrar sessão

POST/api/v2/auth/logout

Revoga o refresh_token do dispositivo atual, sem afetar outros dispositivos logados. É idempotente: chamar de novo com o mesmo token (ou um token já revogado/inexistente) ainda retorna 200, sem vazar se o token era válido.

CampoTipoObrigatórioDescrição
refresh_tokenstringrequiredO refresh_token do dispositivo a ser encerrado
logout.sh
curl -X POST https://api.laranja.site/api/v2/auth/logout \
  -H "Content-Type: application/json" \
  -d '{
    "refresh_token": "9f2b8c1a7e4d6f0b3c5a8e1d2f4b6c9a0e3d5f7b..."
  }'

# 200 OK
{
  "success": true,
  "message": "logout realizado",
  "request_id": "req_9vNpKqXm",
  "timestamp": "2026-06-17T15:00:00.000Z"
}

Erro possível: 400 MISSING_REQUIRED_FIELD (refresh_token ausente).

Saldo

Consulte o saldo disponível e o saldo a liberar da sua conta.

A conta tem duas carteiras PIX independentes — principal ("PIX Principal") e secundaria ("PIX Plus") — cada uma com saldo próprio. O campo data.available é a soma das duas; o detalhamento por carteira vem em data.wallets.

Consultar saldo

GET/api/v2/balance
Escopo necessário:balance.read
balance.sh
curl -X GET https://api.laranja.site/api/v2/balance \
  -H "Authorization: Bearer sk_live_•••"

# 200 OK
{
  "success": true,
  "data": {
    "available": 1250.00,
    "pending": 320.00,
    "currency": "BRL",
    "wallets": {
      "principal": { "label": "PIX Principal", "available": 950.00 },
      "secundaria": { "label": "PIX Plus", "available": 300.00 }
    }
  },
  "request_id": "req_8xK2mNpQ",
  "timestamp": "2026-06-17T14:30:00.000Z"
}
CampoTipoDescrição
data.availablenumberSaldo disponível para saque — soma das duas carteiras (R$)
data.pendingnumberSaldo aguardando liberação (R$)
data.currencystringSempre "BRL"
data.wallets.principal.availablenumberSaldo disponível na carteira PIX Principal
data.wallets.secundaria.availablenumberSaldo disponível na carteira PIX Plus

Perfil

Retorna os dados cadastrais do titular da conta. O CPF é retornado mascarado por segurança.

Consultar perfil

GET/api/v2/profile
Escopo necessário:profile.read
profile.sh
curl -X GET https://api.laranja.site/api/v2/profile \
  -H "Authorization: Bearer sk_live_•••"

# 200 OK
{
  "success": true,
  "data": {
    "name": "João Silva",
    "document": "***.456.789-**",
    "email": "joao@exemplo.com.br",
    "status": "active",
    "kyc_status": "approved"
  },
  "request_id": "req_3pLxNrQv",
  "timestamp": "2026-06-17T14:30:00.000Z"
}

Cobrar PIX

Cria uma cobrança PIX (QR Code dinâmico). O pagador escaneia o QR Code para realizar o pagamento. Após a confirmação, um webhook é disparado.

Criar cobrança PIX

POST/api/v2/transactions/cashin
Escopo necessário:pix.receive
CampoTipoObrigatórioDescrição
amountnumberrequiredValor em reais (ex: 100.00)
external_idstringoptionalID único da cobrança no seu sistema (idempotência)
descriptionstringoptionalDescrição exibida ao pagador
currencystringoptionalSempre "BRL" (padrão)
walletstringoptionalCarteira que recebe o PIX: 'principal' (PIX Principal) ou 'secundaria' (PIX Plus). Padrão: principal
webhook_urlstringoptionalURL https que recebe o cashin.confirmed desta cobrança (não pode apontar pra IP privado/local). Se omitido, usa o webhook padrão cadastrado no app.

As duas carteiras têm saldos separados — um cashin em secundaria credita só o saldo de secundaria. Se seu app não precisa distinguir as duas, não envie wallet: o padrão (principal) mantém o comportamento de sempre.

webhook_url é opcional. Se você não enviar, a notificação de cashin.confirmed vai pro webhook padrão cadastrado no seu app. Se enviar, essa cobrança específica notifica só a URL informada — útil pra rotear o retorno por pedido/cliente sem precisar trocar a config global do app.

criar-cobranca.sh
curl -X POST https://api.laranja.site/api/v2/transactions/cashin \
  -H "Authorization: Bearer sk_live_•••" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 250.00,
    "external_id": "pedido_1042",
    "description": "Pedido #1042 — Loja ABC",
    "wallet": "secundaria",
    "webhook_url": "https://sualoja.com/webhooks/laranjapay"
  }'

# 200 OK
{
  "success": true,
  "transaction_id": "txn_9Km3xPqR",
  "external_id": "pedido_1042",
  "amount": 250.00,
  "fee": 2.49,
  "currency": "BRL",
  "payment_method": "pix",
  "payment_info": {
    "qrcode": "00020126580014br.gov.bcb.pix...",
    "expiration": 3600,
    "expires_at": "2026-06-17T15:30:00.000Z"
  },
  "status": "pending_payment",
  "wallet": "secundaria",
  "postback_url": "https://sualoja.com/webhooks/laranjapay",
  "created_at": "2026-06-17T14:30:00.000Z"
}

Enviar PIX

Envia um PIX para uma chave de destino. Esta operação requer assinatura HMAC para maior segurança. O cashout é processado de forma assíncrona e retorna 202 Accepted.

Assinatura obrigatória

Cashouts exigem os headers X-Signature (HMAC-SHA256), X-Timestamp (Unix) e X-Nonce (UUID único por requisição). Veja a seção de Segurança abaixo.

Enviar PIX para chave

POST/api/v2/transactions/cashout
Escopo necessário:pix.send
CampoTipoObrigatórioDescrição
external_idstringrequiredID único da transferência no seu sistema
amountnumberrequiredValor em reais (ex: 50.00)
keystringrequiredChave PIX do destinatário (CPF, e-mail, telefone ou aleatória)
key_typestringoptionalTipo da chave: cpf, email, phone, random (padrão: random)
namestringrequiredNome do destinatário
descriptionstringoptionalDescrição do pagamento
walletstringoptionalDe qual carteira sai o PIX: 'principal' (PIX Principal) ou 'secundaria' (PIX Plus). Padrão: principal

Um cashout em wallet: "secundaria" só pode sacar do saldo de secundaria — se INSUFFICIENT_FUNDS ocorrer, é porque a carteira escolhida está sem saldo, mesmo que a outra tenha saldo de sobra. Confira o saldo da carteira certa (GET /api/v2/balance) antes de enviar.

HeaderDescrição
X-SignatureHMAC-SHA256 do payload assinado com sua signing key
X-TimestampUnix timestamp (segundos) da requisição
X-NonceUUID único por requisição (evita replay attacks)
enviar-pix.sh
TIMESTAMP=$(date +%s)
NONCE=$(uuidgen)
PAYLOAD='{"external_id":"saque_001","amount":50.00,"key":"joao@email.com","key_type":"email","name":"João Silva","wallet":"principal"}'
SIG=$(echo -n "${TIMESTAMP}.${NONCE}.${PAYLOAD}" | \
  openssl dgst -sha256 -hmac "$SIGNING_KEY" -hex | awk '{print $2}')

curl -X POST https://api.laranja.site/api/v2/transactions/cashout \
  -H "Authorization: Bearer sk_live_•••" \
  -H "Content-Type: application/json" \
  -H "X-Signature: $SIG" \
  -H "X-Timestamp: $TIMESTAMP" \
  -H "X-Nonce: $NONCE" \
  -d '$PAYLOAD'

# 202 Accepted
{
  "transaction_id": "txn_7NpXqRmL",
  "external_id": "saque_001",
  "amount": 50.00,
  "fee": 1.99,
  "currency": "BRL",
  "status": "processing",
  "wallet": "principal",
  "created_at": "2026-06-17T14:30:00.000Z"
}

Transações

Lista o histórico de transações com suporte a filtros, paginação e busca por ID.

Listar transações

POST/api/v2/account/transactions/list
Escopo necessário:transactions.read
CampoTipoObrigatórioDescrição
pagenumberoptionalNúmero da página (padrão: 1)
page_sizenumberoptionalItens por página: máx 100 (padrão: 20)
typestringoptional"cashin" ou "cashout"
statusstringoptionalFiltro por status (ex: confirmed, processing, failed)
from_datestringoptionalData inicial ISO 8601 (ex: 2026-01-01)
to_datestringoptionalData final ISO 8601
transaction_idstringoptionalBusca por ID interno da transação
external_idstringoptionalBusca pelo seu ID externo
listar-transacoes.sh
curl -X POST https://api.laranja.site/api/v2/account/transactions/list \
  -H "Authorization: Bearer sk_live_•••" \
  -H "Content-Type: application/json" \
  -d '{
    "page": 1,
    "page_size": 10,
    "type": "cashin",
    "status": "confirmed",
    "from_date": "2026-06-01"
  }'

# 200 OK
{
  "success": true,
  "data": [
    {
      "id": "txn_9Km3xPqR",
      "type": "cashin",
      "amount": 250.00,
      "fee": 2.49,
      "status": "confirmed",
      "external_id": "pedido_1042",
      "created_at": "2026-06-17T14:30:00.000Z"
    }
  ],
  "pagination": {
    "page": 1,
    "page_size": 10,
    "total": 47,
    "total_pages": 5
  }
}

Webhooks

A LaranjaPay envia notificações HTTP para o webhook_url configurado no seu aplicativo quando eventos importantes ocorrem.

Pra cashin.confirmed, você pode sobrepor o destino por requisição: se a cobrança foi criada com webhook_url no body, a notificação vai só pra essa URL — não pro webhook padrão do app. Sem webhook_url na criação, usa o padrão normalmente. A assinatura HMAC continua usando a signing key do seu app nos dois casos.

cashin.confirmedPIX recebido e confirmado
cashin.expiredCobrança expirou sem pagamento
cashout.confirmedTransferência PIX processada com sucesso
cashout.failedTransferência falhou ou foi rejeitada
webhook-payload.json
{
  "event": "cashin.confirmed",
  "transaction_id": "txn_9Km3xPqR",
  "external_id": "pedido_1042",
  "amount": 250.00,
  "fee": 2.49,
  "net": 247.51,
  "currency": "BRL",
  "status": "confirmed",
  "confirmed_at": "2026-06-17T14:35:12.000Z"
}

Seu servidor deve retornar HTTP 200 para confirmar o recebimento. Sem confirmação, a LaranjaPay tentará novamente até 5 vezes com backoff exponencial.

Erros

Erros retornam um objeto JSON com code e message. Use o campo code para tratamento programático.

erro.json
{
  "success": false,
  "error": {
    "code": "INSUFFICIENT_FUNDS",
    "message": "Saldo insuficiente para realizar o saque."
  },
  "request_id": "req_4xVpQnRm"
}
HTTPCodeDescrição
401UNAUTHORIZEDToken inválido ou expirado
403FORBIDDENEscopo insuficiente ou IP não permitido
401MISSING_SIGNATUREHeaders de assinatura ausentes
401INVALID_SIGNATUREAssinatura HMAC inválida
401REPLAY_DETECTEDNonce já utilizado (replay attack)
401INVALID_TIMESTAMPTimestamp fora do intervalo de ±5 min
400MISSING_REQUIRED_FIELDCampo obrigatório ausente ou inválido
422INVALID_AMOUNTValor inválido ou negativo
422INVALID_WALLETwallet inválida (aceita apenas 'principal' ou 'secundaria')
422INSUFFICIENT_FUNDSSaldo insuficiente na carteira (wallet) escolhida para o cashout
409DUPLICATE_EXTERNAL_IDexternal_id já utilizado
422INVALID_PIX_KEYChave PIX inválida ou não encontrada
403NOT_VERIFIEDConta sem KYC aprovado
422PAYMENT_REJECTEDPagamento rejeitado pelo PSP
502PAYMENT_PROVIDER_ERRORErro na instituição financeira

Escopos

Cada aplicativo tem um conjunto de escopos que determinam quais operações ele pode executar. Configure os escopos ao criar o aplicativo no painel.

EscopoPermissãoEndpoints
balance.readConsultar saldoGET /v2/balance
profile.readConsultar perfilGET /v2/profile
pix.receiveCriar cobranças PIXPOST /v2/transactions/cashin
pix.sendEnviar PIXPOST /v2/transactions/cashout
transactions.readListar transaçõesPOST /v2/account/transactions/list

Pronto para começar?

Crie sua conta, gere suas credenciais de API e comece a integrar em minutos.

Criar conta grátis