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.

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.
| Resultado | Tipo | O que significa |
|---|---|---|
| success | RefundRequestStatus | O App Store recebeu a solicitação de reembolso. Está enviada, não aprovada |
| userCancelled | RefundRequestStatus | O cliente fechou a folha sem enviar. Nada foi enviado |
| duplicateRequest | RefundRequestError | O App Store já tem uma solicitação de reembolso para esta compra |
| failed | RefundRequestError | O 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.
| Etapa | O que dispara | Sua ação | Relógio |
|---|---|---|---|
| O cliente envia a folha | beginRefundRequest retorna success | Registre, mostre pendente, não reembolsado | Instantâneo |
| Apenas consumíveis, a Apple pergunta primeiro | notificação CONSUMPTION_REQUEST | Envie dados de consumo se o cliente consentiu, caso contrário fique em silêncio | 12 horas para responder |
| A Apple aprova | notificação REFUND | Revogue o direito daquela transação | Até 48 horas para decidir |
| A Apple nega | notificação REFUND_DECLINED | Mantenha a venda, não mude nada | Até 48 horas para decidir |

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
- Apple Developer: beginRefundRequest(in:)
- Apple Developer: Transaction.RefundRequestStatus
- Apple Developer: Transaction.RefundRequestError
- Apple Developer: App Store Server Notifications V2 notificationType
- Apple Developer: Send Consumption Information
- Apple Developer: Support customers and handle refunds (WWDC21)
RefundHalt
O piloto automático de reembolsos para App Store e Google Play
Continue lendo
Quando uma compra do Google Play é reembolsada ou estornada, a Voided Purchases API é como você fica sabendo
O Google Play anula uma compra silenciosamente quando ela é reembolsada ou estornada. A Voided Purchases API é a lista desses pedidos, para que você possa revogar o acesso. Aqui estão todos os campos, a janela de 30 dias, a opção de revogação que oculta pedidos e quanto custa.
Três notificações de reembolso da App Store chegam depois que a Apple decide, e REFUND_REVERSED devolve a venda
A Apple envia quatro mensagens de reembolso pelo App Store Server Notifications V2, e a maioria dos apps trata apenas duas. REFUND diz para revogar, REFUND_DECLINED significa manter a venda, e REFUND_REVERSED devolve a venda e pede que você restaure o que retirou. Aqui está o que cada uma exige.