Cartazista.online · JC Marketing Digital · 21 ago 2026

Setup Cartazista

Ordem das quatro frentes, o formulário de Basic Access da Google Ads API campo a campo, e como separar assinatura nova de recorrência no Meta.

Repo VT
clonado · v1.5.0
Credenciais Google
4/4 em .dev.vars
Refresh token
gerado · expira em 7d
DNS
ainda na GoDaddy
01

O token que você acabou de gerar morre em 7 dias

Isso não é folclore — está literal na página de erros comuns da Google Ads API: “A Google Cloud Platform project with an OAuth consent screen configured for an external user type and a publishing status of Testing is issued a refresh token expiring in 7 days.” Seu projeto é External e está em Testes. Passados sete dias, toda venda enviada ao Google volta invalid_grant.

A mensagem que o script imprimiu (“ele não expira”) foi escrita para o cenário de app publicado. Nesse ponto ela está errada para o seu caso, e é por isso que eu não subi nada para a Cloudflare ainda.

Decisão que muda o resto do setup

Existem dois caminhos, e o Google recomenda o segundo.

A — Publicar o app OAuth. Em Google Auth Platform → Público-alvo, mudar o status para “Em produção”. O refresh token vira de longa duração. Custo: como o escopo adwords é classificado como sensível/restrito e o app não é verificado, quem autorizar continua vendo a tela “o Google não verificou este app”, e o projeto passa a ter um teto de 100 novos usuários — vitalício, que não pode ser resetado. Para um cliente só, irrelevante.

B — Service account. A doc da Google Ads API diz textualmente: “Google recommends using the service account workflow over the single user authentication workflow.” Cria-se uma service account no projeto Cloud, e o e-mail dela é adicionado em Google Ads → Administrador → Acesso e segurança → Usuários. Não existe refresh token no circuito: nada expira em 7 dias, nada em 6 meses, e a autorização não morre se o Jeferson trocar de senha ou sair da operação.

Minha recomendação é a B, e ela tem uma consequência de código: o conector google-ads.js do VT autentica por refresh token. Migrar para service account exige assinar um JWT dentro do Worker — dá para fazer com a WebCrypto API, sem biblioteca, mas é trabalho novo que o fênix não tem. Se você preferir não abrir esse escopo agora, o caminho A resolve com um clique e o token que já está no .dev.vars continua servindo. Me diga qual e eu sigo.

02

A ordem das frentes

A ordem não é preferência, é dependência: três das quatro frentes travam no DNS, e a que você mais quer (conversão offline) é a única que depende de aprovação externa com prazo que você não controla. Por isso ela é a última a fechar — e a primeira a ser pedida.

1

GoDaddy → Cloudflare

Pré-requisito de tudo. Worker Route só funciona em hostname proxiado pela Cloudflare — sem o domínio lá, não existem nem as páginas de política nem o /tracking/web.js.

pode começar jásessão própria
2

Setup do VT — infra + Meta

Worker, D1, script no site, e o Meta inteiro. Não depende de nada do Google. É a frente que entrega resultado mais rápido e onde mora a questão do SaaS (seção 4).

depende de 1workflow.md conduz
3

Páginas legais + publicar o app OAuth

Política de privacidade e termos servidos pelo Worker no domínio do cliente, como no fênix. Resolve a expiração de 7 dias e dá ao auditor do Google páginas reais para abrir.

depende de 1só se caminho A
4

Aplicação de Basic Access

Peça assim que o site estiver no ar e as páginas publicadas — a análise leva de dias a duas semanas e roda em paralelo com o resto. Até aprovar, o Google Ads já funciona em modo web pelo gtag; só o purchase server-side fica pendente.

depende de 1 e 3prazo externo

Três achados do DNS que valem para a sessão de migração

Medi o estado real de cartazista.online hoje. O www já está quebrado antes de qualquer migração — o CNAME aponta para base44.onrender.com, que devolve 409 e falha o handshake TLS. Não é culpa da Cloudflare; é a chance de consertar. O apex já está atrás de uma Cloudflare (o IP da Lovable responde com CF-RAY), que é exatamente o cenário que produz o Error 1000 quando você liga a nuvem laranja — precisa ser testado no ato. E o e-mail é GoDaddy Professional Email, não Microsoft 365: o DKIM tem seletor imprevisível e só aparece no zone file exportado, então exportar a zona antes de tocar em qualquer coisa não é zelo, é o que evita o e-mail começar a cair em spam dias depois.

