Primeira integração
Crie um Checkout de teste e receba a confirmação no seu servidor.
Este guia usa HTTP e um consumidor independente. Não exige chave Stripe no seu produto. Você também pode usar os SDKs para Node.js/Bun, Python e PHP/Laravel.
Webhooks habilitados
A entrega de eventos está habilitada em https://api-pay.adila.co. Este guia usa payment.succeeded; o catálogo completo lista os demais. A tela Webhooks permite configurar destinos e enviar testes sintéticos no sandbox. Encaminhamento local por CLI e automações por condições continuam fora desta entrega.
Prepare o sandbox
Você precisa de uma organização ativa, uma conta Stripe conectada no ambiente de teste e das capabilities necessárias para receber pagamentos. Um owner/admin conclui a coleta financeira pelo fluxo Stripe apresentado pela Adila. Pagamento permitido em sandbox não comprova habilitação live ou de repasses.
Configure no servidor do seu produto:
ADILA_PAY_BASE_URL:https://api-pay.adila.co, a API do ambiente de teste (Stripe em test mode).ADILA_PAY_ORGANIZATION_ID: UUID da organização.ADILA_PAY_API_KEY: chave Adila comproducts:write,payments:writeepayments:read.
Use uma API key de teste (pk_test_): o prefixo da chave define o ambiente. Veja Autenticação e Ambientes.
Prepare o consumidor
O exemplo executável utiliza Node.js 22.13+, HTTP nativo e SQLite. Valida assinatura sobre bytes originais, timestamp, organização e sandbox; persiste evento e efeito de demonstração na mesma transação. Não libera acesso a produtos nem chama serviços externos automaticamente.
export ADILA_EXPECTED_LIVEMODE=false
export ADILA_CONSUMER_DATABASE=/caminho/privado/consumer.sqlite
# Configure ADILA_WEBHOOK_SECRET e ADILA_PAY_ORGANIZATION_ID no gerenciador de segredos.
node examples/payment-consumer/server.mjsO servidor escuta em loopback na porta 5188. Publique /events por um proxy HTTPS com certificado válido. A Adila aceita somente destinos públicos na porta 443, sem credenciais, query strings ou redirects. Nunca exponha o arquivo SQLite ou os segredos pelo proxy.
Cadastre o destino
Um owner/admin/developer autenticado configura o destino na tela Webhooks ou na API. API keys existentes, mesmo *, não podem administrar endpoints nesta versão. Use uma sessão autorizada e a origem confiável da aplicação para:
POST /v2/organizations/{organizationId}/integrations/endpoints
Content-Type: application/json
Idempotency-Key: endpoint-produto-sandbox-001
Origin: <origem confiável da aplicação>
Cookie: <sessão obtida no login autorizado>
{
"name": "Meu produto sandbox",
"url": "https://seu-produto.example.com/events",
"events": ["payment.succeeded"]
}Guarde o signingSecret retornado em ADILA_WEBHOOK_SECRET. GETs não retornam esse segredo. Não coloque cookies ou segredos em histórico do terminal, navegador público, prints ou logs. Repetições da mesma criação usam a mesma Idempotency-Key e os mesmos parâmetros.
Teste o recebimento sem criar um pagamento
Na tela Webhooks, use Enviar teste em um endpoint ativo de sandbox. Escolha um dos eventos assinados; a Adila enfileira o envio e abre as entregas para acompanhar status HTTP, payload e tentativas. O endpoint continua exigindo HTTPS público: use um túnel HTTPS para receber no seu servidor local.
Pela API, a mesma operação é:
POST /v2/organizations/{organizationId}/integrations/endpoints/{endpointId}/test
Content-Type: application/json
Idempotency-Key: teste-recebimento-sandbox-001
Origin: <origem confiável da aplicação>
Cookie: <sessão obtida no login autorizado>
{ "type": "payment.succeeded" }O retorno {id,eventId,state,test:true} confirma o enfileiramento. Reutilize a
mesma chave e tipo após uma resposta incerta, para evitar duplicar o envio.
São permitidos cinco novos testes por minuto por endpoint. Conta conectada,
endpoint e instalação devem estar em sandbox; endpoints pausados e tipos não
assinados são recusados.
Reconheça os eventos sintéticos
O payload tem test: true, livemode: false, origem adila_test e IDs
fictícios. Seu consumidor deve reconhecer essa marca antes de aplicar efeitos
de negócio. O exemplo Node/SQLite ignora eventos sintéticos após verificar a
assinatura. Um teste verifica o recebimento e a assinatura; não confirma uma
cobrança nem deve liberar acesso ao produto.
Continue abaixo para validar um pagamento de sandbox com recursos Stripe reais.
Crie produto e preço
O exemplo abaixo lê as credenciais do ambiente e mantém uma chave por operação lógica. Em um produto real, persista essas chaves antes da primeira tentativa e reutilize-as ao repetir a operação.
import { randomUUID } from 'node:crypto';
const base = process.env.ADILA_PAY_BASE_URL;
const org = process.env.ADILA_PAY_ORGANIZATION_ID;
const apiKey = process.env.ADILA_PAY_API_KEY;
if (!base || !org || !apiKey) throw new Error('Configure a integração no servidor');
const prefix = `${base}/v2/organizations/${org}/stripe`;
const keys = { product: randomUUID(), price: randomUUID(), checkout: randomUUID() };
async function create(resource, body, key) {
const response = await fetch(`${prefix}/${resource}`, {
method: 'POST',
headers: { 'content-type': 'application/json', 'x-api-key': apiKey, 'idempotency-key': key },
body: JSON.stringify(body),
});
if (!response.ok) throw new Error(`Adila HTTP ${response.status}`);
return response.json();
}
const product = await create('products', { name: 'Produto de teste' }, keys.product);
const price = await create('prices', {
product: product.id, currency: 'brl', unit_amount: 500,
}, keys.price);
const session = await create('checkout/sessions', {
mode: 'payment', line_items: [{ price: price.id, quantity: 1 }],
client_reference_id: 'pedido-interno-de-teste',
}, keys.checkout);
// Persista session.id associado ao pedido interno e à organização.
// Entregue session.url somente ao pagador autorizado, sem registrar a URL em logs.500 representa R$ 5,00. Use apenas cartões/dados oficiais de teste na página Stripe e confirme que ela mostra ambiente de teste. URLs de retorno são definidas pelo operador no backend, não por parâmetros arbitrários do consumidor.
Receba e confira a confirmação
O worker recebe payment_intent.succeeded real e envia payment.succeeded ao destino cadastrado. O consumidor valida assinatura, ambiente e organização, deduplica pelo ID do evento e evita duplicar o efeito pelo payment_id.
Associe esse ID ao pedido usando os registros do seu servidor e o contrato financeiro autorizado. Consulte a sessão que você persistiu:
const response = await fetch(`${prefix}/checkout/sessions/${session.id}`, {
headers: { 'x-api-key': apiKey },
});
if (!response.ok) throw new Error(`Adila HTTP ${response.status}`);
const checkout = await response.json();
const confirmed = checkout.status === 'complete' && checkout.payment_status === 'paid';
// Confira também pedido, organização, payment_intent, valor e moeda esperados.
// Só então aplique a liberação prevista no seu produto de maneira idempotente.Abrir Checkout, retornar ao aplicativo ou receber um evento de teste não confirma cobrança. Se o recurso ainda estiver pendente, consulte novamente ou responda 503 ao webhook para permitir retry conforme a política documentada.
Simule falha e recupere
- Faça seu consumidor devolver 503 antes de aplicar o efeito.
- Produza um pagamento de teste e consulte
GET /integrations/endpoints/{id}/deliveries. - Confira a tentativa, o status e a próxima execução; restaure o consumidor.
- Confira estado
delivered, histórico e um único efeito persistido. - Para uma falha definitiva, um owner/admin/developer usa
POST /integrations/deliveries/{id}/retry, dentro dos limites de idade/tentativas.
Há até seis tentativas automáticas e uma janela adicional de reenvio até 12 no total, dentro de 72 horas. A entrega é pelo menos uma vez; seu consumidor precisa tolerar repetições. Contrato completo de eventos.
Finalize o teste
Estorne cobranças exclusivamente temporárias, expire sessões abertas e arquive produtos/preços de QA quando autorizado. Pause o endpoint de teste para impedir novos eventos. Confira a limpeza e mantenha os recibos/auditoria necessários. Um teste de sandbox não comprova repasse bancário nem operação com dinheiro real.