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
57
Maintainers
Readme
Componente de integração com o PagBank
Instalação
Para instalar este pacote no seu projeto NEXT, use o npm:
npm i pacote-pagbank
índice
- Componente de integração com o 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
, criarpages > api > pagbank.ts
epublicKey.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.
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.
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.
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.
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:
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.
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>
);
}