Skip to content

Recursos da API

Nesta seção, você encontrará uma visão detalhada de cada recurso disponível na API Pública.

Para cada domínio, apresentamos:

  • O objetivo do recurso
  • O que ele retorna
  • Um exemplo de uso prático

Padrão de uso

Todos os recursos seguem o mesmo padrão de consumo:

1import { Api } from '@uappi/public-sdk';
2
3// Exemplo genérico
4const response = await Api.<dominio>.<metodo>(params);

ℹ️ Informação

Para mais informações sobre cada endpoint, consulte:
API Pública: Árvore de Categoria

Common

Responsável por fornecer dados auxiliares e utilitários, geralmente utilizados em formulários e validações.

listZipcode

Retorna informações de endereço com base no CEP.

1const address = await Api.common.listZipcode(zipcode: string);

listContries

Lista os países disponíveis.

1const countries = await Api.common.listContries();

countryDetail

Retorna os detalhes de um pais.

1await Api.common.countryDetail(code: CountryAlpha3);

listCardFlags

Retorna as bandeiras de cartão suportadas.

1await Api.common.listCardFlags();

Customization

Responsável por dados dinâmicos da loja, como banners, vitrines e menus.

ℹ️ Informação

Os métodos abaixo podem possuir sobrecarga de função, permitindo uma mesma função possuir duas assinaturas.

listBanners

Retorna grupos de banner.

ℹ️ Informação

O método baixo possui um Genérico opcional em sua assinatura.
Caso o banner esteja configurado para trabalhar com parametros adicionais no painel, você deve tipar o Genérico "AdditionalParameters"
Ex: interface AdditionalParameters { title: string; description: string; }

1// Retorna uma lista de grupos de banners
2await Api.customization.listBanners<AdditionalParameters>(codes: Array<string>): Array<Banners<AdditionalParameters>>;
3
4// Retorna apenas um grupo de banner em especifico
5await Api.customization.listBanners<AdditionalParameters>(code: string): Banners<AdditionalParameters>;

listShowcase

Retorna vitrines de produtos.

1// Retorna uma lista de vitrine
2await Api.customization.listShowcase(codes: Array<string>): Array<Showcase>;
3
4// Retorna apenas uma vitrine em especifico
5await Api.customization.listShowcase(code: string): Showcase;

listMenu

Retorna menu.

1// Retorna uma lista de Menus
2await Api.customization.listMenu(codes: Array<string>) Array<Menu>;
3
4// Retorna apenas um Menu em especifico
5await Api.customization.listMenu(code: string) Menu;

listTemplateSettings

Lista as configurações de uma loja: variaveis, apps configurados, informações de SEO.

1await Api.customization.listTemplateSettings<Setting>(uri: string);

Customer

Responsável por dados de cliente, como edição de endereço, login, cadastro, newsletter e outros.

addNewsletter

Inscreve na newsletter da loja por email e name

1await Api.customer.addNewsletter({
2 email: 'example@email.com';
3 name: 'Example Name';
4});

deleteNewsletter

Remove inscrição na newsletter com base no cliente logado (apenas cliente logado)

1await Api.customer.deleteNewsletter();

createProductReview

Avalia um produto (apenas clientes logado)

1await Api.customer.createProductReview(
2 productId: number,
3 {
4 comment: string;
5 recommended: boolean;
6 score: number;
7 name?: string;
8 email?: string;
9 }
10): CreateProductReviewResponse;

createImageProductReview

Envia imagens para uma avaliação de produto já criada. Os arquivos são enviados como multipart/form-data.

1await Api.customer.createImageProductReview(
2 productReviewId: number,
3 files: Array<File>
4): Array<CreateProductReviewMediaResponse>;

listProductReview

Listagem paginada de todas avaliações do produto

1await Api.customer.listProductReview(
2 options?: Pick<
3 ApiParams<ReviewFields, ReviewSortFields, ReviewConditionFields>,
4 'condition' | 'order' | 'fields' | 'limit' | 'offset'
5 >
6);

listStoreReview

Listagem paginada de todas avaliações da loja

1await Api.customer.listStoreReview();

createStoreReview

Cria uma avaliação da loja

1await Api.customer.createStoreReview({
2 comment: string;
3 recommended: boolean;
4 score: number;
5 name?: string;
6 email?: string;
7});

