npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

pacote-pagbank

v0.0.9

Published

[![npm version](https://badge.fury.io/js/nome-do-componente.svg)](https://www.npmjs.com/package/pacote-pagbank)

Downloads

554

Readme

Componente de integração com o PagBank

npm version

Instalação

Para instalar este pacote no seu projeto NEXT, use o npm:

npm i pacote-pagbank

índice

Sobre o componente

Este é um componente que tem por objetivo facilitar a implementação pagamentos via pix, cartão de crédito e boleto em aplicações utilizando como principal integrador os serviços de API do PagBank.

Informações cruciais para o público que irá usar esse componente

É de suma importância que você usuário tenha ciência que criar os próprios componentes front-end para cartão de crédito, boleto e pix. Toda estrutura base para tais componentes serão abordados nesta documentação. Basicamente, você terá que:

  • Fazer a chamada de hooks;
  • Criar o corpo de requisição;
  • Criar arquivo .env.local na raiz do projeto e inserir seu token;
  • Fazer o front-end com o uso da resposta de requisição;
  • Modificar o next.config.mjs;
/** @type {import('next').NextConfig} */
const nextConfig = {
  experimental: {
    esmExternals: "loose",
  },
  transpilePackages: ["pacote-pagbank"],
  webpack: (config) => {
    config.resolve.extensions.push(".ts", ".tsx");
    return config;
  },
};

export default nextConfig;
  • Na pasta src, criar pages > api > pagbank.ts e publicKey.ts (Ambos arquivos serão disponibilizados pra você nessa documentação).
pagbank.ts
import {
  PaymentBoleto,
  PaymentCartao,
  PaymentPix,
} from "pacote-pagbank/src/utils/interface";
import type { NextApiRequest, NextApiResponse } from "next";

interface BodyData {
  authorization: string;
  bodyData: PaymentPix | PaymentBoleto | PaymentCartao;
}

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  if (req.method !== "POST") {
    return res.status(405).json({ message: "Method not allowed" });
  }

  const { authorization, bodyData }: BodyData = req.body;

  try {
    const response = await fetch("https://sandbox.api.pagseguro.com/orders", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        Authorization: authorization,
      },
      body: JSON.stringify(bodyData),
    });

    const data = await response.json();

    console.log(data);

    if (!response.ok) {
      return res
        .status(response.status)
        .json({ message: "Erro na requisição para o PagBank", error: data });
    }
    res.status(200).json(data);
  } catch {
    res.status(500).json({ message: "Erro no servidor" });
  }
}
publicKey.ts
import { NextApiRequest, NextApiResponse } from "next";

export default async function handlePublicKey(
  req: NextApiRequest,
  res: NextApiResponse
) {
  const { authorization } = req.body;

  if (!authorization) {
    return res.status(400).json({ error: "Authorization token is required" });
  }

  const options = {
    method: "POST",
    headers: {
      Authorization: authorization,
      "content-type": "application/json",
    },
    body: JSON.stringify({ type: "card" }),
  };

  try {
    const response = await fetch(
      "https://sandbox.api.pagseguro.com/public-keys",
      options
    );

    if (!response.ok) {
      throw new Error("Erro desconhecido");
    }

    const result = await response.json();
    return res.status(200).json(result);
  } catch (err) {
    if (err instanceof Error) {
      return res.status(500).json({ error: err.message });
    } else {
      return res.status(500).json({ error: "Erro no servidor" });
    }
  }
}

Primeiros passos

  • Crie sua conta no Portal do Desenvolvedor da PagBank para ter uma visão geral de tudo que está acontecendo relativo a sua aplicação local ou em ambiente de produção.

Sua conta será importante pois será necessário ter acesso ao seu token para prosseguir com o uso do nosso componente.

Como obter sua chave de acesso em Sandbox (Ambiente local)

  • Acesse sua contade de Sandbox;
  • Localize o menu Perfis de Integração;
  • Clique em Vendedor. O token de sandbox estará disponível na seção Credenciais.

Como obter sua chave de acesso em Produção

  • Acesse a sua conta PagSeguro;
  • No menu lateral, selecione Venda online;
  • Vá na opção Integrações;
  • E pressione o botão Gerar Token.

Caso você já tenha gerado o token anteriormente, ele será enviado ao seu e-mail de cadastro por segurança. Nesse caso, basta pressionar Enviar por e-mail. Se preferir, você também pode gerar um novo token, mas importante: nesse caso, o token antigo deixará de funcionar.

Inserindo o token no componente

Para que você consiga usufruir plenamente esse componente, é necessário acessar criar um arquivo chamado .env.local na raiz do projeto e inserir seu token.

alt text

Para o uso deste componente recomendamos fortemente o estudo da documentação do PagBank Developer, e em especial, a API Pedidos que usamos extensamente.

Entendendo sobre os componentes pix, cartão crédito e boleto

Cartão de Crédito

O método de pagamento via cartão de crédito é o que envolve mais etapas até a sua finalização.

Para realizar o pagamento com cartão de crédito, é necessário fazer a criptografia de tal cartão.

O PagBank disponibiliza um SDK, dessa forma, a criptografia dos dados sensíveis do Cartão de Crédito é feita diretamente no navegador, reduzindo o seu escopo PCI. Tal SDK não requer chamadas ao servidor, ou seja, a criptografia é feita localmente com uma chave pública e o algoritmo RSA.

