App Store & Play Store Development

Toda compra na App Store precisa de um appAccountToken, ou sua defesa de reembolso não tem onde se apoiar

Quando um cliente solicita um reembolso, a Apple envia um CONSUMPTION_REQUEST que nunca o identifica. O appAccountToken é o UUID que vincula uma compra ao seu usuário. Defina-o e você pode responder com dados reais; ignore-o e você estará apenas chutando.

5 min read
Toda compra na App Store precisa de um appAccountToken, ou sua defesa de reembolso não tem onde se apoiar

Doze horas é tudo o que a Apple lhe dá para justificar um reembolso com evidências. Esse prazo não vale nada se a transação diante de você pertence a um cliente que você não consegue identificar. O appAccountToken é o UUID que fornece essa identificação, e ele só pode ser anexado enquanto a compra está acontecendo.

Imagine a notificação chegando. A Apple quer saber quanto desse produto esse comprador realmente consumiu, há quanto tempo ele é cliente, quanto gastou no total. Perguntas razoáveis, e o seu banco de dados tem todas as respostas. O problema é que o payload diante de você oferece um originalTransactionId e um identificador de produto, nenhum dos quais corresponde a nada na sua tabela de usuários. Você está com uma nota fiscal sem nome, e as respostas de que você precisa estão arquivadas sob nomes.

Esse descompasso tem solução, e a solução tem um prazo. O appAccountToken é um UUID que o seu sistema gera, entrega ao StoreKit durante o checkout, e a Apple então grava na transação resultante. A partir desse momento, tudo o que a Apple lhe informa sobre essa compra chega já identificado. Perca esse momento, porém, e a venda em questão permanece anônima para sempre. A seguir: o que é esse campo, como anexá-lo, o endpoint que resgata retroativamente compras que o seu app nunca viu, e a aritmética do que um reembolso anônimo realmente retira do seu negócio.

Principais pontos

  • Anexe um UUID a uma compra da App Store e a transação criada apontará diretamente para um usuário específico nos seus registros. A Apple mantém esse valor na transação e o devolve em todos os lugares onde essa transação aparece.

  • O formato é a única coisa que a Apple fiscaliza, e o formato é UUID. Forneça um id de banco de dados, um endereço de e-mail, uma string montada à mão, e o StoreKit a descarta sem reclamar, deixando nil onde o appAccountToken deveria estar.

  • O StoreKit 2 o expõe como uma única opção de compra, Product.PurchaseOption.appAccountToken(_:), alimentada por um UUID que o seu sistema gerou e registrou naquela conta previamente.

  • Anexe-o à compra inicial e a Apple propaga esse mesmo valor por todas as renovações, todas as novas tentativas de cobrança e todos os upgrades ao longo da cadeia de assinatura.

  • A partir de 2025, o endpoint Set App Account Token dá ao seu servidor uma forma de marcar compras que o fluxo no app nunca viu, incluindo resgates de códigos de oferta e compras promovidas.

  • O CONSUMPTION_REQUEST da Apple só se torna respondível por causa desse token. Sem ele, você não consegue conectar o reembolso ao próprio cliente cujo consumo você deve detalhar dentro da janela de 12 horas.

  • Um reembolso não identificável é um reembolso indefensável. O dinheiro volta em vendas para as quais você tinha provas, e o processamento, as chamadas de API e os pagamentos já gastos para entregá-las vão junto.

O que esse campo realmente faz

A Apple trata esse valor como algo sem significado próprio, e esse é o ponto. Qualquer UUID que você entregue ao StoreKit durante o checkout é gravado na transação e preservado indefinidamente, sem nenhuma tentativa de interpretá-lo, validar a que ele se refere ou verificar se corresponde a algo de fato. A própria definição da Apple o descreve como "o UUID que associa a transação à conta do usuário no seu próprio serviço." A interpretação é totalmente da sua responsabilidade. A Apple simplesmente carrega o valor consigo e o devolve quando solicitado.

É onde ele é devolvido que torna esse campo útil. As notificações de servidor o trazem dentro da transação assinada. Peça o Get Transaction Info à App Store Server API e ele aparece lá. Toda renovação subsequente em uma cadeia de assinatura o reproduz, desde que a compra original o tenha carregado. Em outras palavras, anexe o valor em um único momento, e ele continuará reaparecendo por todo o tempo em que esse cliente continuar pagando você.

Passe qualquer coisa que não seja um UUID e ele desaparece sem aviso

Os desenvolvedores geralmente descobrem essa regra violando-a. Algo que parecia razoável é passado, um id de conta interno, um endereço de e-mail, alguns campos concatenados, e o StoreKit não levanta nenhuma objeção. Nenhuma exceção, nenhum aviso, nenhuma compra falhada. A transação simplesmente retorna com o appAccountToken como nil, e a conexão que você supunha ter nunca foi criada. Os fóruns de desenvolvedores da Apple trazem um fluxo constante dessa mesma confusão, geralmente formulada como "appAccountToken is missing in the transaction payload", e a explicação é quase sempre um valor que não atendeu ao requisito de formato.