03

O formulário, campo a campo

Seu print é a versão nova do formulário — 11 perguntas, e o botão é Next, não Submit. Há mais telas depois (tipos de campanha e capabilities). O histórico que você me passou é de um caso bem diferente do seu: agência gerenciando contas de terceiros, que foi rejeitada. O Cartazista é o caso fácil — o próprio anunciante, na própria conta, um único uso. A regra que derrubou aquele pedido é a mesma que protege o seu, desde que as respostas fiquem coerentes.

O princípio que decide a aprovação

O compliance do Google cruza as respostas entre si e contra o PDF anexado. Cada divergência é motivo de rejeição. A narrativa inteira precisa dizer uma coisa só: ferramenta interna, proprietária, usada só pelo Cartazista, cujo único uso da API é importar conversão offline. Nada de gestão de campanha, nada de terceiros, nada de revenda.

1

My API contact email in the API Center is accurate and up-to-date.

☑ marcar

Antes de marcar, abra de fato a Central de API na MCC e confirme que o e-mail está preenchido e é uma caixa que alguém lê. O aviso embaixo do campo não é decorativo: não responder ao time de API pode rebaixar ou encerrar o token depois. Se o Google pedir esclarecimento e ninguém responder em poucos dias, o pedido é arquivado.

2

Enter the 11- or 12-digit numeric Google Cloud project number.

902957080860

Esse número você já tem: é o prefixo do seu client ID (902957080860-0tjbfm2g…). O que vem antes do hífen é o project number. Não confunda com o project ID alfanumérico, que no seu caso é verdadeiro-trackeamento — o campo pede o numérico, e essa troca é um erro comum.

3

Enter the Google Ads manager account (MCC) ID associated with your developer token.

— preciso desse dado —

Formato 123-456-7890, no canto superior do painel. Tem que ser a MCC onde o developer token FNbD64… foi criado, não a conta de anúncios do Cartazista. Se o token nasceu numa MCC sua de agência e a conta do cliente está pendurada nela, é o ID da MCC que vai aqui — e aí vale ler o alerta da pergunta 10.

4

Provide your contact email address.

jefersoncosta.marketing@gmail.com ← trocar, se possível contato@cartazista.online ← preferível

O texto de ajuda diz explicitamente que “an email address on your company's domain is preferred”. Um Gmail pessoal funciona, mas é sinal fraco num pedido que é julgado por sinais. Se existir qualquer caixa @cartazista.online monitorada, use ela. O que não pode é ser um endereço que ninguém abre.

5

Do you have an ongoing relationship with a representative at Google?

○ No

Só marque Yes se a conta realmente tiver um gerente do Google designado — contas com investimento alto às vezes têm, e nesse caso ajuda. Marcar Yes sem ter é o tipo de coisa que eles conferem.

6

Provide the URL for your company's primary website.

https://cartazista.online/

O aviso no topo do formulário é direto: “If the website is not live, Google might not be able to process your application.” É a dependência de calendário mais importante do documento — não submeta durante a janela de migração de DNS. Se o site oscilar enquanto o auditor abre, você queima o pedido e recomeça.

7

Describe your business model, the API tool you are building, and your intended audience.

Cartazista (JC Marketing Digital Ltda, CNPJ 53.299.211/0001-33) is a Brazilian SaaS that lets retailers create and print in-store price posters. We advertise our own subscription product on Google Ads and operate our own advertising account. We do not manage campaigns for third parties. We built a proprietary, self-hosted measurement backend that we own, host and maintain. Its only use of the Google Ads API is offline conversion import: when our payment gateway approves a subscription charge, the backend uploads that conversion via UploadClickConversions, matched to the gclid captured on the visitor's first page view, so our own campaigns are optimized on confirmed revenue instead of browser-side signals. The tool is internal and used only by our own team. It does not create, modify or pause campaigns, does not manage accounts, budgets or keywords, and is never sold, licensed or distributed to anyone.

Em inglês, sempre. O histórico do outro caso registra que responder em português é motivo de recusa por barreira de idioma. O campo equivalente tinha limite de 1000 caracteres — este texto tem cerca de 900, com folga.

Os três parágrafos existem para responder, na ordem, as três perguntas que o auditor realmente faz: quem é a empresa, o que exatamente a API vai fazer e quem toca a ferramenta. O terceiro é o que mais pesa — é ele que preempta a acusação de ferramenta de terceiros.

