# Integração de referência Uma loja completa (Express + SQLite) que integra a FaciPay ponta a ponta — copie e adapte. A SDK inclui uma integração de referência completa — a **Wow Media Store** — em `examples/fake-store/`. É uma loja funcional com produtos, carrinho, checkout, webhook e páginas de retorno. Use-a como mapa para a sua própria integração. A integração de referência é **didática**. O webhook de exemplo **não** valida HMAC (está marcado como `TODO`). Em produção, siga sempre o guia de [Segurança](/pt/get-started/security) e valide a assinatura. ## Stack - **Backend:** Node.js + Express + TypeScript - **Base de dados:** SQLite (prepared statements) - **Frontend:** HTML + a FaciPay JS SDK ## Correr localmente ```bash cd examples/fake-store npm install cp .env.example .env # preencha com as suas credenciais de sandbox npm run dev # http://localhost:3000 ``` ## Anatomia ``` fake-store/ ├── src/ │ ├── server.ts # Express + rotas estáticas │ ├── routes/ │ │ ├── orders.ts # criar ordem a partir do carrinho │ │ ├── cart.ts # carrinho │ │ └── webhook.ts # recebe notificações da FaciPay │ ├── services/ │ │ ├── FaciPayService.ts # token + createPaymentOrder + getOrder │ │ └── OrderStatusService.ts # transições de estado │ ├── database/database.ts # SQLite + statements │ └── public/ │ ├── checkout.html # SDK: generateButton + callbacks │ ├── success.html pending.html pending-ref.html cancel.html └── .env.example ``` ## O fluxo, passo a passo A loja lê produtos da BD e mantém um carrinho por sessão. `checkout.html` chama `FaciPay(token).generateButton({...}).render('#facipay-checkout-button')`. O callback faz `POST /api/orders/create-from-cart`. O servidor recalcula o total, cria a ordem na BD e chama `FaciPayService.createOrder()` → devolve `referenceNumber`. A SDK abre o popup. Conforme o resultado, dispara `onApprove`, `onPending` ou `onCancel`, e a loja redireciona para `success` / `pending-ref` / `cancel`. A FaciPay chama `POST /api/webhook/payment`. O `OrderStatusService` atualiza o estado (`CON`/`CAN`/`PEN`) e executa ações pós-pagamento (limpar carrinho, etc.). ## Backend: criar a ordem O `FaciPayService.createOrder()` mostra o fluxo real de token + criação de ordem (ver [Autenticação](/pt/api-reference/authentication)): ```ts const accessToken = await this.getAccessToken(); const response = await fetch(`${this.apiUrl}/facipaypartner/createPaymentOrder`, { method: 'POST', headers: { 'Content-Type': 'application/json; charset=utf-8', Authorization: `Bearer ${accessToken}`, 'Accept-Language': 'pt', }, body: JSON.stringify({ externalTransactionId: data.orderId, clientId: newClientId, applicationUUID: this.publishableKey, // sem prefixo name: data.description, image: data.image, amount: data.amount, quantity: 1, additionalInfo: JSON.stringify({ returnUrl: data.additionalInfo.returnUrl, cancelUrl: data.additionalInfo.cancelUrl, webhookUrl: data.additionalInfo.webhookUrl, }), }), }); const res = await response.json(); return { referenceNumber: res.data.referenceNumber }; ``` O `additionalInfo` é apenas informativo — **não** é usado para configurar o webhook nem quaisquer URLs de retorno/cancelamento. O webhook é registado de forma global pela equipa FaciPay contra as suas credenciais, e a navegação de retorno/cancelamento é tratada pelos callbacks do SDK (`onApprove`/`onPending`/`onCancel`). ## Frontend: SDK real O `checkout.html` usa funcionalidades além do básico — referências múltiplas, info do cliente e atualização de quantidade: ```js await facipay.generateButton({ async createOrder() { /* POST /api/orders/create-from-cart → referenceNumber */ }, async onApprove(data, actions) { /* sincroniza estado, redireciona */ }, async onPending(data, actions) { /* mostra referência EMIS */ }, async onClick(data) { facipay.button.addCustomerInfo({ name, phone }); }, options: faciPayConfig.options, }).render('#facipay-checkout-button'); // Referências múltiplas (um item por linha do carrinho) facipay.button.addAllPaymentReferences(cart.items.map(item => ({ referenceNumber: String(item.id), referenceDescription: item.name, referenceAmount: item.price, referenceQuantity: item.quantity, referenceTotalQuantity: item.stock_quantity, }))); ``` Os scripts `facipay-profiles.js` e `facipay-settings.js` do exemplo são **andaimes do demo** (troca de credenciais entre perfis) — **não** fazem parte da SDK pública. Como validar o webhook corretamente (o que o exemplo ainda não faz).