# 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).