<Script
  src="https://assets.pagseguro.com.br/checkout-sdk-js/rc/dist/browser/pagseguro.min.js"
  strategy="afterInteractive"
  onLoad={() => console.log("PagBank SDK carregado")}
/>

A função que realiza a criptografia fornece uma string que pode ser descriptografada usando a chave privada, a qual apenas o PagBank tem acesso.

Abaixo mostraremos o fluxo e por seguinte explicaremos o mesmo.

alt text

Do componente para obter a chave pública, fazemos uma requisição específica para o PagBank, como por exemplo:

useEffect(() => {
  const token = process.env.NEXT_PUBLIC_TOKEN;
  if (token) {
    postToPagSeguro("Bearer " + token);
  } else {
    toast.error("Erro no token!");
  }
}, []);

Após recebermos a resposta dessa requisição, temos acesso a chave pública que por sua vez nos permite fazer a criptografia do cartão através do SDK. O response vem no formato a seguir, por exemplo:

{
  "public_key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr+ZqgD892U9/HXsa7XqBZUayPquAfS8CPIzdBOtTQCIwrLn2FxI83Clcg55W8gkFSOS6rWNbG5qFZWMll6yl02HtunalHmUlRUL66YeGXdMDC2PuRcmZbGO5a/2tbVppW6mfSWG3NPRpgwIDAQAB",
  "created_at": 1577836800000
}

Em nosso componente de cartão, a forma como inserimos a chave pública se dá da seguinte maneira, por exemplo:

const handlePayment = () => {
  if (!isFormValid()) {
    toast.error("Por favor, preencha todos os campos corretamente.");
    return;
  }

  if (typeof window !== "undefined" && window.PagSeguro) {
    const card = window.PagSeguro.encryptCard({
      publicKey: publicKey?.public_key || "",
      holder: cardDetails.holder,
      number: cardDetails.number,
      expMonth: cardDetails.expMonth,
      expYear: cardDetails.expYear,
      securityCode: cardDetails.securityCode,
    });

    setEncryptedCard(card.encryptedCard);
  }
};

Por fim, com o cartão criptografado, fazemos a criação de ordem através do handleCreateOrder():

const handleCreateOrder = async (encryptedCard: string) => {
  const requestBody: PaymentCartao = {
    reference_id: "ex-00001",
    customer: {
      name: "Jose da Silva",
      email: "[email protected]",
      tax_id: "12345678909",
      phones: [
        {
          country: "55",
          area: "11",
          number: "999999999",
          type: "MOBILE",
        },
      ],
    },
    items: [
      {
        reference_id: "referencia do item",
        name: "nome do item",
        quantity: 1,
        unit_amount: 500,
      },
    ],
    shipping: {
      address: {
        street: "Avenida Brigadeiro Faria Lima",
        number: "1384",
        complement: "apto 12",
        locality: "Pinheiros",
        city: "São Paulo",
        region_code: "SP",
        country: "BRA",
        postal_code: "01452002",
      },
    },
    notification_urls: ["https://meusite.com/notificacoes"],
    charges: [
      {
        reference_id: "referencia da cobranca",
        description: "descricao da cobranca",
        amount: {
          value: 500,
          currency: "BRL",
        },
        payment_method: {
          type: "CREDIT_CARD",
          installments: 1,
          capture: true,
          card: {
            encrypted: encryptedCard,
            store: false,
          },
          holder: {
            name: "Jose da Silva",
            tax_id: "65544332211",
          },
        },
      },
    ],
  };

  const token = process.env.NEXT_PUBLIC_TOKEN;
  if (token) {
    postToPagBank("Bearer " + token, requestBody);
  } else {
    toast.error("Erro no token!");
  }
};

Dentro do handleCreateOrder() temos o requestBody que é utilizado para inserir os dados do pedido.

Por fim, fazemos o envio da ordem com o cartão criptografado:

useEffect(() => {
  if (encryptedCard) {
    handleCreateOrder(encryptedCard);
  }
}, [encryptedCard]);

RequestBody

No handleCreateOrder(), temos que inserir o requestBody, algo que é obrigatório para as requisições de criação de pedidos. O PagBank tem um padrão para os requests, em nosso componente optamos por criar interfaces para facilitar o uso. Abaixo segue um exemplo de requestBody para os pedidos com pagamento via cartão de crédito:

