# Getting started (/en/docs/conta-digital/getting-started)

<QuickLinks>
  <QuickLink href="/docs/conta-digital/endpoints/authentication/post_oauth_token" title="Get access token" method="POST" path="/oauth/token" />

  <QuickLink href="/docs/conta-digital/endpoints/webhooks/post_webhook" title="Register webhook endpoint" method="POST" path="/transactions/webhooks" />

  <QuickLink href="/docs/conta-digital/endpoints/charges/post_payment" title="Create Pix charge" method="POST" path="/transactions/payment" />
</QuickLinks>

<Mermaid
  chart="`
flowchart LR
  A[&#x22;Credential in the dashboard&#x22;] --> B[&#x22;Token&#x22;]
  B --> C[&#x22;Webhook registration&#x22;]
  C --> D[&#x22;Charge&#x22;]
  D --> E[&#x22;PAYMENT_PAID webhook&#x22;]

  click A &#x22;https://hub.payzu.com.br&#x22; &#x22;Dashboard&#x22;
  click B &#x22;/docs/conta-digital/endpoints/authentication/post_oauth_token&#x22; &#x22;Get access token&#x22;
  click C &#x22;/docs/conta-digital/endpoints/webhooks/post_webhook&#x22; &#x22;Register webhook endpoint&#x22;
  click D &#x22;/docs/conta-digital/endpoints/charges/post_payment&#x22; &#x22;Create Pix charge&#x22;
  click E &#x22;/docs/conta-digital/webhooks&#x22; &#x22;Webhooks&#x22;

  style A fill:#f59e0b,stroke:#d97706,color:#ffffff
  style E fill:#14ce71,stroke:#0eb464,color:#ffffff
`"
/>

<Callout type="warn">
  The calls in this guide go to production: the charge created here is real.
</Callout>

<Steps>
  <Step>
    ### Create the credential [#create-the-credential]

    In the Digital Account dashboard, at [hub.payzu.com.br](https://hub.payzu.com.br), open the credentials area and create one with the scopes your integration uses. Creating it asks for the account holder's operation PIN.

    For this guide, select `PAYMENT_WRITE`, `PAYMENT_READ` and `WEBHOOK_WRITE`. What each scope allows is in [Scopes](/docs/conta-digital/authentication#scopes).

    The screen shows the `client_id`, the `client_secret` and the credential token (`pzu_…`).

    <Callout type="warn">
      The `client_secret` appears only once. Store it before leaving the screen.
    </Callout>
  </Step>

  <Step>
    ### Exchange the credential for a token [#exchange-the-credential-for-a-token]

    Send the `client_id` and the `client_secret` to [`POST /oauth/token`](/docs/conta-digital/endpoints/authentication/post_oauth_token). The returned token is valid for 15 minutes.

    <Tabs items="['curl', 'Node.js']">
      <Tab value="curl">
        ```bash
        curl -X POST https://api.hub.payzu.com.br/api/v1/oauth/token \
          -u "$PAYZU_CLIENT_ID:$PAYZU_CLIENT_SECRET" \
          -d 'grant_type=client_credentials'
        ```
      </Tab>

      <Tab value="Node.js">
        ```ts
        const credentials = Buffer.from(`${process.env.PAYZU_CLIENT_ID}:${process.env.PAYZU_CLIENT_SECRET}`).toString('base64');

        const response = await fetch('https://api.hub.payzu.com.br/api/v1/oauth/token', {
          method: 'POST',
          headers: {
            Authorization: `Basic ${credentials}`,
            'Content-Type': 'application/x-www-form-urlencoded',
          },
          body: 'grant_type=client_credentials',
        });

        const { access_token, expires_in } = await response.json();
        ```
      </Tab>
    </Tabs>

    ```json
    {
      "access_token": "eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIn0..mQ3Zy1hbVhpbXBsZQ.ZXhlbXBsbw.c2lnbmF0dXJl",
      "token_type": "Bearer",
      "expires_in": 900,
      "scope": "PAYMENT_WRITE PAYMENT_READ WEBHOOK_WRITE"
    }
    ```

    Send the `access_token` in `Authorization: Bearer` on the other calls. In the examples below, it is in `$PAYZU_TOKEN`. When the token expires, the API responds `401` with `TOKEN_INVALID`: request another one from the same route.
  </Step>

  <Step>
    ### Register the webhook [#register-the-webhook]

    Register the URL of your server that will receive the webhooks, with [`POST /transactions/webhooks`](/docs/conta-digital/endpoints/webhooks/post_webhook) (scope `WEBHOOK_WRITE`). The URL must be HTTPS and public.

    <Tabs items="['curl', 'Node.js']">
      <Tab value="curl">
        ```bash
        curl -X POST https://api.hub.payzu.com.br/api/v1/transactions/webhooks \
          -H "Authorization: Bearer $PAYZU_TOKEN" \
          -H "Content-Type: application/json" \
          -d '{
            "url": "https://sualoja.com.br/webhooks/payzu",
            "events": ["PAYMENT_PAID", "PAYMENT_EXPIRED"]
          }'
        ```
      </Tab>

      <Tab value="Node.js">
        ```ts
        const res = await fetch('https://api.hub.payzu.com.br/api/v1/transactions/webhooks', {
          method: 'POST',
          headers: {
            Authorization: `Bearer ${process.env.PAYZU_TOKEN}`,
            'Content-Type': 'application/json',
          },
          body: JSON.stringify({
            url: 'https://sualoja.com.br/webhooks/payzu',
            events: ['PAYMENT_PAID', 'PAYMENT_EXPIRED'],
          }),
        });
        const { id, secret } = await res.json();
        ```
      </Tab>
    </Tabs>

    The `201` response carries the `secret` that signs each webhook. It appears only in this response: store it. You can also register the webhook in the dashboard.

    If you get `403` with `TOKEN_MISSING_SCOPE`, the credential is missing a scope; its name comes in `details.scope`.
  </Step>

  <Step>
    ### Create the charge [#create-the-charge]

    Create a charge with [`POST /transactions/payment`](/docs/conta-digital/endpoints/charges/post_payment) (scope `PAYMENT_WRITE`). The amount goes in cents: `1500` is R$ 15.00.

    <Tabs items="['curl', 'Node.js']">
      <Tab value="curl">
        ```bash
        curl -X POST https://api.hub.payzu.com.br/api/v1/transactions/payment \
          -H "Authorization: Bearer $PAYZU_TOKEN" \
          -H "Content-Type: application/json" \
          -d '{
            "amount": 1500,
            "method": "PIX",
            "description": "Pedido 4821",
            "externalRef": "pedido-4821",
            "metadata": { "pedido": "4821", "canal": "checkout-web" },
            "customer": { "name": "Maria Souza", "document": "52998224725" }
          }'
        ```
      </Tab>

      <Tab value="Node.js">
        ```ts
        const res = await fetch('https://api.hub.payzu.com.br/api/v1/transactions/payment', {
          method: 'POST',
          headers: {
            Authorization: `Bearer ${process.env.PAYZU_TOKEN}`,
            'Content-Type': 'application/json',
          },
          body: JSON.stringify({
            amount: 1500,
            method: 'PIX',
            description: 'Pedido 4821',
            externalRef: 'pedido-4821',
            metadata: { pedido: '4821', canal: 'checkout-web' },
            customer: { name: 'Maria Souza', document: '52998224725' },
          }),
        });
        const cobranca = await res.json();
        ```
      </Tab>
    </Tabs>

    The `201` response carries the charge with `status: "PENDING"` and the Pix copy-and-paste code in `pix.qrCodeText`. Show it to the customer and generate the QR code from it. Repeating the call with the same `externalRef` returns the same charge (`200`) without creating another one.
  </Step>

  <Step>
    ### Receive the `PAYMENT_PAID` [#receive-the-payment_paid]

    When the customer pays, your server receives the `PAYMENT_PAID`:

    ```http
    POST /webhooks/payzu
    Content-Type: application/json
    X-Payzu-Event: PAYMENT_PAID
    X-Payzu-Delivery: cmu1r7x2k000a01s6h4f2b9qd
    X-Payzu-Timestamp: 1791210790441
    X-Payzu-Signature: sha256=8f3b2c1d...

    {
      "event": "PAYMENT_PAID",
      "id": "cmu1r7x2k000a01s6h4f2b9qd",
      "sentAt": "2026-10-05T14:33:10.441Z",
      "accountId": "cmu0z8k2a000001s6acct0001",
      "data": {
        "paymentId": "cmu2wbljx0000e8gtlic8q1gi",
        "status": "PAID",
        "amount": 1500,
        "serviceFee": 105,
        "netAmount": 1395,
        "metadata": { "pedido": "4821", "canal": "checkout-web" },
        "externalRef": "pedido-4821",
        "endToEndId": "E99999999202610051433a1b2c3d4e5f"
      }
    }
    ```

    Check the signature with the `secret` from the webhook registration, as in [Webhooks](/docs/conta-digital/webhooks#signature), and respond with any `2xx` within 10 seconds. Release the order here, on `PAYMENT_PAID`: the `externalRef` and the `metadata` from creation come back in `data`.
  </Step>
</Steps>

## Check without waiting for the webhook [#check-without-waiting-for-the-webhook]

Get the charge with [`GET /transactions/payment/{paymentId}`](/docs/conta-digital/endpoints/charges/get_payment) (scope `PAYMENT_READ`), using the `id` from the creation response or the `paymentId` from the webhook:

<Tabs items="['curl', 'Node.js']">
  <Tab value="curl">
    ```bash
    curl https://api.hub.payzu.com.br/api/v1/transactions/payment/hubp-20261005K7Q2M9XB4T127431 \
      -H "Authorization: Bearer $PAYZU_TOKEN"
    ```
  </Tab>

  <Tab value="Node.js">
    ```ts
    const res = await fetch('https://api.hub.payzu.com.br/api/v1/transactions/payment/hubp-20261005K7Q2M9XB4T127431', {
      headers: {
        Authorization: `Bearer ${process.env.PAYZU_TOKEN}`,
      },
    });
    const cobranca = await res.json();
    ```
  </Tab>
</Tabs>

To find the charge for an order, use [List charges](/docs/conta-digital/endpoints/charges/get_payments) with `?externalRef=`.

## Next steps [#next-steps]

<QuickLinks>
  <QuickLink href="/docs/conta-digital/charges" title="Pix charges" />

  <QuickLink href="/docs/conta-digital/webhooks" title="Webhooks" />

  <QuickLink href="/docs/conta-digital/withdrawals" title="Pix withdrawals" />

  <QuickLink href="/docs/conta-digital/error-codes" title="Error codes" />
</QuickLinks>