getStoreReviewByCustomer

Retorna a avaliação da loja feita pelo cliente logado

1await Api.customer.getStoreReviewByCustomer(): StoreReviewResponse;

createInterest

Cria uma solicitação de interesse em um produto fora de estoque

1await Api.customer.createInterest({
2 productId: number;
3 origin: InterestType;
4 name: string;
5 email: string;
6 phone: string;
7 message: string;
8});

changePasswordByAuthenticated

Alteração de senha com cliente autenticado

1await Api.customer.changePasswordByAuthenticated({
2 password: string;
3 confirmPassword: string;
4 currentPassword: string;
5});

changePasswordByCode

Alteração de senha através de código enviado por e-mail

1await Api.customer.changePasswordByCode({
2 code: string;
3 password: string;
4 confirmPassword: string;
5});

check

Verifica existencia de cliente com base no e-mail ou documento

1await Api.customer.check({
2 identification: string; // campo usado para enviar o e-mail ou documento do cliente
3});

listAddress

Listagem de endereços do cliente logado

1await Api.customer.listAddress();

createAddress

Cria novo endereço do cliente logado

1await Api.customer.createAddress({
2 zipCode: string;
3 identification: string;
4 countryCode: CountryAlpha3;
5 stateCode: StateCode;
6 state: string;
7 city: string;
8 street: string;
9 number: string;
10 district: string;
11 complement: string;
12 recipient: string;
13});

deleteAddress

Remove um endereço do cliente logado

1await Api.customer.deleteAddress(addressId: number);

updateAddress

Atualiza endereço do cliente logado

1await Api.customer.updateAddress(
2 addressId: number,
3 {
4 zipCode: string;
5 identification: string;
6 countryCode: CountryAlpha3;
7 stateCode: StateCode;
8 state: string;
9 city: string;
10 street: string;
11 number: string;
12 district: string;
13 complement: string;
14 recipient: string;
15 }
16);

updatePrimaryAddress

Define um endereço como principal

1await Api.customer.updatePrimaryAddress(addressId: number);

detail

Detalhes do cliente logado

1await Api.customer.detail(
2 options?: Pick<
3 ApiParams<CustomerFields, CustomerSortFields, CustomerConditionFields>,
4 'condition' | 'fields' | 'order'
5 >,
6);

passwordRecovery

Recuperação de senha

1await Api.customer.passwordRecovery({
2 email: string;
3});

signinByDocument

Login por documento

1await Api.customer.signinByDocument({
2 document: string;
3 password: string;
4});

signinByEmail

Login por e-mail

1await Api.customer.signinByEmail({
2 email: string;
3 password: string;
4}): ResponseSigninCustomer;

ℹ️ Informação

Quando o cliente tem autenticação em duas etapas, signinByEmail e signinByDocument retornam mfaToken e options em vez de token. Nesse caso, conclua o login com sendMfa e loginMfa.

listSalesChannelByEmail

Lista os canais de venda em que o e-mail ou documento informado possui cadastro

1await Api.customer.listSalesChannelByEmail({
2 identification: string;
3}): Array<{ id: number; domain: string }>;

signup

Cadastro de novo cliente

1await Api.customer.signup({
2 email: string;
3 nameCorporateName: string;
4 isCorporate: boolean;
5 gender: 'male' | 'female' | 'undefined';
6 birthdate: string;
7 phone: string;
8 nationality: string;
9 origin: 'frontend' | 'api' | 'admin';
10 password: string;
11 documents?: Array<{
12 type: 'cpf' | 'rg' | 'cnpj' | 'ie' | 'document1' | 'document2' | 'document3';
13 document: string;
14 }>;
15});

update

Atualiza dados do cliente

1await Api.customer.update({
2 email?: string;
3 nameCorporateName?: string;
4 tradeName?: string;
5 isCorporate?: boolean;
6 gender?: 'male' | 'female' | 'undefined';
7 phone?: string;
8});

loggout

Logout de cliente

1await Api.customer.loggout();

detailOrderGroup

Detalhes de pedido

1await Api.customer.detailOrderGroup(
2 orderId,
3 options?: Pick<ApiParams<CustomerOrderGroupFields>, 'fields'>,
4);

listOrderGroups

Lista pedidos