{
  "reference_id": "ex-00001",
  "customer": {
    "name": "Jose da Silva",
    "email": "[email protected]",
    "tax_id": "12345678909",
    "phones": [
      {
        "country": "55",
        "area": "11",
        "number": "999999999",
        "type": "MOBILE"
      }
    ]
  },
  "items": [
    {
      "reference_id": "referencia do item",
      "name": "nome do item",
      "quantity": 1,
      "unit_amount": 500
    }
  ],
  "shipping": {
    "address": {
      "street": "Avenida Brigadeiro Faria Lima",
      "number": "1384",
      "complement": "apto 12",
      "locality": "Pinheiros",
      "city": "São Paulo",
      "region_code": "SP",
      "country": "BRA",
      "postal_code": "01452002"
    }
  },
  "notification_urls": ["https://meusite.com/notificacoes"],
  "charges": [
    {
      "reference_id": "referencia da cobranca",
      "description": "descricao da cobranca",
      "amount": {
        "value": 500,
        "currency": "BRL"
      },
      "payment_method": {
        "type": "CREDIT_CARD",
        "installments": 1,
        "capture": true,
        "card": {
          "encrypted": "V++53ir0qvoK/rUSzNjCqP8Hz9ZTa+HohR779n63CV+NvCeYj4J4lQevL4NKN7Di3BxKQGqfQW5cfS7/4rHw4w8URuOV/j/mGau2GXxkKQ6/szJ6BQr//C4e4XgfCHDwcONQhuPDHMdOB1C+4lzyBbsPJUZ/8TUQrxhMMiMFjwGeg62uf7cUqdFjp+Q5dqJXwhLgH3d1EoX+JKStBLqVzF0lW3gHtFOyfvFhuxxBgB0xrzTKfbTqnL5aSYBoGXRFM0gLodMm6knx7bW+syThxyQffnaigCwj2aNohsu+fuXII+3WnlgrHQxaBx3ChRuWKy+loV2L2USiGulp/bPEcg==",
          "store": false
        },
        "holder": {
          "name": "Jose da Silva",
          "tax_id": "65544332211"
        }
      }
    }
  ]
}

Nessa etapa do requestBody, após entender seu fluxo e como setar cada campo, é sugerido para os usuários que utilizarem este componente que insiram sua lógica para que preencham tais requestBody, é importante frizar da importância de fazer uma requisição por item.

Caso existam muitos pedidos, sugerimos que criem uma fila desses pedidos e processem um por vez.

ResponseBody

Segundo a documentação do PagBank, existem dois tipos de respostas para cartões:

  • Autorização bem-sucedida. Retorna status AUTHORIZED ou PAID.
  • Autorização negada. Retorna status DECLINED.

Essas respostas você pode acessar através da váriavel data no componente de cartão de crédito.

Aqui está um exemplo:

{
  "id": "ORDE_1E38BD2E-F2CC-4D9C-9727-787CDFBCA7CE",
  "reference_id": "ex-00001",
  "created_at": "2023-02-08T15:15:11.408-03:00",
  "customer": {
    "name": "Jose da Silva",
    "email": "[email protected]",
    "tax_id": "12345678909",
    "phones": [
      {
        "type": "MOBILE",
        "country": "55",
        "area": "11",
        "number": "999999999"
      }
    ]
  },
  "items": [
    {
      "reference_id": "referencia do item",
      "name": "nome do item",
      "quantity": 1,
      "unit_amount": 500
    }
  ],
  "shipping": {
    "address": {
      "street": "Avenida Brigadeiro Faria Lima",
      "number": "1384",
      "complement": "apto 12",
      "locality": "Pinheiros",
      "city": "São Paulo",
      "region_code": "SP",
      "country": "BRA",
      "postal_code": "01452002"
    }
  },
  "charges": [
    {
      "id": "CHAR_67FC568B-00D8-431D-B2E7-755E3E6C66A0",
      "reference_id": "referencia da cobranca",
      "status": "PAID",
      "created_at": "2023-02-08T15:15:11.881-03:00",
      "paid_at": "2023-02-08T15:15:12.000-03:00",
      "description": "descricao da cobranca",
      "amount": {
        "value": 500,
        "currency": "BRL",
        "summary": {
          "total": 500,
          "paid": 500,
          "refunded": 0
        }
      },
      "payment_response": {
        "code": "20000",
        "message": "SUCESSO",
        "reference": "032416400102"
      },
      "payment_method": {
        "type": "CREDIT_CARD",
        "installments": 1,
        "capture": true,
        "card": {
          "brand": "visa",
          "first_digits": "411111",
          "last_digits": "1111",
          "exp_month": "12",
          "exp_year": "2026",
          "holder": {
            "name": "Joãozinho da Silva",
            "tax_id": "65544332211"
          },
          "store": false
        },
        "soft_descriptor": "IntegracaoPagsegu"
      },
      "links": [
        {
          "rel": "SELF",
          "href": "https://sandbox.api.pagseguro.com/charges/CHAR_67FC568B-00D8-431D-B2E7-755E3E6C66A0",
          "media": "application/json",
          "type": "GET"
        },
        {
          "rel": "CHARGE.CANCEL",
          "href": "https://sandbox.api.pagseguro.com/charges/CHAR_67FC568B-00D8-431D-B2E7-755E3E6C66A0/cancel",
          "media": "application/json",
          "type": "POST"
        }
      ]
    }
  ],
  "notification_urls": ["https://meusite.com/notificacoes"],
  "links": [
    {
      "rel": "SELF",
      "href": "https://sandbox.api.pagseguro.com/orders/ORDE_1E38BD2E-F2CC-4D9C-9727-787CDFBCA7CE",
      "media": "application/json",
      "type": "GET"
    },
    {
      "rel": "PAY",
      "href": "https://sandbox.api.pagseguro.com/orders/ORDE_1E38BD2E-F2CC-4D9C-9727-787CDFBCA7CE/pay",
      "media": "application/json",
      "type": "POST"
    }
  ]
}