8

Provide documentation of your tool (.pdf, .doc, or .rtf only).

PDF, em inglês, 4 a 6 páginas

É o anexo que o auditor lê de verdade. O do fênix tinha 5 páginas e o escopo declarado ali era exatamente o que o código faz — nem mais, nem menos. Precisa conter: visão geral da empresa e do produto; arquitetura (Cloudflare Worker + D1, webhook do gateway, captura de gclid); a lista exata de chamadas à API — no seu caso são só duas, conversionUploads:uploadClickConversions e uma query de metadata em googleAds:search para achar a ação de conversão; fluxo de dados passo a passo; tratamento de dados pessoais (SHA-256 em e-mail e telefone, retenção); e uma declaração de que não há operação de mutate de campanha.

Eu gero esse PDF para você — o conteúdo sai do próprio código do VT, que é onde está a verdade. Só preciso dos dados da seção 5.

9

Who will have access to the Google Ads API tool you are creating?

◉ Internal users — employees only (outsourcing, contractor included)

Marque essa, e só essa. “Both internal and external users” é um dos maiores gatilhos de rejeição — o Google lê como SaaS público em que terceiros usariam o seu token, que é precisamente o que rejeitou o outro caso.

Repare no parêntese da própria opção: outsourcing, contractor included. É o Google dizendo, no texto do formulário, que desenvolvimento contratado conta como interno. Isso resolve limpo o fato de o VT ter sido construído por você e não por um funcionário do Cartazista.

10

Do you plan to use your Google Ads API token with a tool developed by someone else?

○ No

Foi exatamente aqui que o outro pedido morreu. A política diz: “This token must belong to and be managed by the developer responsible for building and maintaining the codebase… You should not share your developer token with another entity whose codebase you don't manage.” O alvo dela é usar o token com um SaaS público de terceiros. Software feito sob encomenda, rodando na infraestrutura do próprio anunciante, não é isso — e No é a resposta correta e defensável.

Mas há uma condição estrutural que precisa estar certa. O modelo só se sustenta se cada cliente tiver o seu token, na sua conta, com o código rodando na sua Cloudflare. Se o mesmo developer token ou o mesmo projeto Cloud atender vários clientes seus, aí é você quem vira o terceiro — e é rejeição na certa. Vale conferir: o projeto verdadeiro-trackeamento (nº 902957080860) vai na pergunta 2 e o Google olha para ele. Se esse projeto for uma conta sua reutilizada entre clientes, crie um projeto Cloud novo, do Cartazista, antes de submeter.

11

Do you plan to use your token for App Conversion Tracking and Remarketing API?

○ No

Não há aplicativo no escopo. Marcar Yes abriria uma linha de exigências que não tem nada a ver com o seu caso.

Os dois checkboxes finais, e o que vem depois do Next.

☑ I acknowledge that all the information above is accurate. ☑ I accept the Terms and Conditions.

Nas telas seguintes vêm tipos de campanha e capabilities. Duas regras, tiradas de erro real: os tipos de campanha declarados têm que ser os mesmos que estão escritos no PDF — divergência aqui gerou um round extra de revisão no outro caso. E em capabilities, marque só o que o código faz. Para o Cartazista isso significa conversion tracking / reporting, e nada de Account Management ou Campaign Creation. O compliance é literal ao extremo: caixa marcada sem lastro no PDF vira e-mail de questionamento, e e-mail de questionamento vira semanas.

04

SaaS: separar assinatura nova de recorrência no Meta

Sua intuição estava certa e a resposta é a menos óbvia das duas: existe evento próprio para aquisição, mas não existe evento padrão para renovação. Pesquisei a doc e depois mandei um verificador tentar derrubar o resultado — bem feito, porque ele derrubou duas coisas que eu teria te passado erradas.

O que a documentação viva sustenta

Subscribe é definido literalmente como “When a person applies to a start a paid subscription for a product or service you offer.” É o início da assinatura paga — aquisição, não cobrança. Ele aceita value, currency e predicted_ltv, e vale tanto no Pixel quanto na CAPI. Entre os 17 eventos padrão não existe nenhum de renovação.

A peça que amarra tudo é o subscription_id: um campo de user_data na CAPI, que não é hasheado, e que a Meta descreve como o identificador da assinatura — estável entre a primeira cobrança e todas as renovações seguintes. É por ele que a plataforma liga a recorrência à aquisição original.