1await Api.customer.listOrderGroups(
2 options?: Pick<
3 ApiParams<
4 CustomerOrderGroupFields,
5 CustomerOrderGroupSortFields,
6 CustomerOrderGroupConditionFields
7 >,
8 'condition' | 'fields' | 'limit' | 'offset' | 'order'
9 >
10);

listOrderItemHistory

Exibe o histórico de atualizações do pedido

1await Api.customer.listOrderItemHistory(
2 orderId: number,
3 options?: Pick<
4 ApiParams<
5 '',
6 CustomerOrderItemHistorySortFields,
7 CustomerOrderItemHistoryConditionFields
8 >,
9 'condition' | 'fields' | 'limit' | 'offset' | 'order'
10 >,
11);

listCustomerHistory

Exibe o histórico de atualizações de dados do cliente (senha, endereço, etc.)

1await Api.customer.listCustomerHistory(
2 options?: Pick<
3 ApiParams<'', CustomerHistorySortFields, CustomerHistoryConditionFields>,
4 'condition' | 'limit' | 'offset' | 'order'
5 >,
6);

listCustomerReview

Lista avaliações do cliente em produto

1await Api.customer.listCustomerReview(
2 options?: Pick<
3 ApiParams<ReviewFields, ReviewSortFields, ReviewConditionFields>,
4 'condition' | 'order' | 'fields' | 'limit' | 'offset'
5 >,
6);

listWalletTransaction

Lista transações da carteira

1await Api.customer.listWalletTransaction(
2 options?: Pick<
3 ApiParams<'', WalletSortFields, WalletConditionFields>,
4 'condition' | 'order' | 'limit' | 'offset'
5 >,
6);

claimGiftCard

Resgata gift card

1await Api.customer.claimGiftCard({
2 codes: Array<string>;
3});

updateDocument

Gerencia todas as operações relacionadas ao cliente.

1await Api.customer.updateDocument({
2 documents: Array<{
3 type: 'cpf' | 'rg' | 'cnpj' | 'ie' | 'document1' | 'document2' | 'document3';
4 document: string;
5 }>;
6});

Lista de desejos

#### listWishlist

Lista as listas de desejos do cliente logado

1await Api.customer.listWishlist(
2 options?: Pick<
3 ApiParams<'', CustomerWishlistSortFields, CustomerWishlistConditionFields>,
4 'condition' | 'limit' | 'offset' | 'order'
5 >,
6): CustomerListWishlistResponse;

#### detailWishlist

Retorna uma lista de desejos com os produtos paginados

1await Api.customer.detailWishlist(
2 wishlistId: number,
3 options?: Pick<ApiParams<ProductFields>, 'fields' | 'limit' | 'offset'>,
4): CustomerDetailWishlistResponse;

#### addProductToWishlist

Adiciona um produto à lista de desejos do cliente logado

1await Api.customer.addProductToWishlist({
2 productId: number;
3}): true;

#### removeProductToWishlist

Remove um produto de uma lista de desejos

1await Api.customer.removeProductToWishlist(
2 wishlistId: number,
3 productId: number,
4): true;

Autenticação em duas etapas (MFA)

Fluxo de login: signinByEmail/signinByDocument retornam mfaToken e as opções disponíveis → sendMfa envia o código pela opção escolhida → loginMfa valida o código e conclui o login.

Erros específicos são retornados em errorCode (tipo CustomerMFAErrorCode): UAPPI_STORE_CUSTOMER_MFA_CODE_INVALID, UAPPI_STORE_CUSTOMER_MFA_CODE_ATTEMPTS_EXCEEDED e UAPPI_STORE_CUSTOMER_MFA_APP_SETUP_DISABLED.

#### sendMfa

Envia o código de verificação pela opção escolhida (e-mail, SMS, WhatsApp, etc.)

1await Api.customer.sendMfa({
2 mfaToken: string;
3 mfaOptionId: number;
4}): true;

#### loginMfa

Valida o código e conclui o login

1await Api.customer.loginMfa({
2 mfaToken: string;
3 mfaOptionId: number;
4 code: string;
5 secretKey?: string;
6}): true;

#### mfaSetup

Inicia a configuração de MFA por aplicativo autenticador para o cliente logado. As opções do tipo app trazem em settings o qrCode, o otpauth e a secretKey.

1await Api.customer.mfaSetup(force: boolean): ResponseMFASetup;