Cartões de teste

Para finalidades de testes, o PagBank fornece alguns cartões de teste, com bandeiras e respostas já definidas Cartões de Teste.

Caso de uso

Em nosso componente, por padrão, disponibilizamos um caso de uso que pode ser visto no return do componente cartão de crédito.

alt text

export default function CartaoCredito() {
  const { postToPagSeguro, publicKey } = usePublicKey();
  const { postToPagBank, data, loading, error } = usePagBank();

  const [cardDetails, setCardDetails] = useState({
    holder: "",
    number: "",
    expMonth: "",
    expYear: "",
    securityCode: "",
  });

  const [encryptedCard, setEncryptedCard] = (useState < string) | (null > null);

  const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
    const { name, value } = e.target;
    setCardDetails((prev) => ({ ...prev, [name]: value }));
  };

  const isFormValid = () => {
    const { holder, number, expMonth, expYear, securityCode } = cardDetails;
    return holder && number && expMonth && expYear && securityCode;
  };

  useEffect(() => {
    const token = process.env.NEXT_PUBLIC_TOKEN;
    if (token) {
      postToPagSeguro("Bearer " + token);
    } else {
      toast.error("Erro no token!");
    }
  }, []);

  const handleCreateOrder = async (encryptedCard: string) => {
    const requestBody: PaymentCartao = {
      reference_id: "ex-00001",
      customer: {
        name: "Jose da Silva",
        email: "[email protected]",
        tax_id: "12345678909",
        phones: [
          {
            country: "55",
            area: "11",
            number: "999999999",
            type: "MOBILE",
          },
        ],
      },
      items: [
        {
          reference_id: "referencia do item",
          name: "nome do item",
          quantity: 1,
          unit_amount: 500,
        },
      ],
      shipping: {
        address: {
          street: "Avenida Brigadeiro Faria Lima",
          number: "1384",
          complement: "apto 12",
          locality: "Pinheiros",
          city: "São Paulo",
          region_code: "SP",
          country: "BRA",
          postal_code: "01452002",
        },
      },
      notification_urls: ["https://meusite.com/notificacoes"],
      charges: [
        {
          reference_id: "referencia da cobranca",
          description: "descricao da cobranca",
          amount: {
            value: 500,
            currency: "BRL",
          },
          payment_method: {
            type: "CREDIT_CARD",
            installments: 1,
            capture: true,
            card: {
              encrypted: encryptedCard,
              store: false,
            },
            holder: {
              name: "Jose da Silva",
              tax_id: "65544332211",
            },
          },
        },
      ],
    };

    const token = process.env.NEXT_PUBLIC_TOKEN;
    if (token) {
      postToPagBank("Bearer " + token, requestBody);
    } else {
      toast.error("Erro no token!");
    }
  };

  const handlePayment = () => {
    if (!isFormValid()) {
      toast.error("Por favor, preencha todos os campos corretamente.");
      return;
    }

    if (typeof window !== "undefined" && window.PagSeguro) {
      const card = window.PagSeguro.encryptCard({
        publicKey: publicKey?.public_key || "",
        holder: cardDetails.holder,
        number: cardDetails.number,
        expMonth: cardDetails.expMonth,
        expYear: cardDetails.expYear,
        securityCode: cardDetails.securityCode,
      });

      setEncryptedCard(card.encryptedCard);
    }
  };

  useEffect(() => {
    if (encryptedCard) {
      handleCreateOrder(encryptedCard);
    }
  }, [encryptedCard]);

  return (
    <div style={{ textAlign: "center", marginTop: "20px" }}>
      <div
        style={{
          display: "grid",
          gap: "10px",
          maxWidth: "400px",
          margin: "auto",
        }}
      >
        <TextField
          label="Nome do Titular"
          name="holder"
          value={cardDetails.holder}
          onChange={handleChange}
          variant="outlined"
        />
        <TextField
          label="Número do Cartão"
          name="number"
          value={cardDetails.number}
          onChange={handleChange}
          variant="outlined"
        />
        <TextField
          label="Mês de Expiração"
          name="expMonth"
          value={cardDetails.expMonth}
          onChange={handleChange}
          variant="outlined"
        />
        <TextField
          label="Ano de Expiração"
          name="expYear"
          value={cardDetails.expYear}
          onChange={handleChange}
          variant="outlined"
        />
        <TextField
          label="Código de Segurança"
          name="securityCode"
          value={cardDetails.securityCode}
          onChange={handleChange}
          variant="outlined"
        />
        <Button
          variant="contained"
          color="primary"
          onClick={handlePayment}
          disabled={loading || !isFormValid()}
        >
          {loading ? <CircularProgress size={24} /> : "Pagar"}
        </Button>
      </div>

      {data && (
        <div style={{ marginTop: "20px" }}>
          <h3>Detalhes do pagamento:</h3>

          {"charges" in data && data.charges.length > 0 && (
            <>
              <p>
                <strong>Valor:</strong> {data.charges[0].amount.value}{" "}
                {data.charges[0].amount.currency}
              </p>
              <p>
                <strong>Método de pagamento:</strong>{" "}
                {data.charges[0].payment_method.type}
              </p>
              <p>
                <strong>Status do pagamento:</strong>{" "}
                {data.charges[0].payment_response.message}
              </p>
            </>
          )}
        </div>
      )}

      <div style={{ textAlign: "center", marginTop: "20px" }}>
        {loading && <CircularProgress />}

        {error && (
          <p style={{ color: "red" }}>Erro ao pagar com cartão: {error}</p>
        )}

        {data && !loading && !error && (
          <>
            <div style={{ marginBottom: "20px" }}>Deu certo!!</div>
          </>
        )}

        <ToastContainer />
      </div>

      <Script
        src="https://assets.pagseguro.com.br/checkout-sdk-js/rc/dist/browser/pagseguro.min.js"
        strategy="afterInteractive"
        onLoad={() => console.log("PagBank SDK carregado")}
      />

      <ToastContainer />
    </div>
  );
}