Duas correções que a verificação pegou

Não ancore o diferenciador em content_category. Esse campo saiu da tabela de parâmetros da CAPI — a página foi substituída e ele não consta mais. Ainda funciona na prática (o SDK oficial serializa), mas não tem respaldo documental hoje.

RecurringSubscriptionPayment e CancelSubscription existiram, e a página foi removida. A Meta documentou esses dois eventos até 2023; hoje a URL redireciona para o índice de guias e nenhum dos dez guias vivos trata de assinatura. Podem continuar funcionando — mas não construa produção em cima disso sem confirmar antes no Test Events do Gerenciador.

O desenho que eu recomendo

O diferenciador vai numa custom property arbitrária dentro de custom_data — chame de billing_type. Esse é o único caminho com prova documental viva: o próprio reference de conversão personalizada traz um exemplo oficial de regra filtrando um parâmetro inventado ({"and":[{"event":{"eq":"item-sold"}},{"color":{"i_contains":"black"}}]}). Se um parâmetro arbitrário chamado color é filtrável, billing_type também é.

Momentoevent_nameChavesevent_id
1ª cobrança aprovada
aquisição
Subscribesubscription_id em user_data · value, currency, predicted_ltv, order_id, billing_type:"new"sub_<fatura>
RenovaçãoSubscriptionRenewal (custom)mesmo subscription_id · value, currency, order_id da nova fatura, billing_type:"renewal"renew_<fatura>
CancelamentoCancelSubscription (testar)subscription_idcancel_<sub>_<ts>

A armadilha que quebraria o tracking em silêncio

A deduplicação da Meta é por event_id + event_name, numa janela de 48 horas. O erro clássico em SaaS é derivar o event_id do ID da assinatura — aí toda renovação carrega o mesmo id da aquisição. Derive sempre do ID da fatura. E note os papéis opostos: order_id é a fatura (único por cobrança), subscription_id é a assinatura (estável entre cobranças). Trocar os dois inverte exatamente o comportamento que você quer.

Com isso, você otimiza campanha por Subscribe — que fica limpo, contando só cliente novo — e a renovação vira receita visível sem inflar o evento de aquisição. Se preferir mandar tudo como Purchase, dá para criar uma conversão personalizada com a regra {"and":[{"event":{"eq":"Purchase"}},{"billing_type":{"eq":"new"}}]} e otimizar por ela; o custo é que o Purchase cru, usado por padrão em ROAS e relatórios, passa a somar as recorrências.

Isso não existe no VT hoje

O VT manda um Purchase por webhook de compra aprovada, sem noção de assinatura. Para entregar o desenho acima, o parser do gateway precisa distinguir primeira cobrança de renovação e expor subscription_id — e isso depende de qual gateway o Cartazista usa. É desenvolvimento novo, com escopo pequeno, mas real. Entra na frente 2.

05

O que eu preciso de você

06

Como me usar melhor nisso

Uma sessão por frente — você já intuiu isso e está certo. Contexto de migração de DNS não ajuda em nada a decidir evento de Meta, e sessão longa demais vira sessão que esquece o começo.

Deixe o VT conduzir o setup. A pasta tem um condutor próprio em .claude/workflow.md, com os steps 0 a 6, e mantém estado entre sessões num tracking_memory.md que ele mesmo escreve. Abra a sessão da frente 2 dentro de verdadeiro_trackeamento/ e peça o onboarding — ele carrega só os playbooks das plataformas que você confirmar, e retoma de onde parou se a sessão morrer. Também tem slash commands prontos: /audit-tracking, /add-platform, /new-gateway, /analistamais.

Crie um CLAUDE.md na raiz do cartazista, como existe no fênix. É o arquivo que eu leio sozinho ao abrir qualquer sessão nessa pasta: quem é o cliente, CNPJ, domínio, que é SaaS por assinatura, qual gateway, o que já foi feito e o que está pendente. Sem ele, todo começo de sessão gasta suas mensagens me recontando o básico. Eu escrevo esse arquivo quando você quiser.

Sobre segredo: as quatro credenciais do Google já estão em verdadeiro_trackeamento/.dev.vars, que o git ignora, e o .gitignore ganhou uma regra para client_secret*.json. Vale mover aquele JSON da raiz para dentro da pasta — hoje ele está solto num diretório sem git, o que protege por acidente, não por desenho.