Todos os artigos
Deep dive7 min de leitura

Seu app pode exibir uma folha de solicitação de reembolso dentro do app, e aqui está o que a Apple faz depois que o cliente toca em enviar

A solicitação de reembolso dentro do app da Apple permite que o cliente peça um reembolso sem sair do seu app, numa folha que a Apple constrói e revisa. Aqui está o que o beginRefundRequest retorna, os relógios do CONSUMPTION_REQUEST e das 48 horas que ele dispara no seu servidor, e se vale a pena publicar o botão.

Uma mão segurando um smartphone que mostra uma tela de configurações de conta ao lado de um recibo de papel e uma moeda, ilustrando uma solicitação de reembolso dentro do app que o cliente pode iniciar sem sair do app

Principais conclusões

  • O beginRefundRequest da Apple é um método do StoreKit 2 que apresenta a própria folha de reembolso da Apple dentro do seu app. O cliente vê os detalhes da compra e uma lista de códigos de motivo, escolhe um, e a solicitação vai para a Apple. Você não constrói o formulário nem decide o resultado.
  • A chamada retorna um status de success ou userCancelled, ou lança duplicateRequest ou failed. Um status success significa que o App Store recebeu a solicitação, não que a aprovou. Nunca mostre um reembolso confirmado na sua interface quando retornar success.
  • Depois que o cliente envia, a Apple leva até 48 horas para aprovar ou negar. Para compras consumíveis, ela primeiro envia um CONSUMPTION_REQUEST ao seu servidor, e você tem as habituais 12 horas para responder com dados de uso se o cliente consentiu.
  • O resultado chega ao seu servidor como um App Store Server Notification, o mesmo fluxo que você já recebe. A aprovação é uma notificação REFUND, a negação é REFUND_DECLINED. A solicitação dentro do app é roteada para esse fluxo exatamente como um reembolso iniciado na página reportaproblem da Apple.
  • O botão está disponível a partir do iOS 15 e iPadOS 15, Mac Catalyst 15 e visionOS 1, então qualquer app que mire essas versões pode apresentá-lo hoje.
  • O argumento financeiro é que um reembolso que você pode contestar vence um chargeback que você não pode. Manter o cliente dentro do fluxo da Apple dispara um CONSUMPTION_REQUEST que você pode responder, em vez de um chargeback bancário que é definitivo e carrega uma taxa.
  • A recomendação de posicionamento da Apple é chamá-lo a partir das configurações de conta ou de um menu de ajuda, não de uma tela de compra, para que um cliente insatisfeito o encontre sem anunciar reembolsos a todo mundo.

A Apple permite que o cliente solicite um reembolso sem jamais sair do seu app. Uma única chamada do StoreKit, beginRefundRequest, apresenta a própria folha de reembolso da Apple bem dentro da sua interface, o cliente escolhe um motivo, e a solicitação vai para a Apple para revisão. Você não constrói o formulário, não toca no dinheiro, e não decide o resultado. O que você ganha é uma forma de colocar um caminho de reembolso onde o cliente frustrado já está, em vez de perdê-lo para o banco dele. Esta é a solicitação de reembolso dentro do app, e vale a pena entendê-la antes de decidir se publica o botão.

Aqui está a parte que importa para a sua receita. O botão não reembolsa nada por conta própria. Ele abre uma solicitação, a Apple leva até 48 horas para aprovar ou negar, e para compras consumíveis dispara primeiro um CONSUMPTION_REQUEST para o seu servidor. Então a folha não é um presente. É um funil para a mesma revisão de reembolso que você já pode influenciar, e pode puxar uma disputa de volta da rede de cartões antes que ela vire um chargeback que você não pode contestar.

O que a folha de solicitação de reembolso dentro do app realmente é

beginRefundRequest é um método do StoreKit 2 que apresenta a folha de solicitação de reembolso para uma transação em uma cena de janela. A assinatura é curta: func beginRefundRequest(in scene: UIWindowScene) async throws -> Transaction.RefundRequestStatus. Quando você o chama, o sistema mostra uma folha com os detalhes da compra do cliente e uma lista de códigos de motivo para ele escolher. A Apple constrói e controla essa interface. Você fornece a cena e a transação, nada mais.

A recomendação da Apple sobre onde colocá-lo é explícita. Chame esta função a partir das configurações de conta ou de um menu de ajuda, para que um cliente que quer um reembolso o encontre onde procuraria suporte. Ele chegou no iOS 15 e iPadOS 15, Mac Catalyst 15 e visionOS 1, então qualquer app que mire essas versões pode apresentá-lo hoje.