Pix

Para o pix, é muito mais simples, basta certirficar-se que o token está inserido de maneira adequada no .env.local e colocar de forma correta o requestBody.

const [pixCode] = (useState < string) | (null > null);
const copyToClipboard = () => {
  if (pixCode) {
    navigator.clipboard.writeText(pixCode);
    toast.success("Código Pix copiado com sucesso!");
  }
};

const { postToPagBank, error, loading, data } = usePagBank();
const requestBody: PaymentPix = {
  reference_id: "ex-00001",
  customer: {
    name: "Jose da Silva",
    email: "[email protected]",
    tax_id: "12345678909",
    phones: [
      { country: "55", area: "11", number: "999999999", type: "MOBILE" },
    ],
  },
  items: [{ name: "nome do item", quantity: 1, unit_amount: 500 }],
  qr_codes: [
    { amount: { value: 500 }, expiration_date: "2024-10-29T20:15:59-03:00" },
  ],
  shipping: {
    address: {
      street: "Avenida Brigadeiro Faria Lima",
      number: "1384",
      complement: "apto 12",
      locality: "Pinheiros",
      city: "São Paulo",
      region_code: "SP",
      country: "BRA",
      postal_code: "01452002",
    },
  },
  notification_urls: ["https://meusite.com/notificacoes"],
};
useEffect(() => {
  const token = process.env.NEXT_PUBLIC_TOKEN;
  if (token) {
    postToPagBank("Bearer " + token, requestBody);
  } else {
    toast.error("Erro no token!");
  }
}, []);

RequestBody

{
  "reference_id": "ex-00001",
  "customer": {
    "name": "Jose da Silva",
    "email": "[email protected]",
    "tax_id": "12345678909",
    "phones": [
      {
        "country": "55",
        "area": "11",
        "number": "999999999",
        "type": "MOBILE"
      }
    ]
  },
  "items": [
    {
      "name": "nome do item",
      "quantity": 1,
      "unit_amount": 500
    }
  ],
  "qr_codes": [
    {
      "amount": {
        "value": 500
      },
      "expiration_date": "2021-08-29T20:15:59-03:00"
    }
  ],
  "shipping": {
    "address": {
      "street": "Avenida Brigadeiro Faria Lima",
      "number": "1384",
      "complement": "apto 12",
      "locality": "Pinheiros",
      "city": "São Paulo",
      "region_code": "SP",
      "country": "BRA",
      "postal_code": "01452002"
    }
  },
  "notification_urls": ["https://meusite.com/notificacoes"]
}

ResponseBody

{
  "id": "ORDE_9BBD677F-863E-4D46-BAAF-2EECEE49FF31",
  "reference_id": "ex-00001",
  "created_at": "2021-01-19T09:30:12.197-03:00",
  "customer": {
    "name": "José da Silva",
    "email": "[email protected]",
    "tax_id": "12345678901",
    "phones": [
      {
        "country": "55",
        "area": "11",
        "number": "999999999",
        "type": "MOBILE"
      }
    ]
  },
  "items": [
    {
      "reference_id": "referencia do item",
      "name": "nome do item",
      "quantity": "1",
      "unit_amount": "100"
    }
  ],
  "amount": {
    "currency": "BRL",
    "additional": 100,
    "discount": 100
  },
  "shipping": {
    "address": {
      "street": "Avenida Brigadeiro Faria Lima",
      "number": "1384",
      "complement": "apto 12",
      "locality": "Pinheiros",
      "city": "São Paulo",
      "region_code": "SP",
      "country": "BRA",
      "postal_code": "01452002"
    }
  },
  "qr_codes": [
    {
      "id": "QRCO_9E13BFE1-35C3-4DFD-B499-9B110AC0E1BA",
      "expiration_date": "2021-08-29T20:15:59-03:00",
      "amount": {
        "value": 100
      },
      "text": "00020101021226830014br.gov.bcb.pix2561api.pagseguro.com/pix/v2/9E13BFE1-35C3-4DFD-B499-9B110AC0E1BA27600016BR.COM.PAGSEGURO01369E13BFE1-35C3-4DFD-B499-9B110AC0E1BA52045697530398654041.005802BR5925Leticia Oliveira Porto La6007Barueri62070503***6304658F",
      "links": [
        {
          "rel": "QRCODE.PNG",
          "href": "https://api.pagseguro.com/qrcode/QRCO_9E13BFE1-35C3-4DFD-B499-9B110AC0E1BA/png",
          "media": "image/png",
          "type": "GET"
        },
        {
          "rel": "QRCODE.BASE64",
          "href": "https://api.pagseguro.com/qrcode/QRCO_9E13BFE1-35C3-4DFD-B499-9B110AC0E1BA/base64",
          "media": "text/plain",
          "type": "GET"
        }
      ]
    }
  ],
  "charges": [],
  "links": [
    {
      "rel": "SELF",
      "href": "https://api.pagseguro.com/orders/ORDE_9BBD677F-863E-4D46-BAAF-2EECEE49FF31",
      "media": "application/json",
      "type": "GET"
    },
    {
      "rel": "PAY",
      "href": "https://api.pagseguro.com/orders/ORDE_9BBD677F-863E-4D46-BAAF-2EECEE49FF31/pay",
      "media": "application/json",
      "type": "POST"
    }
  ]
}