#### confirmMfa

Confirma a configuração do aplicativo autenticador com o código gerado por ele

1await Api.customer.confirmMfa({
2 mfaToken: string;
3 mfaOptionId: number;
4 code: string;
5 secretKey: string;
6 password: string;
7}): true;

#### deleteMFA

Remove a configuração de MFA por aplicativo do cliente logado

1await Api.customer.deleteMFA();

Product

Responsável pelas informações de produtos e navegação, como: listagem de variações, criação/remoção/listagem de comentários sobre um produto, frete com base no produto, listagem de categoria e busca de produto

listBrands

Listagem de marcas ativas

1await Api.product.listBrands(
2 options?: Pick<
3 ApiParams<BrandFields, BrandOrders, BrandConditions>,
4 'condition' | 'fields' | 'offset' | 'limit' | 'order'
5 >
6): Brand;

getProductById

Retorna um produto pelo ID

1await Api.product.getProductById(
2 productId: number,
3 options?: Pick<
4 ApiParams<ProductFields, ProductSortFields, ProductConditionFields>,
5 'condition' | 'fields' | 'meta'
6 >
7): Product;

getCategoryTree

Retorna a árvore de uma categoria: a categoria atual, suas filhas, irmãs e pai

1await Api.product.getCategoryTree(categoryId: number): CategoryTree;

listCategoriesTree

Retorna a árvore completa de categorias da loja

1await Api.product.listCategoriesTree(): Array<CategoryTreeItem>;

listVariation

Retorna informações sobre uma variação de um produto

1await Api.product.listVariation(
2 variationData: VariationData,
3 options?: Pick<
4 ApiParams<ProductFields, ProductSortFields, ProductConditionFields>,
5 'condition' | 'fields' | 'meta'
6 >
7): Product;

getUrl

Request com dados da página (categoria, detalhe de produto, institucional, marca, etc)

ℹ️ Informação

O método baixo possui um Genérico obrigatório em sua assinatura.
Genérico usado para definir o tipo de página que será retornado
tipos de páginas UrlProduct | UrlPage | UrlBrand | UrlListing

1await Api.product.getUrl<UrlType>(
2 path: string,
3 options?: Pick<
4 ApiParams<ProductFields, ProductOrderFields, ProductConditionFields>,
5 'condition' | 'fields' | 'limit' | 'offset' | 'meta' | 'order'
6 >
7): UrlType;

getSearch

Retorna uma listagem de produtos com base no termo de pesquisa. Pode ser usado para criar uma sugestão no header do site e também para criar uma listagem paginada de busca de produto

1await Api.product.getSearch(
2 term: string,
3 options?: Pick<
4 ApiParams<ProductFields, ProductSortFields, ProductConditionFields>,
5 'condition' | 'fields' | 'limit' | 'meta' | 'offset' | 'order'
6 >
7): Search;

listShipmentQuoteProduct

Usado para cotar frete no contexto do produto informado na requisição. Não considera produtos persistidos no carrinho, apenas o frete considerando um produto em específico.

1await Api.product.listShipmentQuoteProduct(
2 payload: Pick<ApiParams, 'targetCountryCode' | 'targetZipCode' | 'items'>,
3): ShipmentQuoteProductResponse;

deleteProductComment

Permite o cliente deletar seu comentário/pergunta sobre um produto.

1await Api.product.deleteProductComment(
2 commentId: number
3): boolean;

createProductComment

Permite o cliente criar um comentário/pergunta no produto.

1await Api.product.createProductComment(
2 productId: number,
3 payload: CreateProductComment,
4): ProductComment;

listProductComments

Retorna uma listagem paginada de todos os comentários do produto

1await Api.product.listProductComments(
2 options?: Pick<
3 ApiParams<
4 ProductCommentFields,
5 ProductCommentSortFields,
6 ProductCommentConditionFields
7 >,
8 'condition' | 'order' | 'limit' | 'offset' | 'fields'
9 >
10): ProductCommentsResponse;

Cart

addProduct

Adiciona um ou mais produtos ao carrinho

1await Api.cart.addProduct({
2 items: Array<{
3 productId: number;
4 quantity: number;
5 code?: string | null;
6 upsellId?: number | null;
7 productPairOfferId?: number | null;
8 }>;
9}): CartResponse;

deleteProduct

