← Voltar para o blog

Por que (não) construir mais um app de finanças - Parte 2: assinaturas e App Store

Pássaro roxo pensativo, com a mão no queixo, ao lado de uma pilha de livros, um notebook e grandes pontos de interrogação
Assinaturas, ou "é só cobrar".

Cobrar por um app parece a parte simples. Coloca um botão "Assinar", integra com a loja, recebe um aviso quando alguém paga.

Na nossa cabeça, era uma tabela e uma coluna status.

3
lojas cobrando: Stripe, Apple e Google
84
commits com "Apple" no nome desde fev/2026
3
diretrizes da App Store citadas numa única rejeição

Esta é a Parte 2 do diário que começamos na Parte 0. Na Parte 1, contamos o que deu trabalho no Open Finance. Agora é a vez de cobrar pelo app.

Contexto rápido: o Snabber tem plano grátis e planos pagos. Quem assina pela web paga no Stripe. Quem assina no iPhone paga para a Apple. Quem assina no Android paga para o Google.

O que a gente achou que era

O plano original
  1. Um botão "Assinar" em cada app
  2. A loja avisa quando alguém paga
  3. Se parar de pagar, volta para o plano grátis

O que realmente era

Passar na revisão da App Store

Antes de cobrar alguém no iPhone, o app precisa ser aprovado pela Apple. E cada nova versão passa pela revisão de novo. Uma pessoa da Apple instala o app, testa as telas e confere tudo contra as regras da App Store.

As regras são públicas, e são muitas. A revisão confere cada uma com lupa. Não existe detalhe pequeno demais para ser motivo de rejeição.

Em agosto de 2026, mandamos uma versão nova com os planos reformulados. Voltou com três diretrizes citadas de uma vez:

Rejeição de agosto de 2026
Diretriz 3.1.1 · Compras dentro do app
Um campo "tenho um código" no cadastro.
No iPhone, liberar o plano pago tem que passar pela compra da Apple. Um cupom digitado no app é outro caminho, então não pode. Removemos o campo da versão do iPhone.
Diretriz 3.1.2 · Assinaturas
Faltavam informações na tela de assinatura.
Nome do plano, duração, preço, aviso de renovação automática e links para os Termos de Uso e a Política de Privacidade, tudo antes do botão de pagar. Criamos uma tela de confirmação só para isso.
Diretriz 2.1 · App completo
Um plano aparecia como "Anual indisponível".
Para a revisão, um botão que não dá para usar é um app incompleto. Hoje a tela só mostra o que a loja da Apple confirma que está à venda.

Nenhum dos três quebrava o app. Os três bastavam para ele não ir ao ar.

Antes
Botão "Assinar" direto no card do plano
com "Tenho um código" embaixo e "Anual indisponível" ao lado
Agora
"Assinar" abre uma confirmação
anual ou mensal, duração, preço, renovação, Termos e Privacidade. Sem campo de cupom no iPhone.

E essas foram só as que apareceram de uma vez. Outras regras moldaram o app antes mesmo da primeira revisão. Quem oferece login com Google precisa oferecer também uma opção como "Entrar com a Apple". Quem deixa criar conta no app precisa deixar excluir a conta dentro do app, não só por e-mail ou pelo site.

Cada rejeição é uma rodada de dias: ler a mensagem da revisão, entender qual regra foi citada, ajustar, gerar uma versão nova, mandar de novo e esperar. Enquanto isso, a versão que estava pronta fica parada, junto com tudo o que tinha de novo.

Na web, a gente decide quando publicar. No iPhone, quem decide é a revisão.

Três lojas, três verdades

Passar na revisão é só a porta de entrada. Depois, cada loja tem o próprio jeito de dizer "ativo", "atrasado", "cancelado" e "em carência". O app precisa transformar tudo isso em uma resposta só.

Stripe + Apple + Google = pode usar o plano pago agora?

A Apple não te conta que o usuário cancelou

Quando alguém desliga a renovação automática no iPhone, a assinatura continua "ativa" até o fim do período. Faz sentido para o usuário, que pagou até lá.