Esse requisito é estreito: o StoreKit 2 aceita um UUID RFC 4122 e nada além disso. Portanto, o padrão seguro é gerar o UUID no seu servidor, persisti-lo junto à conta e garantir que nenhum outro tipo de valor chegue à chamada de compra.

O silêncio é o que torna isso perigoso. Um valor malformado não custa nenhum erro e nenhuma venda perdida, apenas o vínculo em si, descartado silenciosamente enquanto tudo o mais segue normalmente. Verificar o valor contra o formato UUID antes que ele chegue ao StoreKit custa uma linha de código e elimina todo esse modo de falha.

Anexando o token durante o checkout

Uma única opção de compra é toda a implementação. Gere o UUID no lado do servidor no momento do cadastro, ou na primeira vez que o cliente chega ao checkout, grave-o no registro da conta dele e, depois, forneça esse mesmo valor todas as vezes que ele comprar.

A assinatura da opção é Product.PurchaseOption.appAccountToken(_ token: UUID), e a chamada em si fica assim: try await product.purchase(options: [.appAccountToken(token)]). Independentemente da forma como a transação finalizada chega até você, seja verificando-a por conta própria junto à App Store Server API ou recebendo-a como notificação de servidor, aquele UUID viaja dentro dela, o que reduz a identificação do cliente a uma única busca indexada.

Um token por cliente, reutilizado para sempre

Um erro tentador é gerar um novo token para cada transação. Fazer isso desmonta silenciosamente o benefício. A Apple reproduz o token que estava na compra original em renovações, novas tentativas de cobrança e upgrades dentro daquela cadeia, o que significa que um UUID durável por conta mantém todo o histórico de pagamentos de um cliente conectado. Troque o valor e cada compra se torna uma ilha isolada. Estabilidade é a propriedade que importa aqui, então escolha um UUID quando a conta for criada e nunca o altere.

O endpoint que resgata compras que o seu app nunca tocou

Duas rotas de compra costumavam anular isso completamente. O resgate de um código de oferta acontece na App Store, não no seu app. O mesmo vale para a compra de uma in-app purchase promovida a partir de uma listagem da loja. Nenhuma dessas rotas executa o seu código de compra, o que significava que não havia nenhum momento em que um token pudesse ser fornecido, e essas transações permaneciam permanentemente anônimas.

Essa limitação terminou na WWDC 2025 com o endpoint Set App Account Token. Seu servidor emite um PUT /inApps/v1/transactions/{originalTransactionId}/appAccountToken contra a App Store Server API, levando o UUID no corpo da requisição, e a Apple o grava na transação. A cobertura se estende a todos os tipos de produto, incluindo resgates de códigos de oferta e compras promovidas, e um valor enviado dessa forma substitui qualquer token que a transação já estivesse carregando. A identificação, portanto, passou a ser algo que você pode realizar posteriormente, totalmente no lado do servidor, em compras nas quais o seu app nunca esteve envolvido.

Onde você anexa o token depende de como a compra aconteceu:

  • Para uma in-app purchase comum, defina-o na opção de compra do StoreKit no momento da compra, via Product.PurchaseOption.appAccountToken(UUID).

  • Para um resgate de código de oferta, defina-o com o endpoint Set App Account Token a partir do seu servidor, porque não há nada no app para se conectar e você precisa anexá-lo depois.

  • Para uma in-app purchase promovida pela App Store, defina-o da mesma forma com o endpoint Set App Account Token, já que a transação acontece fora do seu app.

  • Para uma renovação de assinatura, você não precisa fazer nada. O token é herdado automaticamente da compra original.

O que um vínculo quebrado faz com a sua receita

Manter registros organizados não é o argumento aqui. O argumento é que a Apple faz exatamente uma pergunta aos desenvolvedores durante um reembolso, entregue como um CONSUMPTION_REQUEST, e respondê-la exige saber qual dos seus clientes está em questão.

Solicitações de reembolso de consumíveis e assinaturas não renováveis disparam essa notificação, e o Send Consumption Information é como você responde, dentro de doze horas. A Apple espera detalhes sobre um indivíduo específico: a proporção do produto consumida, o tempo como cliente, o gasto total ao longo do tempo, o status da entrega. O token aparece como um campo dentro da própria requisição, mas seu papel mais importante é estrutural, porque é a única coisa capaz de transformar aquela notificação em uma linha no seu próprio banco de dados. Remova o token e a requisição se torna impossível de responder, não importa quão detalhado seja o seu rastreamento de uso.

O preço de responder sem nada

Restam duas opções quando um reembolso chega sem identificação, e nenhuma delas é boa. Envie uma resposta de consumo vazia e a Apple a interpreta como uso mínimo, o que inclina a decisão para a aprovação, incluindo usuários intensivos. Invente uma estimativa, em vez disso, e você estará reportando ficção a um detentor de plataforma. Qualquer caminho que você escolha, vendas que você poderia ter comprovado acabam sendo reembolsadas de qualquer forma, depois que você já pagou para entregá-las.