Remover um ou varios produtos do carrinho

1await Api.cart.deleteProduct({
2 items: Array<{ productId: number; upsellId?: number | null }>;
3}): CartResponse;

listDetail

Retorna todos os detalhes de um carrinho: produtos, descontos, frete selecionado, e mais

1await Api.cart.listDetail(): CartResponse;

shipmentQuote

Retorna opções de frete no contexto do carrinho

1await Api.cart.shipmentQuote({
2 targetCountryCode: CountryAlpha3;
3 targetZipCode: string;
4}): CartResponse;

upsertProduct

Adiciona ou atualiza a quantidade do produto no carrinho

1await Api.cart.upsertProduct({
2 items: Array<{
3 productId: number;
4 quantity: number;
5 code?: string | null;
6 upsellId?: number | null;
7 productPairOfferId?: number | null;
8 }>;
9}): CartResponse;

selectShipment

Seleciona uma opção de frete no contexto do carrinho.

1await Api.cart.selectShipment({
2 orders: Array<{
3 cartOrderId: number;
4 shippingTableId: number;
5 shippingPickupPointId?: number;
6 }>;
7}): CartResponse;

applyAddresses

Aplica endereço no contexto do carrinho.

1await Api.cart.applyAddresses({
2 addresses: Array<{
3 addressId: number;
4 addressType: 'both' | 'delivery' | 'billing';
5 }>;
6}): CartResponse;

listPayments

Lista as opções de pagamento no contexto do carrinho.

1await Api.cart.listPayments(): PaymentResponse;

paymentConditions

Informa as condições do pagamento, para verificar condições do mix de pagamento

1await Api.cart.paymentConditions({
2 cashDiscountPaymentOptionId: number;
3 installmentPaymentOptionId: number | null;
4 items: Array<{
5 reference: string;
6 value: number;
7 }>;
8})

buy

Usado no processo de finalização de uma compra.

1await Api.cart.buy({
2 payments: Array<{
3 paymentOptionId: number;
4 value?: number;
5 selectedInstallment?: number;
6 card?: {
7 token?: string;
8 number: string;
9 cvv: string;
10 month: number;
11 year: number;
12 name: string;
13 };
14 }>;
15});

upsells

Retorna uma lista de upsell com base no parâmetro de location

1await Api.cart.upsells(
2 location: string,
3 options?: Pick<ApiParams<ProductFields>, 'fields'>,
4);

recovery

Permite resturar um carrinho por meio de um recoveryCode, enviado pela plataforma via e-mail na comunicação de recuperação de carrinho "Seu carrinho está te esperando"

1await Api.cart.recovery(recoveryCode: string);

paymentToken

Gera o token usado pelo formulário de pagamento hospedado. Normalmente não é chamado diretamente: o componente PaymentHosted faz essa chamada.

Com orderGroupPaymentCode, o token é gerado para o pedido do link de pagamento em vez do carrinho.

1await Api.cart.paymentToken({
2 paymentOptionId: number;
3 orderGroupPaymentCode?: string;
4}): { token: string };

Promotional

Gerencia cupons, pontos e benefícios.

listPairOffers

Retorna a listagem de opções de compre junto no contexto do produto.

1await Api.promotional.listPairOffers(
2 productId: number,
3 options?: Pick<ApiParams<ProductFields>, 'fields' | 'variationMap'>
4);

addCoupon

Aplica cupom de desconto no carrinho

1await Api.promotional.addCoupon({
2 hash: string;
3}): CartResponse;

deleteCoupon

Remove o cupom aplicado no carrinho no carrinho. É preciso ter um cupom aplicado

1await Api.promotional.deleteCoupon();

applyWallet

Aplica saldo disponível na carteira do cliente no carrinho como parte desconto de pagamento

1await Api.promotional.applyWallet();

deleteWallet

Remove saldo do cliente aplicado no carrinho

1await Api.promotional.deleteWallet();

applyPoint

Aplica saldo de pontos disponível no carrinho como parte desconto de pagamento

1await Api.promotional.applyPoint();

deletePoint

Remove saldo de pontos do cliente aplicado no carrinho

1await Api.promotional.deletePoint()

getPromotionalForecast

Retorna a previsão de benefícios promocionais de um produto: sistema de pontos e promoções