Para a gente, significava não saber quem estava de saída. Por meses, essa informação virava um e-mail no nosso inbox e mais nada. Só em setembro de 2026 ela passou a ser registrada de um jeito que dá para consultar.

Carência que nunca acabava

24
dias no plano pago
depois de vencer

Quando a cobrança falha, Apple e Stripe dão alguns dias de carência antes de cortar o acesso. A gente respeitava isso. Respeitava tanto que um usuário ficou 24 dias no plano pago depois de vencer, com a própria Apple já confirmando "expirado". Nosso código tratava "em carência" como ativo, sem prazo.

Cartão recusado, cliente no escuro

No Stripe, quando o cartão era recusado, a gente mostrava um aviso no app. Só que só vê o aviso quem abre o app. Quem não abria descobria quando perdia o acesso.

Hoje vai e-mail e push com um link direto para trocar o cartão. E como o Stripe manda o mesmo evento a cada nova tentativa de cobrança, foi preciso garantir que ninguém recebesse cinco e-mails iguais.

Perder o plano não pode apagar o banco

No plano grátis não tem Open Finance. Então, quando alguém volta para o grátis, as conexões com o banco são removidas. E isso não tem volta: para reconectar, a pessoa precisa autorizar tudo de novo no app do banco (e, como vimos na Parte 1, reconectar é o momento mais frágil).

Manter alguém num plano pago por engano é perda de receita. Apagar as conexões dele sem aviso é dano que não dá para desfazer.

Entre os dois erros, a gente escolhe o primeiro. Hoje ninguém perde conexão sem ter sido avisado antes, com pelo menos um dia para assinar de novo.

Assinatura compartilhada multiplica tudo

Quando lançamos o plano para a família, cada limite do app (conexões, agentes de IA, acesso à API) precisou passar a contar o grupo, e não a pessoa. Num dos primeiros testes, quatro membros de um plano tinham, juntos, quatro vezes os agentes que o plano vendia.

snabber-fin
$ git log --oneline -i --grep=apple
c52be54a fix(apple): carência 'grace_period' deixa de proteger para sempre
e49bb9e6 Ajustes de rejeição Apple: cupom no iOS, modal de assinatura e disponibilidade via StoreKit
a4723fb6 webhook apple muitos emails
03750648 apple notifications and grace period
b65e57aa feat: Apple in-app purchase subscriptions

Alguns dos 84 commits com "Apple" no nome, de fevereiro a setembro de 2026.

O que fizemos

  • ✓Uma tela de assinatura no iPhone pensada desde o início para as regras da App Store.
  • ✓Uma regra única de "pode usar o plano pago" que traduz Stripe, Apple e Google.
  • ✓Carência com prazo e confirmação da loja antes de cortar o acesso.
  • ✓Registro de quem desligou a renovação no iPhone.
  • ✓Aviso por e-mail e push quando a cobrança falha, sem duplicar.
  • ✓Aviso obrigatório, com prazo, antes de qualquer perda de conexão bancária.

O que ainda não resolvemos

Toda versão nova do iPhone ainda é uma aposta. A gente lê as regras, testa, e mesmo assim só sabe se passou quando a resposta da revisão chega.

Excluir a conta no Snabber não cancela a assinatura da Apple. Só o próprio usuário consegue cancelar, nos Ajustes do iPhone. A gente avisa, mas sempre tem quem exclua a conta e continue sendo cobrado.

E a cada mudança de preço ou de plano, as três lojas precisam ser atualizadas e testadas separadamente. A da Apple, com revisão.

Se você vai cobrar em mais de uma loja

Leia as diretrizes da App Store antes de desenhar a tela de planos, não depois da primeira rejeição. E decida no primeiro dia qual é a sua fonte da verdade sobre quem é assinante.

Os eventos das lojas chegam atrasados, fora de ordem e repetidos. Trate todos como sugestão, não como ordem.

Quer ver como ficou? Crie sua conta no Snabber e teste o plano gratuito.

Na próxima parte: por que "a IA categoriza" é só metade da história.