PayZuDocs

Every call carries a Bearer token that works like a password: how to send it, where to keep it safe, and what to do when the response comes back 401 or 403.

How to send

Every call requires two mandatory headers:

Authorization: Bearer YOUR_TOKEN
Content-Type: application/json

Example of an authenticated call to query the balance:

curl https://api.payzu.processamento.com/v1/user/balance \
  -H "Authorization: Bearer $PAYZU_TOKEN" \
  -H "Content-Type: application/json"
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();
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()
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)
<?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);

Where to store

Never expose the token on the front-end, in a public repository, or in logs. Treat it as a password: store it in a vault and inject it via environment variable.

Recommendations:

  • Google Secret Manager, ideal if you already use GCP.
  • HashiCorp Vault, for self-hosted setups.
  • AWS Secrets Manager, the AWS equivalent.
  • Environment variable in CI, never commit it.

Error format

Every error response from PayZu (4xx and 5xx) follows the same format. The most important field is requestId, which uniquely identifies the call in PayZu's internal logs.

{
  "errorCode": "PZA203",
  "message": "Acesso não permitido a partir do endereço de IP 203.0.113.10.",
  "statusCode": 403,
  "requestId": "cmp70zh4008dx01s6bwjb5bez"
}
FieldPurpose
errorCodeStable code from the catalog (e.g. PZA203). Program your logic against it, not the message.
messageDescription in PT of what happened. Use in logs, not for end users.
statusCodeHTTP response code (mirrors the status).
requestIdUnique ID of the call at PayZu. Send this ID when opening a support ticket, they trace it directly.

The full catalog, including the optional details[] and retryAfterSeconds fields, is in Error codes.

Always log the requestId in your errors: it is the first thing support asks for, and the logging snippet with the full retry strategy is in Error handling.

Opening support with the requestId

Token scopes

A token carries one or more scopes, and they define which routes it opens. The same token can have both DEPOSIT and WITHDRAW.

ScopeWhat it opens
DEPOSITIncoming Pix charges: POST /v1/pix, GET /v1/pix and GET /v1/pix/qr-code/:transactionId.
WITHDRAWPayments and outbound movement: POST /v1/withdraw, POST /v1/withdraw/qrcode, GET /v1/withdraw, POST /v1/internal-transfer, GET /v1/internal-transfer and POST /v1/refund/:transactionId.

DICT lookups (GET /v1/pix/key and POST /v1/pix/qrcode/read) accept either scope.

A token without the scope the route requires receives 403 with errorCode PZA200.

Resolving errors

401 Unauthorized

The most common causes, in order:

  1. Missing token, the Authorization header was not sent.
  2. Incorrect token, typo, extra whitespace, wrong encoding.
  3. Revoked token, it was rotated and you are using the old one.

Example response:

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

403 Forbidden

The token is valid but does not have permission for the operation. Check whether the endpoint requires an additional scope or whether your account is enabled for the resource (for example, internal transfer may require prior approval).

Rotation

If the token leaks, contact PayZu support immediately to issue a new token and revoke the previous one.

IP whitelist

The IP whitelist defines which addresses the account accepts calls from. The check runs on every token-authenticated /v1 route, on queries and on operations that move money, and uses the public source IP of the request.

Account situationResult
With a registered IPOnly accepts calls from the registered IPs. A call from any other IP receives 403 with errorCode PZA203, even with a valid token.
No registered IP and an active token with the WITHDRAW scope (withdrawal permission)Rejects every call with 403 and errorCode PZA205, with any token of the account, until an IP is registered.
No registered IP and no token with the WITHDRAW scopeAccepts calls from any IP.

The PZA203 and PZA205 messages carry the source IP that reached PayZu. A new egress IP is only accepted after it is registered, and the old IP keeps being accepted until it is removed.

Removing the last registered IP revokes, in the same operation, every token of the account with the WITHDRAW scope. From then on, calls with those tokens receive 401, and the account accepts calls from any IP with the remaining tokens.

How to manage

Management is self-service in the web panel, under the Security menu, IP whitelist section. Every addition or removal requires step-up confirmation (operation password), and all changes are recorded for audit.

Limits:

  • Up to 20 active IPs per account.
  • Up to 5 additions every 5 minutes.

An account locked for changes responds 403 with errorCode PZA204 when trying to add or remove IPs. In that case, contact support.

On this page