# Autenticação (/docs/pix-processamento/authentication)



<QuickLinks>
  <QuickLink href="/docs/pix-processamento/endpoints" title="Referência da API" />

  <QuickLink href="/docs/pix-processamento/best-practices/security" title="Segurança" />

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

<Mermaid
  chart="`
flowchart LR
  A[&#x22;Sua aplicação&#x22;] -->|&#x22;Authorization: Bearer SEU_TOKEN&#x22;| B[&#x22;API PayZu&#x22;]
  B --> C{&#x22;Validação&#x22;}
  C -->|Token válido| OK[&#x22;200 OK&#x22;]
  C -->|Token ausente/inválido| E1[&#x22;401 Unauthorized&#x22;]
  C -->|Sem permissão| E2[&#x22;403 Forbidden&#x22;]

  click OK &#x22;/docs/pix-processamento/endpoints&#x22; &#x22;Lista de endpoints&#x22;
  click E1 &#x22;#401-unauthorized&#x22; &#x22;Resolver 401&#x22;
  click E2 &#x22;#403-forbidden&#x22; &#x22;Resolver 403&#x22;
  click A &#x22;/docs/pix-processamento/best-practices/security&#x22; &#x22;Onde guardar o token&#x22;

  style A fill:#f59e0b,stroke:#d97706,color:#ffffff
  style OK fill:#14ce71,stroke:#0eb464,color:#ffffff
  style E1 fill:#ef4444,stroke:#dc2626,color:#ffffff
  style E2 fill:#ef4444,stroke:#dc2626,color:#ffffff
`"
/>

## Como enviar [#como-enviar]

Toda chamada precisa de **dois headers obrigatórios**:

```http
Authorization: Bearer SEU_TOKEN
Content-Type: application/json
```

Exemplo de chamada autenticada para consultar o saldo:

<Tabs items="['curl', 'Node.js', 'Python', 'Go', 'PHP']">
  <Tab value="curl">
    ```bash
    curl https://api.payzu.processamento.com/v1/user/balance \
      -H "Authorization: Bearer $PAYZU_TOKEN" \
      -H "Content-Type: application/json"
    ```
  </Tab>

  <Tab value="Node.js">
    ```ts
    const res = await fetch('https://api.payzu.processamento.com/v1/user/balance', {
      headers: {
        Authorization: `Bearer ${process.env.PAYZU_TOKEN}`,
        'Content-Type': 'application/json',
      },
    });
    const balance = await res.json();
    ```
  </Tab>

  <Tab value="Python">
    ```python
    import os
    import requests

    res = requests.get(
        'https://api.payzu.processamento.com/v1/user/balance',
        headers={
            'Authorization': f'Bearer {os.environ["PAYZU_TOKEN"]}',
            'Content-Type': 'application/json',
        },
    )
    balance = res.json()
    ```
  </Tab>

  <Tab value="Go">
    ```go
    req, _ := http.NewRequest("GET", "https://api.payzu.processamento.com/v1/user/balance", nil)
    req.Header.Set("Authorization", "Bearer " + os.Getenv("PAYZU_TOKEN"))
    req.Header.Set("Content-Type", "application/json")
    res, err := http.DefaultClient.Do(req)
    ```
  </Tab>

  <Tab value="PHP">
    ```php
    <?php
    $ch = curl_init('https://api.payzu.processamento.com/v1/user/balance');
    curl_setopt_array($ch, [
      CURLOPT_RETURNTRANSFER => true,
      CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('PAYZU_TOKEN'),
        'Content-Type: application/json',
      ],
    ]);
    $balance = json_decode(curl_exec($ch), true);
    ```
  </Tab>
</Tabs>

## Onde guardar [#onde-guardar]

<Callout type="warn">
  Nunca expõe o token no front-end, em repositório público ou em logs.
  Trata como senha: armazena em vault e injeta por variável de ambiente.
</Callout>

Recomendações:

* **Google Secret Manager**, ideal se você já usa GCP.
* **HashiCorp Vault**, pra setups self-hosted.
* **AWS Secrets Manager**, equivalente AWS.
* **Variável de ambiente em CI**, nunca commita.

## Formato de erro [#formato-de-erro]

**Toda resposta de erro da PayZu** (4xx e 5xx) segue o mesmo formato. O campo mais importante é o `requestId`, ele identifica univocamente a chamada nos logs internos da PayZu.

```json
{
  "errorCode": "PZA203",
  "message": "Acesso não permitido a partir deste endereço de IP.",
  "statusCode": 403,
  "requestId": "cmp70zh4008dx01s6bwjb5bez"
}
```

| Campo        | Para que serve                                                                                      |
| ------------ | --------------------------------------------------------------------------------------------------- |
| `errorCode`  | Código estável do catálogo (ex.: `PZA203`). Programe sua lógica por ele, não pela mensagem.         |
| `message`    | Descrição em PT do que aconteceu. Use no log, não para usuário final.                               |
| `statusCode` | Código HTTP da resposta (espelha o status).                                                         |
| `requestId`  | **ID único da chamada na PayZu**. Envie esse ID ao abrir chamado de suporte, eles rastreiam direto. |

O catálogo completo, com os campos opcionais `details[]` e `retryAfterSeconds`, está em [Códigos de erro](/docs/pix-processamento/error-codes).

**Sempre logue o `requestId` nos seus erros**: é o primeiro dado que o suporte pede, e o snippet de logging com a estratégia completa de retry está em [Tratamento de erros](/docs/pix-processamento/best-practices/errors).

### Abrir suporte com o requestId [#abrir-suporte-com-o-requestid]

<QuickLinks>
  <QuickLink href="https://suporte.payzu.com.br/portal/pt-br/newticket?departmentId=1103699000000006907&layoutId=1103699000000074011" title="Abrir chamado" />
</QuickLinks>

## Resolvendo erros [#resolvendo-erros]

### 401 Unauthorized [#401-unauthorized]

As causas mais comuns, em ordem:

1. **Token ausente**, header `Authorization` não foi enviado.
2. **Token incorreto**, typo, espaço em branco extra, encoding errado.
3. **Token revogado**, foi rotacionado e você está usando o antigo.

Exemplo de resposta:

```json
{
  "errorCode": "PZA100",
  "message": "Autenticação necessária ou token inválido.",
  "statusCode": 401,
  "requestId": "cmou00000abcdef01s6ghij1k2lm"
}
```

### 403 Forbidden [#403-forbidden]

O token é válido mas não tem permissão para a operação. Verifica se o
endpoint exige escopo adicional ou se sua conta está habilitada para o
recurso (por exemplo, transferência interna pode exigir aprovação prévia).

## Rotação [#rotação]

Se o token vazar, contata o suporte da PayZu imediatamente para emissão
de novo token e revogação do anterior.

## Whitelist de IP para saques e transferências [#whitelist-de-ip-para-saques-e-transferências]

Camada extra de proteção para as operações que movem dinheiro para fora da conta. Quando a whitelist está ativa, `POST /v1/withdraw`, `POST /v1/withdraw/qrcode` e `POST /v1/internal-transfer` só aceitam chamadas dos IPs cadastrados. Qualquer outro IP recebe `403` com `errorCode` `PZA203`, mesmo com token válido. As consultas `GET` dessas mesmas rotas passam pela mesma validação.

### Como gerenciar [#como-gerenciar]

A gestão é self-service no painel web, no menu **Segurança**, seção **Whitelist de IP**. Cada adição ou remoção exige confirmação step-up (senha de operação), e todas as alterações ficam registradas em auditoria.

Limites:

* Até **20 IPs ativos** por conta.
* Até **5 cadastros a cada 5 minutos**.

<Callout type="warn">
  Conta travada para alterações responde `403` com `errorCode` `PZA204` ao tentar
  adicionar ou remover IPs. Nesse caso, contate o suporte.
</Callout>

### Boas práticas [#boas-práticas]

* Cadastre os **IPs de saída fixos** da sua infraestrutura (NAT/egress). IP dinâmico de máquina local vai quebrar na primeira troca.
* Ao migrar de infraestrutura, **adicione o novo IP antes de remover o antigo**. Assim os saques continuam fluindo durante a transição.
* Trate `PZA203` no seu código como erro de configuração, não de negócio: alerta o time de infra em vez de retentar.