Duas formas de abrir a folha

Há dois pontos de entrada. Você pode chamar beginRefundRequest(in:) em uma transação específica que já possui, o que limita a folha àquela compra. Você também pode abrir a folha por identificador de produto quando quiser que o cliente reembolse a compra de um dado produto. De qualquer forma, a folha, a lista de motivos e a decisão pertencem à Apple. Seu trabalho termina em apresentá-la e ler o resultado.

O que a chamada retorna, e o que pode dar errado

O método é async throws, então ele ou retorna um status ou lança um erro. Ambas são listas curtas, e ambas merecem tratamento para que sua interface diga algo verdadeiro quando a folha fechar.

ResultadoTipoO que significa
successRefundRequestStatusO App Store recebeu a solicitação de reembolso. Está enviada, não aprovada
userCancelledRefundRequestStatusO cliente fechou a folha sem enviar. Nada foi enviado
duplicateRequestRefundRequestErrorO App Store já tem uma solicitação de reembolso para esta compra
failedRefundRequestErrorO envio em si falhou. Deixe o cliente tentar de novo

O que acontece no seu servidor depois que o cliente toca em enviar

O fechamento da folha é o início do processo, não o fim. A Apple revisa a solicitação e leva até 48 horas para aprovar ou negar. Para uma compra consumível dentro do app, antes de decidir, o App Store envia uma notificação CONSUMPTION_REQUEST ao seu servidor pedindo dados de uso. Se o cliente consentiu em compartilhar esses dados, você responde pelo endpoint Send Consumption Information. Se ele não consentiu, a própria instrução da Apple é não responder à notificação de forma alguma.

Assim que a Apple decide, o resultado aterrissa no seu servidor como um App Store Server Notification. É o mesmo fluxo que você já recebe, e a solicitação dentro do app é roteada para ele exatamente como um reembolso que um cliente inicia na página reportaproblem da Apple. Nada do tratamento muda só porque a solicitação começou dentro do seu app.

EtapaO que disparaSua açãoRelógio
O cliente envia a folhabeginRefundRequest retorna successRegistre, mostre pendente, não reembolsadoInstantâneo
Apenas consumíveis, a Apple pergunta primeironotificação CONSUMPTION_REQUESTEnvie dados de consumo se o cliente consentiu, caso contrário fique em silêncio12 horas para responder
A Apple aprovanotificação REFUNDRevogue o direito daquela transaçãoAté 48 horas para decidir
A Apple neganotificação REFUND_DECLINEDMantenha a venda, não mude nadaAté 48 horas para decidir
Uma ampulheta ao lado de um smartphone e um recibo de papel, ilustrando a espera de até 48 horas depois que um cliente envia uma solicitação de reembolso dentro do app à Apple

O que o botão custa a você, e o que ele pode economizar

Um reembolso que você pode contestar vence um chargeback que você não pode

Um cliente que não encontra um caminho de reembolso dentro do seu app não desiste. Ele vai ao banco. Um chargeback de cartão é definitivo com o banco, carrega uma taxa de disputa, e tira a decisão das suas mãos e das da Apple. Uma solicitação de reembolso dentro do app mantém esse mesmo cliente dentro do sistema da Apple, onde uma compra consumível dispara um CONSUMPTION_REQUEST que você pode responder e uma decisão que você pode influenciar. Trocar um chargeback incontestável por uma revisão contestável da Apple é todo o argumento financeiro a favor do botão.

Você está reduzindo o atrito de um reembolso

O contrapeso honesto é que um caminho de reembolso visível e de um toque produz mais solicitações de reembolso do que um e-mail de suporte enterrado. Algumas delas nunca teriam acontecido. Esse é um custo real, e é por isso que a Apple diz para você colocar o ponto de entrada nas configurações de conta ou num menu de ajuda, em vez de na tela de compra. Você quer que o cliente que já está insatisfeito o encontre, não o cliente que está apenas curioso.

O custo que corre o tempo todo é servir uma conta reembolsada

Seja qual for a decisão, o medidor da entrega continua correndo até você agir sobre o resultado. A cada hora que um direito reembolsado fica ativo, você continua pagando os custos reais por trás dele: computação, chamadas à API do modelo, armazenamento, e qualquer pagamento a criadores ou parceiros vinculado ao uso daquele cliente. A solicitação dentro do app não muda isso. Revogar prontamente na notificação REFUND muda. O botão é tão barato quanto for o seu tratamento da notificação que ele acaba produzindo.