Caso de uso

Análogamente ao cartão de crédito, segue um exemplo de caso de uso no return do componente pix, para a criação e pagamento de um pedido fictício.

alt text

export default function Pix() {
  const [pixCode] = (useState < string) | (null > null);
  const copyToClipboard = () => {
    if (pixCode) {
      navigator.clipboard.writeText(pixCode);
      toast.success("Código Pix copiado com sucesso!");
    }
  };

  const { postToPagBank, error, loading, data } = usePagBank();
  const requestBody: PaymentPix = {
    reference_id: "ex-00001",
    customer: {
      name: "Jose da Silva",
      email: "[email protected]",
      tax_id: "12345678909",
      phones: [
        { country: "55", area: "11", number: "999999999", type: "MOBILE" },
      ],
    },
    items: [{ name: "nome do item", quantity: 1, unit_amount: 500 }],
    qr_codes: [
      { amount: { value: 500 }, expiration_date: "2024-10-29T20:15:59-03:00" },
    ],
    shipping: {
      address: {
        street: "Avenida Brigadeiro Faria Lima",
        number: "1384",
        complement: "apto 12",
        locality: "Pinheiros",
        city: "São Paulo",
        region_code: "SP",
        country: "BRA",
        postal_code: "01452002",
      },
    },
    notification_urls: ["https://meusite.com/notificacoes"],
  };
  useEffect(() => {
    const token = process.env.NEXT_PUBLIC_TOKEN;
    if (token) {
      postToPagBank("Bearer " + token, requestBody);
    } else {
      toast.error("Erro no token!");
    }
  }, []);

  return (
    <div style={{ textAlign: "center", marginTop: "20px" }}>
      <h2 style={{ marginBottom: "20px" }}>Pagamento via Pix</h2>

      {loading && <CircularProgress />}

      {error && (
        <p style={{ color: "red" }}>Erro ao gerar o QR Code: {error}</p>
      )}

      {data && !loading && !error && "qr_codes" in data && (
        <>
          <div style={{ marginBottom: "20px" }}>
            <img
              src={
                data.qr_codes[0].links.find((link) => link.rel === "QRCODE.PNG")
                  ?.href || ""
              }
              alt="QR Code"
              style={{
                width: "200px",
                height: "200px",
                border: "2px solid #000",
                borderRadius: "10px",
              }}
            />
            <p>Escaneie o QR Code acima para pagar.</p>
          </div>

          <div>
            <TextField
              id="pixCode"
              value={data.qr_codes[0].text}
              InputProps={{ readOnly: true }}
              variant="outlined"
              fullWidth
              sx={{ margin: "10px 0", width: "75%" }}
            />
            <br />
            <Button
              variant="contained"
              size="small"
              style={{ marginLeft: "10px" }}
              onClick={copyToClipboard}
            >
              Copiar
            </Button>
            <p>Copie o código Pix acima para realizar o pagamento.</p>
          </div>
        </>
      )}

      <ToastContainer />
    </div>
  );
}

Boleto

De forma bem similar ao pix, no boleto devemos atentar apenas em preencher o requestBody da maneira adequada, assim como implementar a lógica de fila caso existam muitos pedidos nessa modalidade de pagamento, segue a estrutura:

const [boletoCode] = (useState < string) | (null > null);

const copyToClipboard = () => {
  if (boletoCode) {
    navigator.clipboard.writeText(boletoCode);
    toast.success("Código de Boleto copiado com sucesso!");
  }
};

const downloadBoleto = (url: string) => {
  window.open(url, "_blank");
};

const { postToPagBank, error, loading, data } = usePagBank();

