
Receba, envie e concilie pagamentos PIX direto no seu sistema. REST + JSON, autenticação OAuth2.
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/v2Version
v2Autenticação
OAuth2 BearerA 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
/api/v2/oauth/token| Header | Valor |
|---|---|
Authorization | Basic {base64(client_id:client_secret)} |
Content-Type | application/x-www-form-urlencoded |
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.
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)
/api/v2/auth/loginAutentica o usuário com email e senha. Se a conta tiver 2FA ativado, twoFactorCode é obrigatório (senão a resposta é TWO_FACTOR_REQUIRED).
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
email | string | required | E-mail cadastrado do usuário |
password | string | required | Senha do usuário |
twoFactorCode | string | optional | Código 2FA — obrigatório somente se a conta tiver 2FA ativado |
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" }
| HTTP | Code | Descrição |
|---|---|---|
| 401 | INVALID_CREDENTIALS | E-mail ou senha incorretos |
| 401 | TWO_FACTOR_REQUIRED | Código 2FA ausente ou inválido |
| 423 | ACCOUNT_SUSPENDED | Conta suspensa |
| 429 | RATE_LIMITED | Muitas tentativas — 5 tentativas falhas em 15 min |
Renovar tokens
/api/v2/auth/refreshTroca 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.
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
refresh_token | string | required | O refresh_token retornado por auth_login ou por uma chamada anterior a este endpoint |
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" }
| HTTP | Code | Descrição |
|---|---|---|
| 400 | MISSING_REQUIRED_FIELD | refresh_token ausente |
| 401 | REFRESH_INVALID | Token já revogado, expirado ou inválido — trate como sessão encerrada e refaça o login |
Encerrar sessão
/api/v2/auth/logoutRevoga 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.
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
refresh_token | string | required | O refresh_token do dispositivo a ser encerrado |
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).
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
/api/v2/balancebalance.readcurl -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" }
| Campo | Tipo | Descrição |
|---|---|---|
data.available | number | Saldo disponível para saque — soma das duas carteiras (R$) |
data.pending | number | Saldo aguardando liberação (R$) |
data.currency | string | Sempre "BRL" |
data.wallets.principal.available | number | Saldo disponível na carteira PIX Principal |
data.wallets.secundaria.available | number | Saldo disponível na carteira PIX Plus |
Retorna os dados cadastrais do titular da conta. O CPF é retornado mascarado por segurança.
Consultar perfil
/api/v2/profileprofile.readcurl -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" }
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
/api/v2/transactions/cashinpix.receive| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
amount | number | required | Valor em reais (ex: 100.00) |
external_id | string | optional | ID único da cobrança no seu sistema (idempotência) |
description | string | optional | Descrição exibida ao pagador |
currency | string | optional | Sempre "BRL" (padrão) |
wallet | string | optional | Carteira que recebe o PIX: 'principal' (PIX Principal) ou 'secundaria' (PIX Plus). Padrão: principal |
webhook_url | string | optional | URL 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.
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" }
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
/api/v2/transactions/cashoutpix.send| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
external_id | string | required | ID único da transferência no seu sistema |
amount | number | required | Valor em reais (ex: 50.00) |
key | string | required | Chave PIX do destinatário (CPF, e-mail, telefone ou aleatória) |
key_type | string | optional | Tipo da chave: cpf, email, phone, random (padrão: random) |
name | string | required | Nome do destinatário |
description | string | optional | Descrição do pagamento |
wallet | string | optional | De 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.
| Header | Descrição |
|---|---|
X-Signature | HMAC-SHA256 do payload assinado com sua signing key |
X-Timestamp | Unix timestamp (segundos) da requisição |
X-Nonce | UUID único por requisição (evita replay attacks) |
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"
}Lista o histórico de transações com suporte a filtros, paginação e busca por ID.
Listar transações
/api/v2/account/transactions/listtransactions.read| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
page | number | optional | Número da página (padrão: 1) |
page_size | number | optional | Itens por página: máx 100 (padrão: 20) |
type | string | optional | "cashin" ou "cashout" |
status | string | optional | Filtro por status (ex: confirmed, processing, failed) |
from_date | string | optional | Data inicial ISO 8601 (ex: 2026-01-01) |
to_date | string | optional | Data final ISO 8601 |
transaction_id | string | optional | Busca por ID interno da transação |
external_id | string | optional | Busca pelo seu ID externo |
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 } }
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 confirmadocashin.expiredCobrança expirou sem pagamentocashout.confirmedTransferência PIX processada com sucessocashout.failedTransferência falhou ou foi rejeitada{
"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 retornam um objeto JSON com code e message. Use o campo code para tratamento programático.
{
"success": false,
"error": {
"code": "INSUFFICIENT_FUNDS",
"message": "Saldo insuficiente para realizar o saque."
},
"request_id": "req_4xVpQnRm"
}| HTTP | Code | Descrição |
|---|---|---|
| 401 | UNAUTHORIZED | Token inválido ou expirado |
| 403 | FORBIDDEN | Escopo insuficiente ou IP não permitido |
| 401 | MISSING_SIGNATURE | Headers de assinatura ausentes |
| 401 | INVALID_SIGNATURE | Assinatura HMAC inválida |
| 401 | REPLAY_DETECTED | Nonce já utilizado (replay attack) |
| 401 | INVALID_TIMESTAMP | Timestamp fora do intervalo de ±5 min |
| 400 | MISSING_REQUIRED_FIELD | Campo obrigatório ausente ou inválido |
| 422 | INVALID_AMOUNT | Valor inválido ou negativo |
| 422 | INVALID_WALLET | wallet inválida (aceita apenas 'principal' ou 'secundaria') |
| 422 | INSUFFICIENT_FUNDS | Saldo insuficiente na carteira (wallet) escolhida para o cashout |
| 409 | DUPLICATE_EXTERNAL_ID | external_id já utilizado |
| 422 | INVALID_PIX_KEY | Chave PIX inválida ou não encontrada |
| 403 | NOT_VERIFIED | Conta sem KYC aprovado |
| 422 | PAYMENT_REJECTED | Pagamento rejeitado pelo PSP |
| 502 | PAYMENT_PROVIDER_ERROR | Erro na instituição financeira |
Cada aplicativo tem um conjunto de escopos que determinam quais operações ele pode executar. Configure os escopos ao criar o aplicativo no painel.
| Escopo | Permissão | Endpoints |
|---|---|---|
balance.read | Consultar saldo | GET /v2/balance |
profile.read | Consultar perfil | GET /v2/profile |
pix.receive | Criar cobranças PIX | POST /v2/transactions/cashin |
pix.send | Enviar PIX | POST /v2/transactions/cashout |
transactions.read | Listar transações | POST /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