O custo de entrega é a parte que dói, porque não tem relação com o preço de venda. Chamadas de API de modelo consumidas durante uma geração, imagens produzidas, um vídeo renderizado e exportado, um pagamento a criador liberado mais adiante: todo esse dinheiro saiu das suas contas no momento da entrega, e reembolsar o cliente não faz nada para recuperá-lo. Agora escale o problema. Um único cliente anônimo solicita reembolso repetidamente. Solicitantes habituais de reembolso visam especificamente negócios que não conseguem identificá-los. O token ignorado deixa de ser uma pequena omissão nesse ponto e passa a funcionar como uma torneira aberta.

A pergunta da Apple diz respeito ao consumo real de um cliente, e respondê-la exige saber quem é esse cliente. Sem o token, você perde vendas que poderia ter comprovado, junto com o processamento e os gastos de API já comprometidos na entrega delas.

O Android roda a mesma jogada com outro nome

O setObfuscatedAccountId cumpre essa função no Google Play, vinculando um identificador de conta a uma compra para que a análise de chargeback via orders.reviewrefund tenha uma pessoa real para examinar. As implementações divergem bastante, mas a disciplina subjacente se transfere sem modificação: a identidade é vinculada durante a transação, ou a disputa é perdida por padrão depois. A versão da Apple dessa disciplina é o appAccountToken, e ele exige um UUID.

Três práticas que mantêm toda compra identificada

  • Gere um UUID por conta e persista-o. Um único token durável por cliente, criado no cadastro ou no primeiro checkout, gravado no registro dele e reutilizado em tudo o que ele comprar.

  • Verifique o valor antes de entregá-lo. Confirme que ele realmente é um UUID dentro do seu código de compra, para que um identificador malformado nunca se transforme silenciosamente em um token nil na transação.

  • Preencha retroativamente tudo o que foi comprado fora do app. Quando uma notificação de servidor chegar para um resgate de código de oferta ou uma compra promovida sem token, recorra ao endpoint Set App Account Token e anexe o token correto.

Adote as três práticas e a identificação deixa de ser algo que você tenta depois do fato. Ela se torna uma propriedade que toda transação já tem quando a Apple a entrega a você, incluindo as solicitações de reembolso.

O Refund Sensor foi construído diretamente sobre essa premissa. Extraímos o appAccountToken de cada transação e notificação de servidor, cruzamos com os dados de consumo já registrados para aquela conta, e enviamos uma resposta à solicitação da Apple bem dentro da janela de doze horas, usando números que descrevem genuinamente aquele comprador. Um reembolso que você consegue identificar é um reembolso que você pode contestar, e esse é o único tipo que vale a pena contestar.

Onde essas regras estão documentadas

Perguntas frequentes

Um UUID que pertence ao seu sistema e que o StoreKit apenas registra. Você o fornece durante o checkout, a Apple o grava na transação resultante e, a partir daí, ele reaparece em todos os lugares onde essa compra aparece: nas informações da transação, em qualquer notificação de servidor relacionada a ela e em cada renovação mais adiante na mesma cadeia. O efeito prático é que tudo o que a Apple informar depois, incluindo uma solicitação de reembolso, pode ser direcionado para a linha correta no seu próprio banco de dados.

O formato, quase certamente. O RFC 4122 é o padrão que o StoreKit 2 aceita, e um valor que não passa esse teste é descartado sem levantar erro, deixando nil enquanto a compra se completa como se nada tivesse dado errado. Ids de registro interno, endereços de e-mail e strings montadas à mão falham exatamente dessa maneira. A outra possibilidade é que o seu app nunca tenha processado a compra, sendo o resgate de código de oferta o culpado mais comum, de modo que nenhum código seu chegou a rodar para fornecer um token.

Desde 2025, sim. A Apple introduziu o Set App Account Token na App Store Server API exatamente para essa situação. Um PUT para /inApps/v1/transactions/{originalTransactionId}/appAccountToken, com o UUID fornecido no corpo, grava um token em uma transação que já existe, ou substitui um que já estava lá. Todos os tipos de produto se qualificam, e o recurso foi desenhado em torno de compras que o seu app nunca tratou, especialmente códigos de oferta e compras promovidas.

Sim, sem exceção. Para onde o UUID aponta do seu lado é assunto inteiramente seu, e a Apple nunca inspeciona isso, mas o próprio valor precisa satisfazer o formato UUID. Se não satisfizer, o StoreKit se recusa a mantê-lo, deixando nil na transação.

Reembolsos disparam um CONSUMPTION_REQUEST, e a Apple espera uma resposta dentro de doze horas descrevendo como aquele comprador específico usou o produto. Produzir essa resposta significa converter a transação da notificação em um registro de cliente que você realmente pode consultar, o que é precisamente a função do token. Ele também viaja como um campo dentro da requisição. Sem ele, sua resposta fica vazia ou inventada, e uma resposta vazia geralmente resulta na concessão do reembolso.

#appaccounttoken#storekit#refunds#in-app purchases#ios
Refund SensorRefund Sensor TeamRefund defense for App Store and Google Play developers