Você deveria publicar a solicitação de reembolso dentro do app?

Coloque onde mora o suporte, não onde moram as vendas

Siga a recomendação de posicionamento da Apple. As configurações de conta e um menu de ajuda são os lares certos. Um link de reembolso ao lado de um paywall treina as pessoas a esperar o dinheiro de volta, e convida o reembolso por curiosidade que você nunca precisou oferecer.

Teste o fluxo completo no sandbox antes de confiar nele

Você pode simular todo o caminho no sandbox e no teste do StoreKit no Xcode, movendo uma solicitação de pendente para aprovada ou negada. Uma aprovação entrega uma notificação REFUND ao seu servidor, e uma negação entrega REFUND_DECLINED, então você pode provar que seu manipulador reage corretamente antes que um cliente real toque em enviar.

Trate cada resultado, e nunca exagere

Mostre pendente em success, ofereça uma nova tentativa em failed, diga que nada mudou em userCancelled, e trate duplicateRequest como uma nota discreta de que a solicitação anterior do cliente ainda está de pé. O único erro que machuca é dizer a um cliente que o reembolso está feito quando tudo o que você tem é uma solicitação enviada.

Como o RefundHalt cuida do que vem depois

A folha dentro do app é da Apple. O que vem depois é seu, e essa é a parte que o RefundHalt executa. Quando um cliente envia um reembolso de dentro do seu app, o RefundHalt captura o CONSUMPTION_REQUEST para compras consumíveis e o responde dentro da janela de 12 horas com a evidência de uso que ajuda a Apple a decidir. Quando a Apple decide, ele revoga em REFUND e mantém o acesso intocado em REFUND_DECLINED, cada um vinculado à transação exata. Você pode oferecer o caminho de reembolso mais amigável dentro do app sem deixar a revisão, a evidência ou a revogação para uma correria manual.

Perguntas frequentes

O que o beginRefundRequest faz?
Ele apresenta a folha de solicitação de reembolso da Apple dentro do seu app para uma transação específica. O cliente vê os detalhes da compra e uma lista de códigos de motivo, escolhe um, e a solicitação vai para a Apple. O método retorna um status de success ou userCancelled, ou lança duplicateRequest ou failed. Ele não reembolsa a compra em si, porque a Apple revisa a solicitação e leva até 48 horas para decidir.
Uma solicitação de reembolso dentro do app reembolsa o dinheiro na hora?
Não. Um resultado success significa que o App Store recebeu a solicitação, não que a aprovou. A Apple leva até 48 horas para aprovar ou negar, e para consumíveis primeiro pede ao seu servidor dados de uso por meio de uma notificação CONSUMPTION_REQUEST. Mostre ao cliente um estado pendente em success, nunca um reembolso confirmado.
Qual versão do iOS suporta a solicitação de reembolso dentro do app?
iOS 15 e iPadOS 15, Mac Catalyst 15 e visionOS 1. O método do StoreKit 2 beginRefundRequest(in:) está disponível a partir dessas versões, então qualquer app que mire iOS 15 ou posterior pode apresentar a folha de reembolso da Apple de dentro do app.
Onde eu deveria colocar o botão de reembolso dentro do app?
A recomendação da Apple é chamá-lo a partir das configurações de conta ou de um menu de ajuda, não de uma tela de compra ou paywall. Isso coloca o caminho de reembolso onde um cliente insatisfeito procura suporte, sem anunciar reembolsos a clientes que não iam pedir.
Um reembolso dentro do app é melhor do que um cliente contatar o banco?
Geralmente sim, para a sua receita. Um chargeback bancário é definitivo e carrega uma taxa, e remove tanto a Apple quanto você da decisão. Uma solicitação de reembolso dentro do app mantém o cliente no fluxo da Apple, onde uma compra consumível dispara um CONSUMPTION_REQUEST que você pode responder e uma revisão que você pode influenciar. Um reembolso contestável vence um chargeback incontestável.

Fontes e leituras adicionais

RefundHalt

O piloto automático de reembolsos para App Store e Google Play

Continue lendo

A próxima solicitação de reembolso já está a caminho.

Configure a RefundHalt no tempo que você levaria para ler mais um e-mail de suporte sobre um reembolso que não conseguiu contestar.