# Xpend — Guia de integração para IA (llms.txt) > Dá este ficheiro (ou o URL https://xpend.pt/llms.txt) à tua IA — Cursor, Claude, > ChatGPT, Lovable, Windsurf, Replit — e pede-lhe para integrar a Xpend na tua loja. > Substitui os placeholders SUBSTITUI_... pelas tuas chaves reais, disponíveis em > https://app.xpend.pt/dashboard/settings/api-keys --- # Xpend — Ficheiro de Integração # Loja: A tua loja # Gerado em: 21 de julho de 2026 # IMPORTANTE: Este ficheiro contém credenciais privadas. # Não partilhes publicamente nem commites para o git. --- ## O que é a Xpend Xpend (https://xpend.pt) é um gateway de pagamentos português real com API REST própria que processa MB WAY e Multibanco. NÃO usar Stripe, IfthenPay, Easypay, Eupago nem qualquer outro gateway. Usar APENAS os endpoints da Xpend documentados abaixo. --- ## Credenciais (já configuradas — não alterar os valores) ```env XPEND_PUBLIC_KEY=pk_live_SUBSTITUI_PELA_TUA_CHAVE_PUBLICA XPEND_SECRET_KEY=SUBSTITUI_PELA_TUA_XPEND_SECRET_KEY XPEND_WEBHOOK_SECRET=SUBSTITUI_PELO_TEU_WEBHOOK_SECRET ``` Como adicionar ao teu projecto: - Lovable → Settings → Environment Variables → colar cada linha - Replit → Secrets → adicionar cada variável - Vercel → Settings → Environment Variables - Local → criar ficheiro .env e colar REGRA DE SEGURANÇA: XPEND_SECRET_KEY e XPEND_WEBHOOK_SECRET são privadas. Usar APENAS em edge functions, server actions, API routes ou backend Node.js. NUNCA num componente React ou ficheiro que corra no browser. --- ## API Xpend — Endpoints Base URL: https://app.xpend.pt/api/v1 REGRA CRÍTICA — SDK obrigatório: - Base URL: https://app.xpend.pt/api/v1 - NUNCA chamar a API com fetch/curl directo — falha com 403 INTEGRATION_SIGNATURE_REQUIRED - Usar o cliente oficial (ZIP Node.js/PHP em Dashboard → Integrações) que envia o header X-VP-Trace (HMAC anti-replay) - XPEND_SECRET_KEY só no servidor — nunca no browser Dados do checkout (sempre enviar em createPayment): - customer: { name, email, phone (9XXXXXXXX), address, city, postalCode, country } - items: [{ id, name, quantity, priceInCents }] - trackingParameters: { utm_source, utm_medium, utm_campaign, utm_content, utm_term, fbclid, gclid, ttclid, src, sck } — obrigatório para Facebook Ads / UTMify atribuir campanhas - Mapeia os campos que o cliente preenche no checkout da loja; captura fbclid/UTMs da URL (window.location.search ou cookies UTMify) - Lojistas com vendas pagas ficam isentos (grandfather). Contas novas (0 vendas paid) exigem customer + items por defeito. Rollback: XPEND_REQUIRE_CHECKOUT_DATA=false UTMify + Facebook Ads (atribuição de campanhas): - A Xpend NÃO envia directamente para o Facebook — envia pedidos para a API UTMify quando o pagamento confirma - O lojista liga o Facebook Ads no painel UTMify (Meta Pixel / Conversions API); a UTMify reencaminha os eventos - Configurar: Dashboard Xpend → Integrações → UTMify → colar API token da UTMify - No POST /payments/init enviar trackingParameters (fbclid, utm_*) e customer (nome + email real) para atribuição correcta - Eventos enviados na confirmação bancária (não no POST /init): waiting_payment + paid (ou só paid se "Enviar somente venda paga" estiver activo) - Sem trackingParameters o UTMify recebe a venda mas o Facebook Ads pode não atribuir à campanha Headers em todos os pedidos (gerados pelo SDK — não repetir manualmente): Authorization: Bearer XPEND_SECRET_KEY X-VP-Trace: X-Xpend-Install-Id: XPEND_INSTALL_ID (opcional, vem no ZIP) Content-Type: application/json Webhook secret: whsec_... ou vhsec_... (ambos válidos) ### POST /payments/init — Criar transacção Body: { "orderId": "ORDER-123", "amount": 49.90, "customer": { "name", "email", "phone", "address", "city", "postalCode", "country" }, "items": [{ "id", "name", "quantity", "priceInCents" }], "trackingParameters": { "utm_source", "utm_medium", "utm_campaign", "fbclid", "gclid" } } Resposta:{ "transactionId": "txn_xxx", "amount": 49.90, "currency": "EUR" } Erro validação (contas novas): { "error": "...", "fields": ["customer.email", "items"] } ### POST /payments/mbway — Accionar MB WAY Body: { "transactionId": "txn_xxx", "phoneNumber": "912345678" } Resposta:{ "success": true, "message": "Notificação enviada. 4 minutos para aceitar." } Nota: phoneNumber com 9 dígitos, começa por 9, sem espaços ou prefixo. ### POST /payments/multibanco — Gerar referência Body: { "transactionId": "txn_xxx" } Resposta:{ "entity": "XXXXX", "reference": "XXXXXXXXX", "amount": 49.90, "expiresAt": "ISO date" } ### GET /payments/status — Consultar estado Query: ?transactionId=txn_xxx Resposta:{ "transactionId": "txn_xxx", "status": "pending|paid|failed|cancelled", "amount": 49.90, "paidAt": null } --- ## O que implementar no teu projecto ### Edge functions / API routes necessárias #### POST /api/xpend/init Recebe { orderId, amount, customer, items } → chama /payments/init → devolve { transactionId, amount } #### POST /api/xpend/mbway Recebe { transactionId, phoneNumber } → chama /payments/mbway → devolve { success } #### POST /api/xpend/multibanco Recebe { transactionId } → chama /payments/multibanco → devolve { entity, reference, amount, expiresAt } #### GET /api/xpend/status Query transactionId → chama /payments/status → devolve { status, paidAt } #### POST /api/xpend/webhook Receber notificações automáticas de pagamento. Verificar header X-Xpend-Signature: ```js const crypto = require('crypto') const signature = req.headers['x-xpend-signature'] const expected = 'sha256=' + crypto.createHmac('sha256', XPEND_WEBHOOK_SECRET).update(body).digest('hex') if (signature !== expected) return status 401 ``` Processar: payment.success → marcar encomenda como paga payment.failed → marcar como falhada Responder sempre 200 OK. ### Componente de checkout Selector de método: [MB WAY] [Multibanco] Fluxo MB WAY: 1. Input de telemóvel (9 dígitos, começa por 9) 2. POST /api/xpend/init → obter transactionId 3. POST /api/xpend/mbway com transactionId + phoneNumber 4. Mostrar "Abre o MB WAY — tens 4 minutos" 5. Polling GET /api/xpend/status cada 5s (máx 48× = 4 minutos) — só para UX no checkout; NÃO confirma pagamentos (lê BD já actualizada pelo webhook SIBS). Confirmação oficial: webhook payment.success. 6. paid → onSuccess() | failed/cancelled → mostrar erro Fluxo Multibanco: 1. POST /api/xpend/init → obter transactionId 2. POST /api/xpend/multibanco → obter entity + reference + amount + expiresAt 3. Mostrar card: Entidade: XXXXX Referência: XXX XXX XXX (formatar com espaços a cada 3 dígitos) Montante: XX,XX EUR (EXACTO — aviso importante) Válido até: data formatada [Copiar referência] 4. Polling GET /api/xpend/status cada 5s — fallback UX; confirmação oficial via webhook payment.success 5. paid → onSuccess() --- ## Configurar webhook depois de implementar Ir a: https://app.xpend.pt/dashboard/settings/webhook URL a configurar: https://teu-site.com/api/xpend/webhook --- ## Documentação completa https://app.xpend.pt/docs https://app.xpend.pt/docs/mbway https://app.xpend.pt/docs/multibanco https://app.xpend.pt/docs/webhooks https://app.xpend.pt/docs/ficheiro-integracao