# Multi-tenant com virtualAccount (/docs/pix-processamento/best-practices/multi-tenant)



<QuickLinks>
  <QuickLink href="/docs/pix-processamento/endpoints/pix-operations/post_pix" title="POST /pix" />

  <QuickLink href="/docs/pix-processamento/endpoints/reports/get_user_transactions" title="GET /user/transactions" />

  <QuickLink href="/docs/pix-processamento/glossary" title="Glossário" />
</QuickLinks>

Se você opera várias marcas, lojas, filiais ou parceiros em uma só conta PayZu, passe `virtualAccount` (até 50 caracteres) em cada criação. Esse campo:

* **Volta em todo callback**, você sabe imediatamente de qual tenant é a transação.
* **Pode ser filtrado** em `GET /user/transactions` e `GET /pix`, listas isoladas por tenant.
* **Dispensa contas filhas**, uma só conta PayZu serve N tenants.

<Mermaid
  chart="`
flowchart LR
  L1[&#x22;Loja RJ&#x22;] -->|&#x22;virtualAccount=loja-rj-01&#x22;| API[&#x22;API PayZu&#x22;]
  L2[&#x22;Loja SP&#x22;] -->|&#x22;virtualAccount=loja-sp-02&#x22;| API
  L3[&#x22;Marketplace&#x22;] -->|&#x22;virtualAccount=mkt-acme&#x22;| API
  API --> CB[&#x22;Callbacks preservam virtualAccount&#x22;]
  CB --> R[&#x22;Você roteia por tenant&#x22;]

  click API &#x22;/docs/pix-processamento/endpoints/pix-operations/post_pix&#x22; &#x22;POST /pix&#x22;
  click CB &#x22;/docs/pix-processamento/webhooks&#x22; &#x22;Webhooks&#x22;
  click R &#x22;/docs/pix-processamento/best-practices/callbacks&#x22; &#x22;Handler de callbacks&#x22;

  style API fill:#14ce71,stroke:#0eb464,color:#ffffff
  style R fill:#3b82f6,stroke:#1d4ed8,color:#ffffff
`"
/>

## Convenções de nome [#convenções-de-nome]

| Padrão                   | Quando usar                        |
| ------------------------ | ---------------------------------- |
| `tenant-{slug}`          | Plataforma SaaS multi-cliente.     |
| `loja-{cidade}-{numero}` | Rede com lojas físicas.            |
| `mkt-{partner}`          | Marketplace com vários vendedores. |
| `filial-{codigo}`        | Filiais de uma mesma empresa.      |
| `branch-{branchId}`      | Genérico, em inglês.               |

<Callout type="info">
  Tamanho máximo: **50 caracteres**. Use formato estável e legível. Evite caracteres especiais e espaços.
</Callout>

## Criar com `virtualAccount` [#criar-com-virtualaccount]

<Tabs items="['Request', 'Response', 'Callback']">
  <Tab value="Request">
    ```json
    {
      "amount": 99.90,
      "clientReference": "order-1234",
      "virtualAccount": "loja-rj-01",
      "callbackUrl": "https://seusite.com.br/webhooks/payzu"
    }
    ```
  </Tab>

  <Tab value="Response">
    ```json
    {
      "id": "PAYZU20251123104518DF75D20A8F",
      "status": "PENDING",
      "amount": 99.90,
      "clientReference": "order-1234",
      "virtualAccount": "loja-rj-01",
      "qrCodeText": "00020126870014br.gov.bcb.pix..."
    }
    ```
  </Tab>

  <Tab value="Callback">
    ```json
    {
      "id": "PAYZU20251123104518DF75D20A8F",
      "type": "DEPOSIT",
      "status": "COMPLETED",
      "amount": 99.90,
      "clientReference": "order-1234",
      "virtualAccount": "loja-rj-01",
      "paidAt": "2025-11-23T10:46:26.986Z"
    }
    ```
  </Tab>
</Tabs>

## Listar só de um tenant [#listar-só-de-um-tenant]

<Tabs items="['curl', 'Node.js']">
  <Tab value="curl">
    ```bash
    curl "https://api.payzu.processamento.com/v1/user/transactions?virtualAccount=loja-rj-01&dateFrom=2025-11-01" \
      -H "Authorization: Bearer $TOKEN" \
      -H "Content-Type: application/json"
    ```
  </Tab>

  <Tab value="Node.js">
    ```ts
    const url = new URL('https://api.payzu.processamento.com/v1/user/transactions');
    url.searchParams.set('virtualAccount', 'loja-rj-01');
    url.searchParams.set('dateFrom', '2025-11-01');

    const res = await fetch(url, {
      headers: {
        Authorization: `Bearer ${process.env.PAYZU_TOKEN}`,
        'Content-Type': 'application/json',
      },
    });
    ```
  </Tab>
</Tabs>

## Rotear o callback [#rotear-o-callback]

```ts
async function payzuWebhook(tx: PayzuCallback) {
  const tenantId = tx.virtualAccount;
  if (!tenantId) {
    log.warn('callback sem virtualAccount', { id: tx.id });
    return;
  }

  const handler = tenantHandlers[tenantId];
  if (!handler) {
    log.error('tenant desconhecido', { tenantId, id: tx.id });
    return;
  }

  await handler.process(tx);
}
```

## `virtualAccount` vs `clientReference` [#virtualaccount-vs-clientreference]

Os dois são campos **independentes e complementares**. Use os dois sempre.

| Campo             | Granularidade | Propósito                         |
| ----------------- | ------------- | --------------------------------- |
| `clientReference` | Por transação | Idempotência + lookup por pedido. |
| `virtualAccount`  | Por tenant    | Roteamento + filtro de listagens. |

Basta enviar os dois campos no mesmo payload de criação, como no exemplo acima.

## Armadilhas comuns [#armadilhas-comuns]

| Armadilha                                                 | Sintoma                                  |
| --------------------------------------------------------- | ---------------------------------------- |
| Usar `clientReference` pra identificar tenant             | Não filtra em listagens, complica lookup |
| `virtualAccount` muda toda vez (timestamp, slug variável) | Listagem fica fragmentada                |
| Não tratar callback sem `virtualAccount`                  | Roteamento crasha em transações legadas  |
| Hardcode de tenants no handler                            | Onboarding manual a cada novo cliente    |