const requestBody: PaymentBoleto = {
  reference_id: "ex-00001",
  customer: {
    name: "Jose da Silva",
    email: "[email protected]",
    tax_id: "12345679891",
    phones: [
      {
        country: "55",
        area: "11",
        number: "999999999",
        type: "MOBILE",
      },
    ],
  },
  items: [
    {
      reference_id: "referencia do item",
      name: "nome do item",
      quantity: 1,
      unit_amount: 500,
    },
  ],
  shipping: {
    address: {
      street: "Avenida Brigadeiro Faria Lima",
      number: "1384",
      complement: "apto 12",
      locality: "Pinheiros",
      city: "São Paulo",
      region_code: "SP",
      country: "BRA",
      postal_code: "01452002",
    },
  },
  notification_urls: ["https://meusite.com/notificacoes"],
  charges: [
    {
      reference_id: "referencia da cobranca",
      description: "descricao da cobranca",
      amount: {
        value: 500,
        currency: "BRL",
      },
      payment_method: {
        type: "BOLETO",
        boleto: {
          due_date: "2024-12-31",
          instruction_lines: {
            line_1: "Pagamento processado para DESC Fatura",
            line_2: "Via PagSeguro",
          },
          holder: {
            name: "Jose da Silva",
            tax_id: "12345679891",
            email: "[email protected]",
            address: {
              country: "Brasil",
              region: "São Paulo",
              region_code: "SP",
              city: "Sao Paulo",
              postal_code: "01452002",
              street: "Avenida Brigadeiro Faria Lima",
              number: "1384",
              locality: "Pinheiros",
            },
          },
        },
      },
    },
  ],
};

useEffect(() => {
  const token = process.env.NEXT_PUBLIC_TOKEN;
  if (token) {
    postToPagBank("Bearer " + token, requestBody);
  } else {
    toast.error("Erro no token!");
  }
}, []);

RequestBody

Alguns parâmetros são obrigatórios quando criando um pedido utilizando Boleto. Uma lista é apresentada na tabela a seguir:

alt text

Aqui está um exemplo de request:

{
  "reference_id": "ex-00001",
  "customer": {
    "name": "Jose da Silva",
    "email": "[email protected]",
    "tax_id": "12345679891",
    "phones": [
      {
        "country": "55",
        "area": "11",
        "number": "999999999",
        "type": "MOBILE"
      }
    ]
  },
  "items": [
    {
      "reference_id": "referencia do item",
      "name": "nome do item",
      "quantity": 1,
      "unit_amount": 500
    }
  ],
  "shipping": {
    "address": {
      "street": "Avenida Brigadeiro Faria Lima",
      "number": "1384",
      "complement": "apto 12",
      "locality": "Pinheiros",
      "city": "São Paulo",
      "region_code": "SP",
      "country": "BRA",
      "postal_code": "01452002"
    }
  },
  "notification_urls": ["https://meusite.com/notificacoes"],
  "charges": [
    {
      "reference_id": "referencia da cobranca",
      "description": "descricao da cobranca",
      "amount": {
        "value": 500,
        "currency": "BRL"
      },
      "payment_method": {
        "type": "BOLETO",
        "boleto": {
          "due_date": "2023-06-20",
          "instruction_lines": {
            "line_1": "Pagamento processado para DESC Fatura",
            "line_2": "Via PagSeguro"
          },
          "holder": {
            "name": "Jose da Silva",
            "tax_id": "12345679891",
            "email": "[email protected]",
            "address": {
              "country": "Brasil",
              "region": "São Paulo",
              "region_code": "SP",
              "city": "Sao Paulo",
              "postal_code": "01452002",
              "street": "Avenida Brigadeiro Faria Lima",
              "number": "1384",
              "locality": "Pinheiros"
            }
          }
        }
      }
    }
  ]
}

ResponseBody

{
  "id": "ORDE_E8A44EB1-89BC-4261-9004-739A09B53A8C",
  "reference_id": "ex-00001",
  "created_at": "2023-02-08T15:10:15.763-03:00",
  "customer": {
    "name": "Jose da Silva",
    "email": "[email protected]",
    "tax_id": "12345679891",
    "phones": [
      {
        "type": "MOBILE",
        "country": "55",
        "area": "11",
        "number": "999999999"
      }
    ]
  },
  "items": [
    {
      "reference_id": "referencia do item",
      "name": "nome do item",
      "quantity": 1,
      "unit_amount": 500
    }
  ],
  "shipping": {
    "address": {
      "street": "Avenida Brigadeiro Faria Lima",
      "number": "1384",
      "complement": "apto 12",
      "locality": "Pinheiros",
      "city": "São Paulo",
      "region_code": "SP",
      "country": "BRA",
      "postal_code": "01452002"
    }
  },
  "charges": [
    {
      "id": "CHAR_BF10AE3B-68D2-430D-AED6-0D5E2C7E180E",
      "reference_id": "referencia da cobranca",
      "status": "WAITING",
      "created_at": "2023-02-08T15:10:15.901-03:00",
      "description": "descricao da cobranca",
      "amount": {
        "value": 500,
        "currency": "BRL",
        "summary": {
          "total": 500,
          "paid": 0,
          "refunded": 0
        }
      },
      "payment_response": {
        "code": "20000",
        "message": "SUCESSO"
      },
      "payment_method": {
        "type": "BOLETO",
        "boleto": {
          "id": "0E243EE1-736A-45EF-B153-CC9B9F0A838F",
          "barcode": "03399853012970000024227020901016278150000015630",
          "formatted_barcode": "03399.85301 29700.000242 27020.901016 2 78150000015630",
          "due_date": "2023-06-20",
          "instruction_lines": {
            "line_1": "Pagamento processado para DESC Fatura",
            "line_2": "Via PagSeguro"
          },
          "holder": {
            "name": "Jose da Silva",
            "tax_id": "12345679891",
            "email": "[email protected]",
            "address": {
              "region": "São Paulo",
              "city": "Sao Paulo",
              "postal_code": "01452002",
              "street": "Avenida Brigadeiro Faria Lima",
              "number": "1384",
              "locality": "Pinheiros",
              "country": "Brasil",
              "region_code": "SP"
            }
          }
        }
      },
      "links": [
        {
          "rel": "SELF",
          "href": "https://boleto.sandbox.pagseguro.com.br/0e243ee1-736a-45ef-b153-cc9b9f0a838f.pdf",
          "media": "application/pdf",
          "type": "GET"
        },
        {
          "rel": "SELF",
          "href": "https://boleto.sandbox.pagseguro.com.br/0e243ee1-736a-45ef-b153-cc9b9f0a838f.png",
          "media": "image/png",
          "type": "GET"
        },
        {
          "rel": "SELF",
          "href": "https://sandbox.api.pagseguro.com/charges/CHAR_BF10AE3B-68D2-430D-AED6-0D5E2C7E180E",
          "media": "application/json",
          "type": "GET"
        }
      ]
    }
  ],
  "notification_urls": ["https://meusite.com/notificacoes"],
  "links": [
    {
      "rel": "SELF",
      "href": "https://sandbox.api.pagseguro.com/orders/ORDE_E8A44EB1-89BC-4261-9004-739A09B53A8C",
      "media": "application/json",
      "type": "GET"
    },
    {
      "rel": "PAY",
      "href": "https://sandbox.api.pagseguro.com/orders/ORDE_E8A44EB1-89BC-4261-9004-739A09B53A8C/pay",
      "media": "application/json",
      "type": "POST"
    }
  ]
}