1await Api.promotional.getPromotionalForecast(productId: number): {
2 pointSystem: {
3 name: string;
4 pointValue: number;
5 finalAmount: number;
6 finalValue: number;
7 } | null;
8 promotions: Array<Record<string, unknown>>;
9};

Order

Consultas públicas de pedido.

detailOrderPaymentCode

Consulta o pedido pelo código do link de pagamento. Usado na tela que o cliente abre ao clicar no link enviado pelo vendedor. Não exige cliente logado.

Retorna o grupo de pedido e as opções de pagamento permitidas no link, cada uma com suas configurações.

1await Api.order.detailOrderPaymentCode(code: string): {
2 code: string;
3 expiresAt: string;
4 orderGroup: CustomerOrderResponse | null;
5 paymentOptions: Array<{
6 option: PaymentOption;
7 settings: Array<PaymentConfiguration>;
8 }>;
9};

Erros possíveis em errorCode (tipo OrderPaymentCodeErrorCode):

CódigoSignificado
UAPPI_STORE_ORDER_PAYMENT_CODE_NOT_FOUNDLink inexistente
UAPPI_STORE_ORDER_PAYMENT_CODE_EXPIREDLink expirado
UAPPI_STORE_ORDER_PAYMENT_CODE_INVALID_ORDER_STATUSPedido em status que não permite pagamento
UAPPI_STORE_ORDER_PAYMENT_CODE_ALREADY_PAIDPedido já pago
UAPPI_STORE_ORDER_INVALID_PAYMENT_OPTIONOpção de pagamento não permitida no link
UAPPI_STORE_ORDER_PAYMENT_FAILFalha no pagamento
UAPPI_STORE_ORDER_ANTI_FRAUD_FAILPagamento recusado pelo antifraude
UAPPI_RENDER_PAYMENT_EXPIRED_TOKENToken do formulário de pagamento expirado

Notify

contact

Envia mensagem de contato. Usado em formulários de página institucional de central de ajuda

ℹ️ Informação

O método baixo possui um Genérico obrigatório em sua assinatura.
Genérico flexível para atender qualquer informação necessária para o lojista consiga entrar em contato

1await Api.notify.contact<Data>(payload: Data);

Responsável por comunicação com a loja.

Third Party

Integrações com aplicações externas.

oauthRedirect

Método usado para autenticação com app de login social.

1await Api.thirdParty.oauthRedirect(
2 type: 'google-login' | 'facebook-login',
3 {
4 loginUrl: string;
5 registerUrl: string;
6 }
7)

Eventos do Facebook (API de Conversões)

Registram o evento no servidor e retornam o eventId, que deve ser repassado ao Pixel (fbq) para a deduplicação entre navegador e servidor.

ℹ️ Informação

O módulo Tracking já faz essas chamadas e o disparo no Pixel. Use estes métodos diretamente apenas se você não usa o Tracking.

MétodoPayloadEvento
facebookPageView()—PageView
facebookViewContent(payload){ productId: number }ViewContent
facebookAddToCart(payload){ sku: string; quantity: number; price: number }AddToCart
facebookInitiateCheckout()—InitiateCheckout
facebookAddPaymentInfo(payload){ totalValue: number }AddPaymentInfo
facebookSearch(payload){ searchTerm: string; contentIds?: Array }Search
facebookPurchase(payload){ orderGroupId: number }Purchase
1const eventId = await Api.thirdParty.facebookViewContent({ productId: 10 });
2
3window.fbq('track', 'ViewContent', { content_ids: ['10'], content_type: 'product' }, { eventID: eventId });

Utilitários

usePublicApi

Função base usada por todos os métodos do SDK. Use para chamar um endpoint da API Pública que ainda não tem método próprio no SDK: ela já aplica a URL base, os headers e o tratamento de erro.

1import { Api } from '@uappi/public-sdk';
2
3await Api.usePublicApi<ResponseType>({
4 endpoint: '/publics/...',
5 method: 'GET', // padrão
6 params?: object,
7 payload?: object,
8});

getCookieName / captureCookieName

Leem e capturam o nome do cookie de autenticação. Veja Instalação: nome do cookie de autenticação.

🏁 Próximo passo

Agora que você já domina o módulo Api do public-sdk, é hora de aprender sobre o Tracking.

SDK Público - Tracking: Introdução

Uappi é a melhor opção para o crescimento da sua loja!

;