Skip to content

Get started

This guide takes you from your first key to your first paid payment link. Start in the sandbox. Nothing here charges real money until you switch the key to production.

The cockpit is https://app.pgz.link. The API is https://api.pgz.link.

1. Create the API key

In the cockpit, open Configurações → Integrações (Settings → Integrations). At the top right, keep the environment selector on Sandbox.

Under Chave de API (API key), fill in Nome da chave (key name — for example, "Test backend") and click Gerar chave (Generate key).

The key starts with pgz_test_ in the sandbox and pgz_live_ in production.

The key is shown only once

The plaintext key is shown only at creation time. Store it somewhere safe. If you lose the key, there is no way to recover it — generate a new one and delete the old one.

What exists and what does not:

  • Revoke: yes. The trash button revokes the key. It stops working immediately.
  • Rotate: does not exist. To replace a key, generate a new one and revoke the old one.
  • Scopes: you do not choose them. Every key created in the cockpit gets full access to the API.

2. Test vs live: test never charges

Each key belongs to one environment, and the two are isolated.

  • A pgz_test_ key never reaches the payment provider and never creates a real charge.
  • A pgz_live_ key operates in production.

Resources created in one environment are invisible in the other.

Production uses real money

When creating keys in Live, the cockpit warns: "Chaves de produção criam cobranças com dinheiro real." (Production keys create charges with real money.) Always start in the sandbox.

3. Where to put the key

The key goes in the Authorization header, in Bearer format:

Authorization: Bearer pgz_test_...

This command creates a payment link for R$ 2.500,00. Replace the key with yours.

bash
curl https://api.pgz.link/v1/payment_links \
  -H "Authorization: Bearer pgz_test_..." \
  -H "Idempotency-Key: 3f1a9b2c-6d4e-4a71-9c2f-8e5b1d0a7c33" \
  -H "Content-Type: application/json" \
  -d '{ "amount": 250000, "currency": "BRL", "reference": "pedido-8842" }'

You get:

json
{
  "id": "pl_9f8c...",
  "checkout_url": "https://sualoja.pgz.link/pay/pl_9f8c...",
  "reference": "pedido-8842",
  "status": "active"
}
  • amount: 250000 is R$ 2.500,00 (value in cents).
  • reference is your reconciliation key. It comes back on every read and every webhook. Use your order number.
  • The Idempotency-Key header protects against duplicate charges: if the same request arrives twice (a network failure, a retry), the second one returns the first response instead of creating another charge. Use a unique string per request — we recommend a UUID.

The checkout_url lives at sualoja.pgz.link. Here, sualoja is your store slug — the identifier you set in the cockpit. With a custom domain (step 9), that address becomes yours.

Take the checkout_url and send it to your customer. They pay on that page.

The main path is PIX. Credit card also exists, with installments — the details are in the Reference.

5. Register the webhook, generate the secret, and verify the signature

The webhook is how you learn that the payment was confirmed.

Under Configurações → Integrações → Webhook, fill in URL de webhook (webhook URL) with your server's address and click Salvar URL (Save URL). Then click Gerar secret (Generate secret).

The secret is shown only once

The signing secret is shown only when you generate it. Store it. To replace it, use Rotacionar secret (Rotate secret) — the new value is also shown only once.

On each event, the platform sends a POST to your URL with this header:

Pagooz-Signature: t=1700000000,v1=<hex>

To verify: compute the HMAC-SHA256 of the text "{t}.{body}" (the timestamp, a dot, and the raw request body) using your secret, and compare it to the v1 value. Reject deliveries where t is more than 5 minutes from the current time.

js
const crypto = require("crypto");

function verifyPagoozSignature(rawBody, header, secret) {
  const parts = Object.fromEntries(header.split(",").map((kv) => kv.split("=")));
  const t = Number(parts.t);
  if (!t || Math.abs(Date.now() / 1000 - t) > 300) return false; // 5 min
  const expected = crypto.createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex");
  const a = Buffer.from(expected);
  const b = Buffer.from(parts.v1 || "");
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}

The events you receive: payment.succeeded, payment.failed, and payment.cancelled.

Always respond 2xx

A delivery only counts as successful with a 2xx response. A failure triggers retries with growing delays. The same event may arrive more than once — process each event.id exactly once.

6. Simulate a payment in the sandbox

In the sandbox you close the loop without spending money. Simulate the outcome of a test link:

bash
curl https://api.pgz.link/v1/payment_links/pl_9f8c.../simulate_payment \
  -H "Authorization: Bearer pgz_test_..." \
  -H "Content-Type: application/json" \
  -d '{ "outcome": "succeeded" }'

This moves the payment to the requested state and fires the matching webhook, signed the same way as in production. outcome values: succeeded, failed, expired.

This endpoint only exists in the sandbox. With a pgz_live_ key, it returns 403.

7. How to know it worked

Two ways:

  1. Your webhook. Did it receive payment.succeeded for the right reference? That is the source of truth.
  2. The "Últimas entregas" (Recent deliveries) panel in the cockpit (under Integrations). It shows the latest webhook deliveries: the event, when, the status, and the number of attempts. An Atualizar (Refresh) button reloads the list.

"Recent deliveries" does not show the response body

The panel shows event, time, status, and attempts. It does not show your server's response body or the payload sent. To debug the content, log the request on your side.

There is no event lookup endpoint

Events are delivered by webhook. There is no API endpoint to list or fetch past events. If your server can go down, store the webhooks you receive.

8. Move to production

Once the flow works in the sandbox:

  1. In the cockpit, switch the environment selector to Live.
  2. Generate a pgz_live_ key (step 1, now in Live).
  3. Register the webhook URL and generate the production secret — they are separate from the sandbox ones.
  4. Replace the key in your requests with the pgz_live_ key.

Live confirms real payments

When configuring the webhook in Live, the cockpit warns: "Webhooks de produção confirmam pagamentos reais." (Production webhooks confirm real payments.) Check everything in the sandbox first.

9. Use a custom domain for checkout

By default, the checkout_url lives at sualoja.pgz.link. You can use your own address, like pay.sualoja.com.br.

Under Configurações → Integrações → Domínio (Domain), fill in Domínio and click Adicionar (Add). The platform shows a CNAME record — type, name, and value. Create that CNAME in the panel where you bought the domain.

Then click Verificar (Verify).

The domain does not verify itself

There is no automatic verification. After you create the CNAME, you click Verificar. The status goes through: pendingverifyingactive (or failed, with the reason). DNS propagation can take a few minutes; if it has not found the CNAME yet, try again later.

While the domain is not active, checkout keeps working at sualoja.pgz.link. You are never left without checkout.