Caso de uso

Em nosso componente padrão de boleto, você poderá encontrar no return nosso caso de uso padrão.

alttext

export default function Boleto() {
  const [boletoCode] = (useState < string) | (null > null);

  const copyToClipboard = () => {
    if (boletoCode) {
      navigator.clipboard.writeText(boletoCode);
      toast.success("Código de Boleto copiado com sucesso!");
    }
  };

  const downloadBoleto = (url: string) => {
    window.open(url, "_blank");
  };

  const { postToPagBank, error, loading, data } = usePagBank();

  const requestBody: PaymentBoleto = {
    reference_id: "ex-00001",
    customer: {
      name: "Jose da Silva",
      email: "[email protected]",
      tax_id: "12345679891",
      phones: [
        {
          country: "55",
          area: "11",
          number: "999999999",
          type: "MOBILE",
        },
      ],
    },
    items: [
      {
        reference_id: "referencia do item",
        name: "nome do item",
        quantity: 1,
        unit_amount: 500,
      },
    ],
    shipping: {
      address: {
        street: "Avenida Brigadeiro Faria Lima",
        number: "1384",
        complement: "apto 12",
        locality: "Pinheiros",
        city: "São Paulo",
        region_code: "SP",
        country: "BRA",
        postal_code: "01452002",
      },
    },
    notification_urls: ["https://meusite.com/notificacoes"],
    charges: [
      {
        reference_id: "referencia da cobranca",
        description: "descricao da cobranca",
        amount: {
          value: 500,
          currency: "BRL",
        },
        payment_method: {
          type: "BOLETO",
          boleto: {
            due_date: "2024-12-31",
            instruction_lines: {
              line_1: "Pagamento processado para DESC Fatura",
              line_2: "Via PagSeguro",
            },
            holder: {
              name: "Jose da Silva",
              tax_id: "12345679891",
              email: "[email protected]",
              address: {
                country: "Brasil",
                region: "São Paulo",
                region_code: "SP",
                city: "Sao Paulo",
                postal_code: "01452002",
                street: "Avenida Brigadeiro Faria Lima",
                number: "1384",
                locality: "Pinheiros",
              },
            },
          },
        },
      },
    ],
  };

  useEffect(() => {
    const token = process.env.NEXT_PUBLIC_TOKEN;
    if (token) {
      postToPagBank("Bearer " + token, requestBody);
    } else {
      toast.error("Erro no token!");
    }
  }, []);

  return (
    <div style={{ textAlign: "center", marginTop: "20px" }}>
      <h2 style={{ marginBottom: "20px" }}>Pagamento via Boleto</h2>

      {loading && <CircularProgress />}

      {error && <p style={{ color: "red" }}>Erro ao gerar o Boleto: {error}</p>}

      {data && !loading && !error && "charges" in data && (
        <>
          <div>
            <TextField
              id="boletoCode"
              value={
                "boleto" in data.charges[0].payment_method
                  ? data.charges[0].payment_method.boleto?.formatted_barcode ||
                    ""
                  : ""
              }
              InputProps={{ readOnly: true }}
              variant="outlined"
              fullWidth
              sx={{ margin: "10px 0", width: "75%" }}
            />
            <br />
            <Button
              variant="contained"
              size="small"
              style={{ marginLeft: "10px" }}
              onClick={copyToClipboard}
            >
              Copiar
            </Button>
            <p>Copie o código de boleto acima para realizar o pagamento.</p>
          </div>

          <Button
            variant="contained"
            size="small"
            style={{ marginTop: "10px" }}
            onClick={() => downloadBoleto(data.charges[0].links[0].href)}
          >
            Ver Boleto PDF
          </Button>
        </>
      )}

      <ToastContainer />
    </div>
  );
}